diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0b0b1830..a2159a06 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(QT_MIN_VERSION "5.5.1")
@@ -53,34 +53,38 @@ set(PROJECT_SOURCES
src/gui/dialogues/exporttocsvdialog.h
src/gui/dialogues/exporttocsvdialog.cpp
src/gui/dialogues/exporttocsvdialog.ui
+ src/gui/dialogues/entryeditdialog.h
+ src/gui/dialogues/entryeditdialog.cpp
+
# Widgets
- src/gui/widgets/tailswidget.h
- src/gui/widgets/tailswidget.cpp
- src/gui/widgets/aircraftwidget.ui
- src/gui/widgets/airportwidget.h
- src/gui/widgets/airportwidget.cpp
- src/gui/widgets/airportwidget.ui
+ src/gui/widgets/homewidget.h
+ src/gui/widgets/homewidget.cpp
+ src/gui/widgets/homewidget.ui
+ src/gui/widgets/totalswidget.h
+ src/gui/widgets/totalswidget.cpp
+ src/gui/widgets/totalswidget.ui
src/gui/widgets/backupwidget.h
src/gui/widgets/backupwidget.cpp
src/gui/widgets/backupwidget.ui
src/gui/widgets/debugwidget.h
src/gui/widgets/debugwidget.cpp
src/gui/widgets/debugwidget.ui
- src/gui/widgets/homewidget.h
- src/gui/widgets/homewidget.cpp
- src/gui/widgets/homewidget.ui
- src/gui/widgets/logbookwidget.h
- src/gui/widgets/logbookwidget.cpp
- src/gui/widgets/logbookwidget.ui
- src/gui/widgets/pilotswidget.h
- src/gui/widgets/pilotswidget.cpp
- src/gui/widgets/pilotswidget.ui
+
src/gui/widgets/settingswidget.h
src/gui/widgets/settingswidget.cpp
src/gui/widgets/settingswidget.ui
- src/gui/widgets/totalswidget.h
- src/gui/widgets/totalswidget.cpp
- src/gui/widgets/totalswidget.ui
+
+ src/gui/widgets/tableeditwidget.h
+ src/gui/widgets/tableeditwidget.cpp
+ src/gui/widgets/pilottableeditwidget.h
+ src/gui/widgets/pilottableeditwidget.cpp
+ src/gui/widgets/tailtableeditwidget.h
+ src/gui/widgets/tailtableeditwidget.cpp
+ src/gui/widgets/airporttableeditwidget.h
+ src/gui/widgets/airporttableeditwidget.cpp
+ src/gui/widgets/logbooktableeditwidget.h
+ src/gui/widgets/logbooktableeditwidget.cpp
+
# Verification
src/gui/verification/validationstate.h
src/gui/verification/userinput.h
@@ -95,7 +99,8 @@ set(PROJECT_SOURCES
src/gui/verification/completerprovider.cpp
src/gui/verification/tailinput.h
src/gui/verification/tailinput.cpp
-
+ src/gui/widgets/currencywidget.h
+ src/gui/widgets/currencywidget.cpp
# Classes
src/classes/style.h
@@ -116,6 +121,20 @@ set(PROJECT_SOURCES
src/classes/md5sum.cpp
src/classes/time.h
src/classes/time.cpp
+ src/classes/easaftl.h
+ src/classes/easaftl.cpp
+ src/classes/date.h
+ src/classes/date.cpp
+ src/classes/styleddatedelegate.h
+ src/classes/styleddatedelegate.cpp
+ src/classes/styledtimedelegate.h
+ src/classes/styledtimedelegate.cpp
+ src/classes/styledpilotdelegate.h
+ src/classes/styledpilotdelegate.cpp
+ src/classes/styledregistrationdelegate.h
+ src/classes/styledregistrationdelegate.cpp
+ src/classes/styledtypedelegate.h
+ src/classes/styledtypedelegate.cpp
# Database Entries
src/database/flightentry.h
@@ -132,7 +151,6 @@ set(PROJECT_SOURCES
src/database/simulatorentry.cpp
src/database/currencyentry.h
src/database/currencyentry.cpp
-
src/database/previousexperienceentry.h
src/database/previousexperienceentry.cpp
@@ -158,6 +176,8 @@ set(PROJECT_SOURCES
src/database/databasecache.h
src/database/databasecache.cpp
+ src/database/views/logbookviewinfo.h
+
# Ressources
assets/icons.qrc
assets/database/templates.qrc
@@ -224,7 +244,7 @@ if(WIN32)
)
endif()
else()
- if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
+if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(openPilotLog
${PROJECT_SOURCES}
${QM_FILES}
diff --git a/assets/database/database_schema.sql b/assets/database/database_schema.sql
index 65901615..4c86bd7e 100644
--- a/assets/database/database_schema.sql
+++ b/assets/database/database_schema.sql
@@ -22,6 +22,7 @@ CREATE TABLE IF NOT EXISTS 'tails' (
'multiengine' INTEGER,
'engineType' INTEGER,
'weightClass' INTEGER,
+ 'typeString' TEXT,
PRIMARY KEY('tail_id' AUTOINCREMENT)
);
DROP TABLE IF EXISTS 'flights';
@@ -89,11 +90,11 @@ CREATE TABLE IF NOT EXISTS 'airports' (
PRIMARY KEY('airport_id' AUTOINCREMENT)
);
DROP TABLE IF EXISTS 'currencies';
-CREATE TABLE IF NOT EXISTS 'currencies' (
- 'currency_id' INTEGER NOT NULL,
- 'currencyName' TEXT,
- 'expiryDate' NUMERIC,
- PRIMARY KEY('currency_id' AUTOINCREMENT)
+CREATE TABLE IF NOT EXISTS "currencies" (
+ "currency_id" INTEGER NOT NULL,
+ "currencyName" TEXT,
+ "expiryDate" NUMERIC,
+ PRIMARY KEY('currency_id' AUTOINCREMENT)
);
DROP TABLE IF EXISTS 'changelog';
CREATE TABLE IF NOT EXISTS 'changelog' (
@@ -134,133 +135,139 @@ CREATE TABLE 'previousExperience' (
'autoland' INTEGER
);
DROP VIEW IF EXISTS 'viewDefault';
-CREATE VIEW viewDefault AS
+CREATE VIEW viewDefault AS
SELECT flight_id,
- doft as 'Date',
- dept AS 'Dept',
- printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time',
- dest AS 'Dest', printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time ',
- printf('%02d',(tblk/60))||':'||printf('%02d',(tblk%60)) AS 'Total',
- CASE WHEN pilot_id = 1 THEN alias ELSE lastname||', '||substr(firstname, 1, 1)||'.' END AS 'Name PIC',
- CASE WHEN variant IS NOT NULL THEN make||' '||model||'-'||variant ELSE make||' '||model END AS 'Type',
- registration AS 'Registration',
- FlightNumber AS 'Flight #',
- remarks AS 'Remarks'
-FROM flights
+ doft,
+ dept,
+ tofb,
+ dest,
+ tonb,
+ tblk,
+ pilots.pilot_id,
+ tails.tail_id,
+ tails.registration,
+ flightNumber,
+ remarks
+FROM flights
INNER JOIN pilots on flights.pic = pilots.pilot_id
INNER JOIN tails on flights.acft = tails.tail_id
-ORDER BY date DESC;
+ORDER BY doft DESC
DROP VIEW IF EXISTS 'viewDefaultSim';
-CREATE VIEW viewDefaultSim AS
-SELECT flight_id AS 'rowid',
- doft as 'Date',
- dept AS 'Dept',
- printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time',
- dest AS 'Dest', printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time ',
- printf('%02d',(tblk/60))||':'||printf('%02d',(tblk%60)) AS 'Total',
- CASE WHEN pilot_id = 1 THEN alias ELSE lastname||', '||substr(firstname, 1, 1)||'.' END AS 'Name PIC',
- CASE WHEN variant IS NOT NULL THEN make||' '||model||'-'||variant ELSE make||' '||model END AS 'Type',
- registration AS 'Registration',
- null AS 'Sim Type',
- null AS 'Time of Session',
- remarks AS 'Remarks'
-FROM flights
-INNER JOIN pilots on flights.pic = pilots.pilot_id
-INNER JOIN tails on flights.acft = tails.tail_id
-UNION
- SELECT (session_id * -1),
- date,
- null, null, null, null,
- 'SIM',
- null,
- aircraftType,
- registration,
- deviceType,
- printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)),
+CREATE VIEW viewDefaultSim AS
+SELECT flights.flight_id,
+ flights.doft,
+ flights.dept,
+ flights.tofb,
+ flights.dest,
+ flights.tonb,
+ flights.tblk,
+ pilots.pilot_id ,
+ tails.tail_id,
+ tails.registration,
+ null AS 'deviceType',
+ null AS 'SimTime',
+ flights.remarks
+FROM flights
+INNER JOIN pilots on flights.pic = pilots.pilot_id
+INNER JOIN tails on flights.acft = tails.tail_id
+UNION
+ SELECT (simulators.session_id * -1),
+ simulators.date,
+ null, null, null, null, null, null,
+ simulators.aircraftType,
+ simulators.registration,
+ simulators.deviceType,
+ simulators.totalTime,
remarks
-FROM simulators
-ORDER BY date DESC;
+FROM simulators
+ORDER BY date DESC
DROP VIEW IF EXISTS 'viewEasa';
-CREATE VIEW viewEasa AS SELECT flight_id,
- doft as 'Date',
- dept AS 'Dept',
- printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time',
- dest AS 'Dest',
- printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time ',
- CASE WHEN variant IS NOT NULL THEN make||' '||model||'-'||variant ELSE make||' '||model END AS 'Type',
- registration AS 'Registration',
- (SELECT printf('%02d',(tSPSE/60))||':'||printf('%02d',(tSPSE%60)) WHERE tSPSE IS NOT NULL) AS 'SP SE',
- (SELECT printf('%02d',(tSPME/60))||':'||printf('%02d',(tSPME%60)) WHERE tSPME IS NOT NULL) AS 'SP ME',
- (SELECT printf('%02d',(tMP/60))||':'||printf('%02d',(tMP%60)) WHERE tMP IS NOT NULL) AS 'MP',
- printf('%02d',(tblk/60))||':'||printf('%02d',(tblk%60)) AS 'Total',
- CASE WHEN pilot_id = 1 THEN alias ELSE lastname||', '||substr(firstname, 1, 1)||'.' END AS 'Name PIC',
- ldgDay AS 'L/D',
- ldgNight AS 'L/N',
- (SELECT printf('%02d',(tNight/60))||':'||printf('%02d',(tNight%60)) WHERE tNight IS NOT NULL) AS 'Night',
- (SELECT printf('%02d',(tIFR/60))||':'||printf('%02d',(tIFR%60)) WHERE tIFR IS NOT NULL) AS 'IFR',
- (SELECT printf('%02d',(tPIC/60))||':'||printf('%02d',(tPIC%60)) WHERE tPIC IS NOT NULL) AS 'PIC',
- (SELECT printf('%02d',(tSIC/60))||':'||printf('%02d',(tSIC%60)) WHERE tSIC IS NOT NULL) AS 'SIC',
- (SELECT printf('%02d',(tDual/60))||':'||printf('%02d',(tDual%60)) WHERE tDual IS NOT NULL) AS 'Dual',
- (SELECT printf('%02d',(tFI/60))||':'||printf('%02d',(tFI%60)) WHERE tFI IS NOT NULL) AS 'FI',
- remarks AS 'Remarks'
-FROM flights
-INNER JOIN pilots on flights.pic = pilots.pilot_id
-INNER JOIN tails on flights.acft = tails.tail_id ORDER BY date DESC;
+CREATE VIEW viewEasa AS
+SELECT
+ flight_id,
+ doft,
+ dept,
+ tofb,
+ dest,
+ tonb,
+ tail_id,
+ registration,
+ tSPSE,
+ tSPME,
+ tMP,
+ tblk,
+ pilot_id,
+ ldgDay,
+ ldgNight,
+ tNight,
+ tIFR,
+ tPIC,
+ tSIC,
+ tDUAL,
+ tFI,
+ remarks
+FROM flights
+INNER JOIN pilots on flights.pic = pilots.pilot_id
+INNER JOIN tails on flights.acft = tails.tail_id ORDER BY doft DESC
DROP VIEW IF EXISTS 'viewEasaSim';
-CREATE VIEW viewEasaSim AS SELECT flight_id,
- doft as 'Date',
- dept AS 'Dept',
- printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time',
- dest AS 'Dest',
- printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time ',
- CASE WHEN variant IS NOT NULL THEN make||' '||model||'-'||variant ELSE make||' '||model END AS 'Type',
- registration AS 'Registration',
- (SELECT printf('%02d',(tSPSE/60))||':'||printf('%02d',(tSPSE%60)) WHERE tSPSE IS NOT NULL) AS 'SP SE',
- (SELECT printf('%02d',(tSPME/60))||':'||printf('%02d',(tSPME%60)) WHERE tSPME IS NOT NULL) AS 'SP ME',
- (SELECT printf('%02d',(tMP/60))||':'||printf('%02d',(tMP%60)) WHERE tMP IS NOT NULL) AS 'MP',
- printf('%02d',(tblk/60))||':'||printf('%02d',(tblk%60)) AS 'Total',
- CASE WHEN pilot_id = 1 THEN alias ELSE lastname||', '||substr(firstname, 1, 1)||'.' END AS 'Name PIC',
- ldgDay AS 'L/D',
- ldgNight AS 'L/N',
- (SELECT printf('%02d',(tNight/60))||':'||printf('%02d',(tNight%60)) WHERE tNight IS NOT NULL) AS 'Night',
- (SELECT printf('%02d',(tIFR/60))||':'||printf('%02d',(tIFR%60)) WHERE tIFR IS NOT NULL) AS 'IFR',
- (SELECT printf('%02d',(tPIC/60))||':'||printf('%02d',(tPIC%60)) WHERE tPIC IS NOT NULL) AS 'PIC',
- (SELECT printf('%02d',(tSIC/60))||':'||printf('%02d',(tSIC%60)) WHERE tSIC IS NOT NULL) AS 'SIC',
- (SELECT printf('%02d',(tDual/60))||':'||printf('%02d',(tDual%60)) WHERE tDual IS NOT NULL) AS 'Dual',
- (SELECT printf('%02d',(tFI/60))||':'||printf('%02d',(tFI%60)) WHERE tFI IS NOT NULL) AS 'FI',
- null AS 'Sim Type',
- null AS 'Time of Session',
- remarks AS 'Remarks'
-FROM flights
-INNER JOIN pilots on flights.pic = pilots.pilot_id
-INNER JOIN tails on flights.acft = tails.tail_id
-UNION
-SELECT (session_id * -1),
+CREATE VIEW viewEasaSim AS
+SELECT flight_id,
+ flights.doft as 'Date',
+ flights.dept,
+ flights.tofb,
+ flights.dest,
+ flights.tonb,
+ tails.tail_id AS 'Type',
+ tails.registration AS 'Registration',
+ flights.tSPSE,
+ flights.tSPME,
+ flights.tMP,
+ flights.tblk,
+ pilots.pilot_id AS 'PIC',
+ flights.ldgDay,
+ flights.ldgNight,
+ flights.tNight,
+ flights.tIFR,
+ flights.tPIC,
+ flights.tSIC,
+ flights.tDual,
+ flights.tFI,
+ null AS 'deviceType',
+ null AS 'simTime',
+ flights.remarks
+FROM flights
+INNER JOIN pilots on flights.pic = pilots.pilot_id
+INNER JOIN tails on flights.acft = tails.tail_id
+UNION
+SELECT (session_id * -1),
+ simulators.date,
+ null, null, null, null,
+ simulators.aircraftType,
+ simulators.registration,
+ null, null, null, null,
+ null, null, null, null,
+ null, null, null, null,
+ null,
+ simulators.deviceType,
+ simulators.totalTime,
+ simulators.remarks
+FROM simulators
+ORDER BY date DESC
+
+DROP VIEW IF EXISTS 'viewSimulators';
+CREATE VIEW viewSimulators AS
+SELECT (session_id * -1),
date,
- null, null, null, null,
- aircraftType,
registration,
- null, null, null,
- 'SIM',
- null, null, null, null, null, null, null, null, null,
- deviceType, printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)),
+ aircraftType,
+ deviceType,
+ totalTime,
remarks
-FROM simulators
-ORDER BY date DESC;
-
-DROP VIEW IF EXISTS 'viewSimulators';
-CREATE VIEW viewSimulators AS SELECT (session_id * -1),
- date as 'Date',
- registration AS 'Registration',
- aircraftType AS 'Aircraft Type',
- deviceType 'Sim Type',
- printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)) AS 'Time of Session',
- remarks AS 'Remarks'
-FROM simulators
-ORDER BY date DESC;
+FROM simulators
+ORDER BY date DESC
DROP VIEW IF EXISTS 'viewTails';
CREATE VIEW viewTails AS
diff --git a/assets/database/templates.qrc b/assets/database/templates.qrc
index 4f23bc68..ebe4a76c 100644
--- a/assets/database/templates.qrc
+++ b/assets/database/templates.qrc
@@ -3,7 +3,6 @@
templates/aircraft.json
templates/airports.json
templates/changelog.json
- templates/currencies.json
database_schema.sql
diff --git a/assets/database/templates/currencies.json b/assets/database/templates/currencies.json
deleted file mode 100644
index 57f4fbf0..00000000
--- a/assets/database/templates/currencies.json
+++ /dev/null
@@ -1,32 +0,0 @@
-[
- {
- "currency_id": 1,
- "currencyName": "Licence",
- "expiryDate": null
- },
- {
- "currency_id": 2,
- "currencyName": "Type Rating",
- "expiryDate": null
- },
- {
- "currency_id": 3,
- "currencyName": "Line Check",
- "expiryDate": null
- },
- {
- "currency_id": 4,
- "currencyName": "Medical",
- "expiryDate": null
- },
- {
- "currency_id": 5,
- "currencyName": "Custom1",
- "expiryDate": null
- },
- {
- "currency_id": 6,
- "currencyName": "Custom2",
- "expiryDate": null
- }
-]
\ No newline at end of file
diff --git a/src/gui/widgets/aircraftwidget.ui b/deprecated/aircraftwidget.ui
similarity index 100%
rename from src/gui/widgets/aircraftwidget.ui
rename to deprecated/aircraftwidget.ui
diff --git a/src/gui/widgets/airportwidget.cpp b/deprecated/airportwidget.cpp
similarity index 100%
rename from src/gui/widgets/airportwidget.cpp
rename to deprecated/airportwidget.cpp
diff --git a/src/gui/widgets/airportwidget.h b/deprecated/airportwidget.h
similarity index 100%
rename from src/gui/widgets/airportwidget.h
rename to deprecated/airportwidget.h
diff --git a/src/gui/widgets/airportwidget.ui b/deprecated/airportwidget.ui
similarity index 100%
rename from src/gui/widgets/airportwidget.ui
rename to deprecated/airportwidget.ui
diff --git a/src/gui/widgets/pilotswidget.cpp b/deprecated/pilotswidget.cpp
similarity index 75%
rename from src/gui/widgets/pilotswidget.cpp
rename to deprecated/pilotswidget.cpp
index 06396549..bb129f3b 100644
--- a/src/gui/widgets/pilotswidget.cpp
+++ b/deprecated/pilotswidget.cpp
@@ -59,7 +59,7 @@ void PilotsWidget::setupModelAndView()
view->verticalHeader()->hide();
view->setAlternatingRowColors(true);
view->setSortingEnabled(true);
- sortColumn = Settings::read(Settings::UserData::PilotSortColumn).toInt();
+ sortColumn = Settings::getPilotSortColumn();
view->sortByColumn(sortColumn, Qt::AscendingOrder);
view->show();
@@ -70,10 +70,12 @@ void PilotsWidget::setupModelAndView()
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);
+ QObject::connect(ui->pilotSearchLineEdit, &QLineEdit::textChanged,
+ this, &PilotsWidget::filterLineEdit_textChanged);
+ QObject::connect(view->horizontalHeader(), &QHeaderView::sectionClicked,
+ this, &PilotsWidget::newSortColumnSelected);
+ QObject::connect(view, &QTableView::clicked,
+ this, &PilotsWidget::editRequested);
}
void PilotsWidget::setUiEnabled(bool enabled)
@@ -103,43 +105,28 @@ void PilotsWidget::onPilotsWidget_databaseUpdated()
refreshView();
}
-void PilotsWidget::on_pilotSearchLineEdit_textChanged(const QString &arg1)
+void PilotsWidget::filterLineEdit_textChanged(const QString &arg1)
{
model->setFilter(QLatin1Char('\"') + ui->pilotsSearchComboBox->currentText()
+ QLatin1String("\" LIKE '%") + arg1
+ QLatin1String("%' AND ID > 1"));
}
-void PilotsWidget::tableView_selectionChanged()
+void PilotsWidget::editRequested(const QModelIndex &index)
{
- 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 = NewPilotDialog(selectedPilots.first(), this);
- np.setWindowFlag(Qt::Widget);
- ui->stackedWidget->addWidget(&np);
- ui->stackedWidget->setCurrentWidget(&np);
+ int pilotID = model->index(index.row(), 0).data().toInt();
- setUiEnabled(false);
- np.exec();
- refreshView();
- setUiEnabled(true);
- }
+ NewPilotDialog np = NewPilotDialog(pilotID, this);
+ np.setWindowFlag(Qt::Widget);
+ ui->stackedWidget->addWidget(&np);
+ ui->stackedWidget->setCurrentWidget(&np);
+ np.exec();
+ refreshView();
}
-void PilotsWidget::tableView_headerClicked(int column)
+void PilotsWidget::newSortColumnSelected(int newSortColumn)
{
- sortColumn = column;
- Settings::write(Settings::UserData::PilotSortColumn, column);
+ Settings::setPilotSortColumn(newSortColumn);
}
void PilotsWidget::on_newPilotButton_clicked()
@@ -209,7 +196,7 @@ void PilotsWidget::onDeleteUnsuccessful()
} else {
QString constrained_flights_string;
for (int i=0; i"));
+ constrained_flights_string.append(OPL::FlightEntry(constrained_flights[i]).getFlightSummary() + QStringLiteral("
"));
if (i>10) {
constrained_flights_string.append("
[...]
");
break;
@@ -245,24 +232,3 @@ const QString PilotsWidget::getPilotName(const OPL::PilotEntry &pilot) const
return pilot.getLastName() + QLatin1String(", ") + pilot.getFirstName();
}
-
-const QString PilotsWidget::getFlightSummary(const OPL::FlightEntry &flight) const
-{
-
- if(!flight.isValid())
- return QString();
-
- auto tableData = flight.getData();
- QString flight_summary;
- auto space = QLatin1Char(' ');
- flight_summary.append(tableData.value(OPL::FlightEntry::DOFT).toString() + space);
- flight_summary.append(tableData.value(OPL::FlightEntry::DEPT).toString() + space);
- flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TOFB).toInt()).toString()
- + space);
- flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TONB).toInt()).toString()
- + space);
- flight_summary.append(tableData.value(OPL::FlightEntry::DEST).toString());
-
- return flight_summary;
-
-}
diff --git a/src/gui/widgets/pilotswidget.h b/deprecated/pilotswidget.h
similarity index 85%
rename from src/gui/widgets/pilotswidget.h
rename to deprecated/pilotswidget.h
index 77b8c10c..07945cf1 100644
--- a/src/gui/widgets/pilotswidget.h
+++ b/deprecated/pilotswidget.h
@@ -59,12 +59,34 @@ class PilotsWidget : public QWidget
~PilotsWidget();
private slots:
- void tableView_selectionChanged();
- void tableView_headerClicked(int);
+ /*!
+ * \brief Creates a dialog to add a new Pilot to the database
+ */
void on_newPilotButton_clicked();
+
+ /*!
+ * \brief Deletes the selected pilot from the database if the selection is valid.
+ */
void on_deletePilotButton_clicked();
+
+ /*!
+ * \brief Informs the user about a error that ocurred when trying to delete an entry.
+ */
void onDeleteUnsuccessful();
- void on_pilotSearchLineEdit_textChanged(const QString &arg1);
+
+ /*!
+ * \brief Sets a filter on the model
+ */
+ void filterLineEdit_textChanged(const QString &arg1);
+
+ /*!
+ * \brief Creates a new PilotWidget to allow editing of the selected item
+ */
+ void editRequested(const QModelIndex &index);
+ /*!
+ * \brief Sorts the table on the selected column
+ */
+ void newSortColumnSelected(int newSortColumn);
public slots:
/*!
@@ -96,8 +118,6 @@ public slots:
const QString getPilotName(const OPL::PilotEntry &pilot) const;
- const QString getFlightSummary(const OPL::FlightEntry &flight) const;
-
void setupModelAndView();
void connectSignalsAndSlots();
diff --git a/src/gui/widgets/pilotswidget.ui b/deprecated/pilotswidget.ui
similarity index 100%
rename from src/gui/widgets/pilotswidget.ui
rename to deprecated/pilotswidget.ui
diff --git a/src/gui/widgets/tailswidget.cpp b/deprecated/tailswidget.cpp
similarity index 98%
rename from src/gui/widgets/tailswidget.cpp
rename to deprecated/tailswidget.cpp
index dc5591e3..9d6f739d 100644
--- a/src/gui/widgets/tailswidget.cpp
+++ b/deprecated/tailswidget.cpp
@@ -59,7 +59,7 @@ void TailsWidget::setupModelAndView()
view->verticalHeader()->hide();
view->setAlternatingRowColors(true);
- sortColumn = Settings::read(Settings::UserData::TailSortColumn).toInt();
+ sortColumn = Settings::getTailSortColumn();
view->setSortingEnabled(true);
view->sortByColumn(sortColumn, Qt::DescendingOrder);
@@ -153,8 +153,7 @@ void TailsWidget::on_aircraftSearchLineEdit_textChanged(const QString &arg1)
void TailsWidget::tableView_headerClicked(int column)
{
- sortColumn = column;
- Settings::write(Settings::UserData::TailSortColumn, column);
+ Settings::setTailSortColumn(column);
}
void TailsWidget::on_deleteAircraftButton_clicked()
diff --git a/src/gui/widgets/tailswidget.h b/deprecated/tailswidget.h
similarity index 100%
rename from src/gui/widgets/tailswidget.h
rename to deprecated/tailswidget.h
diff --git a/main.cpp b/main.cpp
index ad54dfd6..fec9e912 100644
--- a/main.cpp
+++ b/main.cpp
@@ -33,50 +33,70 @@
#include
#include
+
+
+/*!
+ * \brief firstRun - is run if the application is run for the first time and launches
+ * the FirstRunDialog which guides the user through the initial set-up process.
+ */
+bool firstRun()
+{
+ if(FirstRunDialog().exec() == QDialog::Rejected){
+ LOG << "Initial setup incomplete or unsuccessfull.";
+ return false;
+ }
+
+ Settings::setSetupCompleted(true);
+ LOG << "Initial Setup Completed successfully";
+ QMessageBox mb;
+ mb.setText("Initial set-up has been completed successfully.
Please re-start the application.");
+ mb.exec();
+ return true;
+}
+
+
/*!
* \brief init - Sets up the logging facilities, loads the user settings and sets
* up the application style before the MainWindow is instantiated
*/
-void init()
+bool init()
{
+ // Check if another instance of the application is already running, we don't want
+ // different processes writing to the same database
+ RunGuard guard(QStringLiteral("opl_single_key"));
+ if ( !guard.tryToRun() ){
+ LOG << "Another Instance of openPilotLog is already running. Exiting.";
+ return false;
+ }
+
LOG << "Setting up / verifying Application Directories...";
if(OPL::Paths::setup()) {
LOG << "Application Directories... verified";
} else {
+ return false;
LOG << "Unable to create directories.";
}
+
LOG << "Setting up logging facilities...";
if(OPL::Log::init(true)) {
LOG << "Logging enabled.";
} else {
LOG << "Unable to initalise logging.";
}
+
LOG << "Reading Settings...";
- Settings::setup();
+ Settings::init();
LOG << "Setting up application style...";
OPL::Style::setup();
// Translations to be done at a later stage
//LOG << "Installing translator...";
//ATranslator::installTranslator(OPL::Translations::English);
-}
-/*!
- * \brief firstRun - is run if the application is run for the first time and launches
- * the FirstRunDialog which guides the user through the initial set-up process.
- */
-int firstRun()
-{
- if(FirstRunDialog().exec() == QDialog::Rejected){
- LOG << "Initial setup incomplete or unsuccessfull.";
- return 1;
- }
+ // Check for First Run and launch Setup Wizard
+ if(!Settings::getSetupCompleted())
+ return firstRun();
- Settings::write(Settings::Main::SetupComplete, true);
- LOG << "Initial Setup Completed successfully";
- QMessageBox mb;
- mb.setText("Initial set-up has been completed successfully.
Please re-start the application.");
- mb.exec();
- return 0;
+ return true;
}
int main(int argc, char *argv[])
@@ -86,20 +106,9 @@ int main(int argc, char *argv[])
QCoreApplication::setOrganizationDomain(ORGDOMAIN);
QCoreApplication::setApplicationName(APPNAME);
- // Check of another instance of the application is already running, we don't want
- // different processes writing to the same database
- RunGuard guard(QStringLiteral("opl_single_key"));
- if ( !guard.tryToRun() ){
- LOG << "Another Instance of openPilotLog is already running. Exiting.";
- return 0;
- }
-
// Set Up the Application
- init();
-
- // Check for First Run and launch Setup Wizard
- if (!Settings::read(Settings::Main::SetupComplete).toBool())
- return firstRun();
+ if(!init())
+ return 1;
// Create Main Window and set Window Icon acc. to Platform
MainWindow w;
diff --git a/mainwindow.cpp b/mainwindow.cpp
index b4004004..76893ff8 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -17,30 +17,23 @@
*/
#include
#include "mainwindow.h"
+#include "src/gui/widgets/airporttableeditwidget.h"
+#include "src/gui/widgets/logbooktableeditwidget.h"
+#include "src/gui/widgets/pilottableeditwidget.h"
+#include "src/gui/widgets/tailtableeditwidget.h"
#include "ui_mainwindow.h"
#include "src/database/database.h"
#include "src/classes/style.h"
#include "src/gui/dialogues/firstrundialog.h"
-#include "src/gui/dialogues/newflightdialog.h"
-#include "src/gui/dialogues/newsimdialog.h"
-#include "src/gui/dialogues/newflightdialog.h"
#include "src/database/databasecache.h"
#include "src/classes/settings.h"
// Quick and dirty Debug area
void MainWindow::doDebugStuff()
{
- OPL::RowData_T xp = DB->getTotals(false);
- LOG << "Totals without previous:";
- LOG << xp;
-
- xp = DB->getTotals(true);
- LOG << "Totals with previous:";
- LOG << xp;
-
- OPL::FlightEntry fe = OPL::FlightEntry();
- LOG << "FLIGHT table: " << fe.getTableName();
- OPL::Row row = OPL::Row();
- LOG << "ROW table: " << row.getTableName();
+// LogbookTableEditWidget *widget = new LogbookTableEditWidget(this);
+// widget->init();
+// widget->setWindowFlags(Qt::Dialog);
+// widget->show();
}
MainWindow::MainWindow(QWidget *parent)
@@ -49,9 +42,6 @@ MainWindow::MainWindow(QWidget *parent)
{
ui->setupUi(this);
init();
-
- // set Startup Screen (Home Screen)
- ui->stackedWidget->setCurrentWidget(homeWidget);
}
MainWindow::~MainWindow()
@@ -66,6 +56,7 @@ void MainWindow::init()
setupToolbar();
connectWidgets();
setActionIcons(OPL::Style::getStyleType());
+ ui->stackedWidget->setCurrentWidget(homeWidget);
}
void MainWindow::setupToolbar()
@@ -93,16 +84,20 @@ void MainWindow::initialiseWidgets()
homeWidget = new HomeWidget(this);
ui->stackedWidget->addWidget(homeWidget);
- logbookWidget = new LogbookWidget(this);
+ logbookWidget = new LogbookTableEditWidget(this);
+ logbookWidget->init();
ui->stackedWidget->addWidget(logbookWidget);
- aircraftWidget = new TailsWidget(this);
- ui->stackedWidget->addWidget(aircraftWidget);
+ tailsWidget = new TailTableEditWidget(this);
+ tailsWidget->init();
+ ui->stackedWidget->addWidget(tailsWidget);
- pilotsWidget = new PilotsWidget(this);
+ pilotsWidget = new PilotTableEditWidget(this);
+ pilotsWidget->init();
ui->stackedWidget->addWidget(pilotsWidget);
- airportWidget = new AirportWidget(this);
+ airportWidget = new AirportTableEditWidget(this);
+ airportWidget->init();
ui->stackedWidget->addWidget(airportWidget);
settingsWidget = new SettingsWidget(this);
@@ -122,8 +117,9 @@ void MainWindow::connectDatabase()
WARN(tr("Error establishing database connection. The following error has ocurred:
%1")
.arg(DB->lastError.text()));
}
- DBCache->init();
+
// Load Cache
+ DBCache->init();
}
void MainWindow::setActionIcons(OPL::Style::StyleType style)
@@ -131,27 +127,27 @@ void MainWindow::setActionIcons(OPL::Style::StyleType style)
switch (style){
case OPL::Style::StyleType::Light:
LOG << "Setting Light Icon theme";
- ui->actionHome->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_HOME));
- ui->actionNewFlight->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT));
- ui->actionNewSim->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT)); // pending seperate icon
- ui->actionLogbook->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_LOGBOOK));
- ui->actionAircraft->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_AIRCRAFT));
- ui->actionPilots->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_PILOT));
- ui->actionAirports->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_BACKUP));
- ui->actionSettings->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_SETTINGS));
- ui->actionQuit->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_QUIT));
+ ui->actionHome->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_HOME));
+ ui->actionNewFlight->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT));
+ ui->actionNewSim->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT)); // TODO seperate icon
+ ui->actionLogbook->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_LOGBOOK));
+ ui->actionAircraft->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_AIRCRAFT));
+ ui->actionPilots->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_PILOT));
+ ui->actionAirports->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_BACKUP));
+ ui->actionSettings->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_SETTINGS));
+ ui->actionQuit->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_QUIT));
break;
case OPL::Style::StyleType::Dark:
LOG << "Setting Dark Icon theme";
- ui->actionHome->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_HOME_DARK));
- ui->actionNewFlight->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT_DARK));
- ui->actionNewSim->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT_DARK)); // pending separate icon
- ui->actionLogbook->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_LOGBOOK_DARK));
- ui->actionAircraft->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_AIRCRAFT_DARK));
- ui->actionPilots->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_PILOT_DARK));
- ui->actionAirports->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_BACKUP_DARK));
- ui->actionSettings->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_SETTINGS_DARK));
- ui->actionQuit->setIcon(QIcon(OPL::Assets::ICON_TOOLBAR_QUIT_DARK));
+ ui->actionHome->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_HOME_DARK));
+ ui->actionNewFlight->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT_DARK));
+ ui->actionNewSim->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_NEW_FLIGHT_DARK)); // pending separate icon
+ ui->actionLogbook->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_LOGBOOK_DARK));
+ ui->actionAircraft->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_AIRCRAFT_DARK));
+ ui->actionPilots->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_PILOT_DARK));
+ ui->actionAirports->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_BACKUP_DARK));
+ ui->actionSettings->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_SETTINGS_DARK));
+ ui->actionQuit->setIcon( QIcon(OPL::Assets::ICON_TOOLBAR_QUIT_DARK));
break;
}
}
@@ -170,40 +166,19 @@ void MainWindow::nope()
*/
void MainWindow::connectWidgets()
{
- QObject::connect(DB, &OPL::Database::dataBaseUpdated,
- homeWidget, &HomeWidget::refresh);
- QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
- homeWidget, &HomeWidget::refresh);
-
- QObject::connect(DB, &OPL::Database::dataBaseUpdated,
- logbookWidget, &LogbookWidget::refresh);
- QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
- logbookWidget, &LogbookWidget::onLogbookWidget_viewSelectionChanged);
-
- QObject::connect(DB, &OPL::Database::dataBaseUpdated,
- aircraftWidget, &TailsWidget::onAircraftWidget_dataBaseUpdated);
- QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
- aircraftWidget, &TailsWidget::onAircraftWidget_settingChanged);
-
- QObject::connect(DB, &OPL::Database::dataBaseUpdated,
- pilotsWidget, &PilotsWidget::onPilotsWidget_databaseUpdated);
QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
- pilotsWidget, &PilotsWidget::onPilotsWidget_settingChanged);
+ logbookWidget, &LogbookTableEditWidget::viewSelectionChanged);
+ QObject::connect(this, &MainWindow::addFlightEntryRequested,
+ logbookWidget, &LogbookTableEditWidget::addEntryRequested);
+ QObject::connect(this, &MainWindow::addSimulatorEntryRequested,
+ logbookWidget, &LogbookTableEditWidget::addSimulatorEntryRequested);
QObject::connect(settingsWidget, &SettingsWidget::settingChanged,
this, &MainWindow::onStyleChanged);
-
- QObject::connect(DB, &OPL::Database::connectionReset,
- logbookWidget, &LogbookWidget::repopulateModel);
- QObject::connect(DB, &OPL::Database::connectionReset,
- pilotsWidget, &PilotsWidget::repopulateModel);
- QObject::connect(DB, &OPL::Database::connectionReset,
- aircraftWidget, &TailsWidget::repopulateModel);
}
void MainWindow::onDatabaseInvalid()
{
QMessageBox db_error(this);
- //db_error.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
db_error.addButton(tr("Restore Backup"), QMessageBox::ButtonRole::AcceptRole);
db_error.addButton(tr("Create New Database"), QMessageBox::ButtonRole::RejectRole);
db_error.addButton(tr("Abort"), QMessageBox::ButtonRole::DestructiveRole);
@@ -235,7 +210,7 @@ void MainWindow::onDatabaseInvalid()
LOG << "Initial setup incomplete or unsuccessfull.";
on_actionQuit_triggered();
}
- Settings::write(Settings::Main::SetupComplete, true);
+ Settings::setSetupCompleted(true);
LOG << "Initial Setup Completed successfully";
}
}
@@ -251,8 +226,16 @@ void MainWindow::on_actionHome_triggered()
void MainWindow::on_actionNewFlight_triggered()
{
- auto* nf = new NewFlightDialog(this);
- nf->exec();
+ ui->stackedWidget->setCurrentWidget(logbookWidget);
+ emit addFlightEntryRequested();
+}
+
+void MainWindow::on_actionNewSim_triggered()
+{
+ // auto nsd = NewSimDialog(this);
+ // nsd.exec();
+ ui->stackedWidget->setCurrentWidget(logbookWidget);
+ emit addSimulatorEntryRequested();
}
void MainWindow::on_actionLogbook_triggered()
@@ -262,7 +245,7 @@ void MainWindow::on_actionLogbook_triggered()
void MainWindow::on_actionAircraft_triggered()
{
- ui->stackedWidget->setCurrentWidget(aircraftWidget);
+ ui->stackedWidget->setCurrentWidget(tailsWidget);
}
void MainWindow::on_actionPilots_triggered()
@@ -291,8 +274,4 @@ void MainWindow::on_actionDebug_triggered()
ui->stackedWidget->setCurrentWidget(debugWidget);
}
-void MainWindow::on_actionNewSim_triggered()
-{
- auto nsd = NewSimDialog(this);
- nsd.exec();
-}
+
diff --git a/mainwindow.h b/mainwindow.h
index 4dd0f34b..be252e46 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -29,17 +29,14 @@
#include
#include
+#include
+
#include "src/gui/widgets/homewidget.h"
#include "src/gui/widgets/settingswidget.h"
-#include "src/gui/widgets/logbookwidget.h"
-#include "src/gui/widgets/tailswidget.h"
-#include "src/gui/widgets/airportwidget.h"
-#include "src/gui/widgets/airportwidget.h"
-#include "src/gui/widgets/pilotswidget.h"
+#include "src/gui/widgets/tableeditwidget.h"
#include "src/gui/widgets/debugwidget.h"
#include "src/classes/style.h"
-enum Style {Light, Dark};
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
@@ -121,13 +118,13 @@ private slots:
HomeWidget* homeWidget;
- LogbookWidget* logbookWidget;
-
- TailsWidget* aircraftWidget;
+ LogbookTableEditWidget* logbookWidget; // This widget has a slot not present in TableEditWidget
+
+ TableEditWidget* tailsWidget;
- PilotsWidget* pilotsWidget;
+ TableEditWidget* pilotsWidget;
- AirportWidget* airportWidget;
+ TableEditWidget* airportWidget;
SettingsWidget* settingsWidget;
@@ -172,18 +169,15 @@ private slots:
*/
void resizeEvent(QResizeEvent *event) override
{
- //DEB << "SIZE:" << this->size();
- int icon_size;
- if (this->height() < 760)
- icon_size = (this->height() / 16);
- else
- icon_size = (this->height() / 14);
-
- auto tool_bar = this->findChild();
- tool_bar->setIconSize(QSize(icon_size, icon_size));
+ const auto icon_size = this->height() / 14;
+ const auto toolBar = this->findChild();
+ toolBar->setIconSize(QSize(icon_size, icon_size));
event->accept();
}
+signals:
+ void addFlightEntryRequested();
+ void addSimulatorEntryRequested();
//void closeEvent(QCloseEvent *event) override; //TODO check and prompt for creation of backup?
};
#endif // MAINWINDOW_H
diff --git a/src/classes/date.cpp b/src/classes/date.cpp
new file mode 100644
index 00000000..2b47bedb
--- /dev/null
+++ b/src/classes/date.cpp
@@ -0,0 +1,49 @@
+#include "date.h"
+#include
+
+namespace OPL {
+
+Date::Date(int julianDay, const DateTimeFormat &format)
+ : m_format(format)
+{
+ m_date = QDate::fromJulianDay(julianDay);
+}
+
+Date::Date(const QString &textDate, const DateTimeFormat &format)
+ : m_format(format)
+{
+ switch(format.dateFormat()) {
+ case DateTimeFormat::DateFormat::Default:
+ m_date = QDate::fromString(textDate, Qt::ISODate);
+ break;
+ case DateTimeFormat::DateFormat::Custom:
+ m_date = QDate::fromString(textDate, format.dateFormatString());
+ break;
+ case DateTimeFormat::DateFormat::SystemLocale:
+ m_date = QDate::fromString(QLocale::system().dateFormat(QLocale::ShortFormat));
+ break;
+ default:
+ break;
+ }
+}
+
+Date::Date(const QDate &date, const DateTimeFormat &format)
+ : m_format(format), m_date(date)
+{}
+
+const QString Date::toString() const
+{
+ switch (m_format.dateFormat()) {
+ case DateTimeFormat::DateFormat::Default:
+ return m_date.toString(Qt::ISODate);
+ case DateTimeFormat::DateFormat::SystemLocale:
+ return m_date.toString(QLocale::system().dateFormat(QLocale::ShortFormat));
+ case DateTimeFormat::DateFormat::Custom:
+ return m_date.toString(m_format.dateFormatString());
+ default:
+ return QString();
+ }
+}
+
+
+} // namespace OPL
diff --git a/src/classes/date.h b/src/classes/date.h
new file mode 100644
index 00000000..414ed98a
--- /dev/null
+++ b/src/classes/date.h
@@ -0,0 +1,45 @@
+#ifndef DATE_H
+#define DATE_H
+#include
+#include "src/opl.h"
+namespace OPL {
+
+/*!
+ * \brief The Date class wraps the QDate class.
+ * \details The QDate class stores dates internally as a Julian Day number,
+ * an integer count of every day in a contiguous range, with 24 November 4714 BCE
+ * in the Gregorian calendar being Julian Day 0 (1 January 4713 BCE in the Julian calendar).
+ *
+ * Storing a given date as an integer value allows for easy conversion to localised strings
+ * as well as calculations like date ranges.
+ *
+ * Julian day is also used to store a date in the database.
+ */
+class Date
+{
+public:
+
+ Date() = delete;
+ Date(int julianDay, const DateTimeFormat &format);
+ Date(const QString &textDate, const DateTimeFormat &format);
+ Date(const QDate &date, const DateTimeFormat &format);
+
+ const QString toString() const;
+ const bool isValid() const { return m_date.isValid(); }
+
+ const inline int toJulianDay() const { return m_date.toJulianDay(); }
+ const static inline Date today(const DateTimeFormat &format) { return Date(QDate::currentDate().toJulianDay(), format); }
+
+// void setDateFormat(const DateFormat_ &format) {m_format = format}
+ // todo copy constructor
+
+private:
+ QDate m_date;
+ DateTimeFormat m_format;
+};
+
+
+
+} // namespace OPL
+
+#endif // DATE_H
diff --git a/src/classes/easaftl.cpp b/src/classes/easaftl.cpp
new file mode 100644
index 00000000..e2cae210
--- /dev/null
+++ b/src/classes/easaftl.cpp
@@ -0,0 +1,16 @@
+#include "easaftl.h"
+
+int EasaFTL::getLimit(OPL::Statistics::TimeFrame timeFrame)
+{
+ switch (timeFrame) {
+ case OPL::Statistics::TimeFrame::Rolling28Days:
+ return 100*60; // 100h
+ case OPL::Statistics::TimeFrame::Rolling12Months:
+ return 1000 * 60; // 1000h
+ case OPL::Statistics::TimeFrame::CalendarYear:
+ return 900 * 60; // 900h
+ default:
+ return 0;
+ break;
+ }
+}
diff --git a/src/classes/easaftl.h b/src/classes/easaftl.h
new file mode 100644
index 00000000..d147f0c4
--- /dev/null
+++ b/src/classes/easaftl.h
@@ -0,0 +1,14 @@
+#ifndef EASAFTL_H
+#define EASAFTL_H
+#include "src/functions/statistics.h"
+
+
+class EasaFTL
+{
+public:
+ EasaFTL() = delete;
+
+ static int getLimit(OPL::Statistics::TimeFrame timeFrame);
+};
+
+#endif // EASAFTL_H
diff --git a/src/classes/settings.cpp b/src/classes/settings.cpp
index a37f5cd3..0b2f1f11 100644
--- a/src/classes/settings.cpp
+++ b/src/classes/settings.cpp
@@ -19,50 +19,12 @@
#include
#include "src/classes/paths.h"
-
-QMap Settings::mainMap = {
- {Main::SetupComplete, QStringLiteral("setupComplete")},
- {Main::Style, QStringLiteral("style")},
- {Main::Font, QStringLiteral("font")},
- {Main::FontSize, QStringLiteral("fontSize")},
- {Main::UseSystemFont, QStringLiteral("useSystemFont")},
- {Main::LogbookView, QStringLiteral("logbookView")},
- {Main::DateFormat, QStringLiteral("dateFormat")},
-};
-
-QMap Settings::userDataMap = {
- {UserData::DisplaySelfAs, QStringLiteral("displayselfas")},
- {UserData::TailSortColumn, QStringLiteral("tailSortColumn")},
- {UserData::PilotSortColumn, QStringLiteral("pilotSortColumn")},
- {UserData::FtlWarningThreshold, QStringLiteral("ftlWarningThreshold")},
- {UserData::CurrWarningThreshold, QStringLiteral("currWarningThreshold")},
- {UserData::ShowToLgdCurrency, QStringLiteral("showToLdgCurrency")},
- {UserData::ShowLicCurrency, QStringLiteral("showLicCurrency")},
- {UserData::ShowTrCurrency, QStringLiteral("showTrCurrency")},
- {UserData::ShowLckCurrency, QStringLiteral("showLckCurrency")},
- {UserData::ShowMedCurrency, QStringLiteral("showMedCurrency")},
- {UserData::ShowCustom1Currency, QStringLiteral("showCustom1Currency")},
- {UserData::ShowCustom2Currency, QStringLiteral("showCustom2Currency")},
- {UserData::Custom1CurrencyName, QStringLiteral("custom1CurrencyName")},
- {UserData::Custom2CurrencyName, QStringLiteral("custom2CurrencyName")},
-};
-
-QMap Settings::flightLoggingMap = {
- {FlightLogging::Function, QStringLiteral("function")},
- {FlightLogging::Approach, QStringLiteral("approach")},
- {FlightLogging::NightLoggingEnabled,QStringLiteral("nightLoggingEnabled")},
- {FlightLogging::LogIFR, QStringLiteral("logIfr")},
- {FlightLogging::FlightNumberPrefix, QStringLiteral("flightnumberPrefix")},
- {FlightLogging::PilotFlying, QStringLiteral("pilotFlying")},
- {FlightLogging::NightAngle, QStringLiteral("nightangle")},
- //{FlightLogging::FlightTimeFormat, QStringLiteral("flightTimeFormat")},
-};
-
-void Settings::setup()
+void Settings::init()
{
+ LOG << "Initialising application settings...";
QSettings::setDefaultFormat(QSettings::IniFormat);
QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, OPL::Paths::path(OPL::Paths::Settings));
- QSettings();
+ Settings::settingsInstance = new QSettings();
}
/*!
@@ -70,70 +32,43 @@ void Settings::setup()
*/
void Settings::resetToDefaults()
{
- write(Main::Style, QStringLiteral("Fusion"));
- write(Main::UseSystemFont, true);
- write(Main::LogbookView, 0);
- write(Main::DateFormat, 0);
-
- write(UserData::DisplaySelfAs, 0);
- write(UserData::FtlWarningThreshold, 0.8); // To Do: UI Option
- write(UserData::CurrWarningThreshold, 30);
- write(UserData::ShowToLgdCurrency, true);
- write(UserData::ShowLicCurrency, false);
- write(UserData::ShowTrCurrency, false);
- write(UserData::ShowLckCurrency, false);
- write(UserData::ShowMedCurrency, false);
- write(UserData::ShowCustom1Currency, false);
- write(UserData::ShowCustom2Currency, false);
- write(UserData::PilotSortColumn, 0);
- write(UserData::TailSortColumn, 0);
-
- write(FlightLogging::PilotFlying, true);
- write(FlightLogging::NightAngle, -6);
+ setApplicationStyle(QStringLiteral("Fusion"));
+ setUseSystemFont(true);
+ setLogbookView(OPL::LogbookView::Default);
+ setLogAsPilotFlying(true);
+ setNightAngle(-6);
+ setShowSelfAs(0);
+ setFtlWarningThreshold(0.8);
+ setCurrencyWarningThreshold(90);
+ setPilotSortColumn(0);
+ setTailSortColumn(0);
+ setDisplayFormat(OPL::DateTimeFormat());
+
+ sync();
}
-//
-// Read/Write
-//
-
-QVariant Settings::read(const FlightLogging key)
-{ return QSettings().value(groupOfKey(key)); }
-
-void Settings::write(const FlightLogging key, const QVariant &val)
-{ QSettings().setValue(groupOfKey(key), val); }
-
-QVariant Settings::read(const Main key)
-{ return QSettings().value(groupOfKey(key)); }
-
-void Settings::write(const Main key, const QVariant &val)
-{ QSettings().setValue(groupOfKey(key), val); }
-
-QVariant Settings::read(const UserData key)
-{ return QSettings().value(groupOfKey(key)); }
-
-void Settings::write(const UserData key, const QVariant &val)
-{ QSettings().setValue(groupOfKey(key), val); }
-
-//
-// QString conversion PATH
-//
-QString Settings::groupOfKey (const Settings::FlightLogging key)
-{ return QStringLiteral("flightlogging/") + flightLoggingMap[key]; }
+OPL::DateTimeFormat Settings::getDisplayFormat()
+{
+ using namespace OPL;
-QString Settings::groupOfKey (const Settings::Main key)
-{ return QStringLiteral("main/") + mainMap[key]; }
+ // date format
+ const DateTimeFormat::DateFormat dateFormat = static_cast(
+ settingsInstance->value(FORMAT_DATE_FORMAT, 0).toInt());
+ const QString dateFormatString = settingsInstance->value(FORMAT_DATE_STRING, QStringLiteral("yyyy-MM-dd")).toString();
+ // time format
+ const DateTimeFormat::TimeFormat timeFormat = static_cast(
+ settingsInstance->value(FORMAT_TIME_FORMAT, 0).toInt());
+ const QString timeFormatString = settingsInstance->value(FORMAT_TIME_STRING, QStringLiteral("hh:mm")).toString();
-QString Settings::groupOfKey (const Settings::UserData key)
-{ return QStringLiteral("userdata/") + userDataMap[key]; }
+ return DateTimeFormat(dateFormat, dateFormatString, timeFormat, timeFormatString);
-//
-// QString conversion ONLY KEY
-//
-QString Settings::stringOfKey (const Settings::FlightLogging key)
-{ return flightLoggingMap[key]; }
+}
-QString Settings::stringOfKey (const Settings::Main key)
-{ return mainMap[key]; }
+void Settings::setDisplayFormat(const OPL::DateTimeFormat &format)
+{
+ settingsInstance->setValue(FORMAT_DATE_FORMAT, static_cast(format.dateFormat()));
+ settingsInstance->setValue(FORMAT_DATE_STRING, format.dateFormatString());
+ settingsInstance->setValue(FORMAT_TIME_FORMAT, static_cast(format.timeFormat()));
+ settingsInstance->setValue(FORMAT_TIME_STRING, format.timeFormatString());
+}
-QString Settings::stringOfKey (const Settings::UserData key)
-{ return userDataMap[key]; }
diff --git a/src/classes/settings.h b/src/classes/settings.h
index bce3fa8d..c8700bfe 100644
--- a/src/classes/settings.h
+++ b/src/classes/settings.h
@@ -17,89 +17,233 @@
*/
#ifndef SETTINGS_H
#define SETTINGS_H
+#include "src/opl.h"
#include
#include
/*!
- * \brief Thin wrapper for the QSettings class,
- * simplifying reading and writing of settings.
+ * \brief A wrapper for the QSettings class, simplifying reading and writing of settings.
*/
class Settings {
public:
- enum class Main {
- SetupComplete,
- Style,
- Font,
- FontSize,
- UseSystemFont,
- LogbookView,
- DateFormat,
- };
-
- enum class UserData {
- DisplaySelfAs,
- TailSortColumn,
- PilotSortColumn,
- FtlWarningThreshold,
- CurrWarningThreshold,
- ShowToLgdCurrency,
- ShowLicCurrency,
- ShowTrCurrency,
- ShowLckCurrency,
- ShowMedCurrency,
- ShowCustom1Currency,
- ShowCustom2Currency,
- Custom1CurrencyName,
- Custom2CurrencyName,
- };
-
- enum class FlightLogging {
- Function,
- Approach,
- NightLoggingEnabled,
- LogIFR,
- FlightNumberPrefix,
- PilotFlying,
- NightAngle,
- //FlightTimeFormat,
- };
-
- /*!
- * \brief Should be called after QCoreApplication::set...Name have been called.
- */
- static void setup();
+ /*!
+ * \brief Initialise the default setting object. Call after QCoreApplication has been set up in main
+ */
+ static void init();
+
+ /*!
+ * \brief Reset the application settings to its default values
+ */
static void resetToDefaults();
- static QVariant read(const Main key);
- static void write(const Main key, const QVariant &val);
+ /*!
+ * \brief Writes any unsaved changes to permanent storage
+ * \note This function is called automatically from QSettings's destructor and by the event loop at regular intervals,
+ * so you normally don't need to call it yourself.
+ */
+ static void sync() { settingsInstance->sync(); }
+
+ /*!
+ * \brief Initial set-up of the application and database has been completed
+ */
+ static bool getSetupCompleted() { return settingsInstance->value(MAIN_SETUP_COMPLETE, false).toBool(); }
+
+ /*!
+ * \brief Initial set-up of the application and database has been completed
+ */
+ static void setSetupCompleted(bool completed) { settingsInstance->setValue(MAIN_SETUP_COMPLETE, completed); }
+
+ /*!
+ * \brief returns the name of the preferred application style (default: fusion)
+ */
+ static const QString getApplicationStyle() { return settingsInstance->value(MAIN_STYLE, "Fusion").toString(); }
+
+ /*!
+ * \brief set the name of the preferred application style
+ */
+ static const void setApplicationStyle(const QString &style) { settingsInstance->setValue(MAIN_STYLE, style); }
+
+ /*!
+ * \brief returns the name of the preferred application font (default: system font)
+ * \return
+ */
+ static const QString getApplicationFontName() { return settingsInstance->value(MAIN_FONT_NAME, QString()).toString(); }
+
+ /*!
+ * \brief set the name of the preferred application font
+ * \return
+ */
+ static const void setApplicationFontName(const QString &fontName) { settingsInstance->setValue(MAIN_FONT_NAME, fontName); }
+
+ /*!
+ * \brief returns the preferred font size (default: 10)
+ * \return
+ */
+ static int getApplicationFontSize() { return settingsInstance->value(MAIN_FONT_SIZE, 10).toInt(); }
+
+ /*!
+ * \brief sets the preferred font size
+ */
+ static void setApplicationFontSize(int size) { settingsInstance->setValue(MAIN_FONT_SIZE, size); }
+
+ /*!
+ * \brief returns if the default system font should be used (default: true)
+ */
+ static bool getUseSystemFont() { return settingsInstance->value(MAIN_USE_SYSTEM_FONT, true).toBool(); }
+
+ /*!
+ * \brief sets if the default system font should be used
+ */
+ static void setUseSystemFont(bool value) { settingsInstance->setValue(MAIN_USE_SYSTEM_FONT, value); }
+
+ /*!
+ * \brief returns the view to be used in the logbook widget
+ */
+ static OPL::LogbookView getLogbookView() { return OPL::LogbookView(settingsInstance->value(MAIN_LOGBOOK_VIEW).toInt()); }
+
+ /*!
+ * \brief sets the view to be used in the logbook widget
+ */
+ static void setLogbookView(OPL::LogbookView view) { (settingsInstance->setValue(MAIN_LOGBOOK_VIEW, static_cast(view))); }
+
+ /*!
+ * \brief returns the Display Format used in the application
+ */
+ static OPL::DateTimeFormat getDisplayFormat();
+
+ /*!
+ * \brief sets the Display Format used in the application
+ */
+ static void setDisplayFormat(const OPL::DateTimeFormat &format);
+
+ /*!
+ * \brief returns the default pilot function for new flights
+ */
+ static OPL::PilotFunction getPilotFunction() { return OPL::PilotFunction(settingsInstance->value(LOG_FUNCTION).toInt()); }
- static QVariant read(const FlightLogging key);
- static void write(const UserData key, const QVariant &val);
+ /*!
+ * \brief sets the default pilot function for new flights
+ */
+ static void setPilotFunction(OPL::PilotFunction function) { settingsInstance->setValue(LOG_FUNCTION, static_cast(function)); }
- static QVariant read(const UserData key);
- static void write(const FlightLogging key, const QVariant &val);
+ /*!
+ * \brief returns the default approach type for new flights
+ */
+ static const QString getApproachType() { return settingsInstance->value(LOG_APPROACH).toString(); }
+ /*!
+ * \brief sets the default approach type for new flights
+ */
+ static void setApproachType(const QString &value) { settingsInstance->setValue(LOG_APPROACH, value); }
/*!
- * \brief Return string representation of group of key: "ini_header/key"
+ * \brief returns if automatic night time calculation is enabled for new flights
*/
- static QString groupOfKey(const Main key);
- static QString groupOfKey(const FlightLogging key);
- static QString groupOfKey(const UserData key);
+ static bool getNightLoggingEnabled() { return settingsInstance->value(LOG_NIGHT).toBool(); }
/*!
- * \brief Return string representation of key
+ * \brief sets if automatic night time calculation is enabled for new flights
*/
- static QString stringOfKey(const Main key);
- static QString stringOfKey(const FlightLogging key);
- static QString stringOfKey(const UserData key);
+ static void setNightLoggingEnabled(bool value) { settingsInstance->setValue(LOG_NIGHT, value); }
+
+ /*!
+ * \brief returns the angle of elevation for night time calculation (default: -6 degrees)
+ */
+ static int getNightAngle() { return settingsInstance->value(LOG_NIGHT_ANGLE, -6).toInt(); }
+
+ /*!
+ * \brief sets the angle of elevation for night time calculation
+ */
+ static void setNightAngle(int value) { settingsInstance->setValue(LOG_NIGHT_ANGLE, value); }
+
+ /*!
+ * \brief returns if flight time should be logged as IFR for new flights
+ */
+ static bool getLogIfr() { return settingsInstance->value(LOG_IFR).toBool(); }
+
+ /*!
+ * \brief sets if flight time should be logged as IFR for new flights
+ */
+ static void setLogIfr(bool value) { settingsInstance->setValue(LOG_IFR, value); }
+
+ /*!
+ * \brief returns if new flights should be logged as Pilot Flying
+ */
+ static bool getLogAsPilotFlying() { return settingsInstance->value(LOG_AS_PF).toBool(); }
+
+ /*!
+ * \brief sets if new flights should be logged as Pilot Flying
+ */
+ static void setLogAsPilotFlying(bool value) { settingsInstance->setValue(LOG_AS_PF, value); }
+
+ /*!
+ * \brief returns the default Flight Number Prefix for new flights
+ */
+ static const QString getFlightNumberPrefix() { return settingsInstance->value(LOG_PREFIX).toString(); }
+
+ /*!
+ * \brief sets the default Flight Number Prefix for new flights
+ */
+ static void setFlightNumberPrefix(const QString &value) { settingsInstance->setValue(LOG_PREFIX, value); }
+
+ /*!
+ * \brief sets how the logbook owner is shown in the view
+ * \details
+ *
+ * - 0 - self
+ *
+ */
+ static int getShowSelfAs() { return settingsInstance->value(SHOW_SELF_AS).toInt(); }
+
+ static void setShowSelfAs(int value) { settingsInstance->setValue(SHOW_SELF_AS, value); }
+
+ static int getTailSortColumn() { return settingsInstance->value(TAIL_SORT_COLUMN).toInt(); }
+ static void setTailSortColumn(int value) { settingsInstance->setValue(TAIL_SORT_COLUMN, value); }
+
+ static int getPilotSortColumn() { return settingsInstance->value(PILOT_SORT_COLUMN).toInt(); }
+ static void setPilotSortColumn(int value) { settingsInstance->setValue(PILOT_SORT_COLUMN, value); }
+
+ static double getFtlWarningThreshold() { return settingsInstance->value(FTL_WARNING_THR, 0.8).toDouble(); }
+ static void setFtlWarningThreshold(double value) { settingsInstance->setValue(FTL_WARNING_THR, value); }
+
+ static int getCurrencyWarningThreshold() { return settingsInstance->value(CURR_WARNING_THR, 90).toInt(); }
+ static void setCurrencyWarningThreshold(int days) { settingsInstance->setValue(CURR_WARNING_THR, days); }
+
- static QSettings settings();
- static void sync() { QSettings().sync(); }
private:
- static QMap mainMap;
- static QMap userDataMap;
- static QMap flightLoggingMap;
+
+ // keep an instance to avoid having to create a new QSettings object every time
+ static inline QSettings *settingsInstance;
+
+ // Setting keys
+ const static inline QString CURRENCY_STUB = QStringLiteral("userdata/%1Currency");
+ const static inline QString SHOW_SELF_AS = QStringLiteral("userdata/displaySelfAs");
+ const static inline QString TAIL_SORT_COLUMN = QStringLiteral("userdata/tailSortColumn");
+ const static inline QString PILOT_SORT_COLUMN = QStringLiteral("userdata/pilotSortColumn");
+ const static inline QString FTL_WARNING_THR = QStringLiteral("ftlWarningThreshold");
+ const static inline QString CURR_WARNING_THR = QStringLiteral("currWarningThreshold");
+
+ const static inline QString LOG_FUNCTION = QStringLiteral("flightlogging/function");
+ const static inline QString LOG_APPROACH = QStringLiteral("flightlogging/approach");
+ const static inline QString LOG_NIGHT = QStringLiteral("flightlogging/nightLoggingEnabled");
+ const static inline QString LOG_NIGHT_ANGLE = QStringLiteral("flightlogging/nightangle");
+ const static inline QString LOG_IFR = QStringLiteral("flightlogging/logIfr");
+ const static inline QString LOG_AS_PF = QStringLiteral("flightlogging/pilotFlying");
+ const static inline QString LOG_PREFIX = QStringLiteral("flightlogging/flightnumberPrefix");
+
+ const static inline QString MAIN_SETUP_COMPLETE = QStringLiteral("main/setupComplete");
+ const static inline QString MAIN_STYLE = QStringLiteral("main/style");
+ const static inline QString MAIN_FONT_NAME = QStringLiteral("main/font");
+ const static inline QString MAIN_FONT_SIZE = QStringLiteral("main/fontSize");
+ const static inline QString MAIN_USE_SYSTEM_FONT = QStringLiteral("main/useSystemFont");
+ const static inline QString MAIN_LOGBOOK_VIEW = QStringLiteral("main/logbookView");
+
+ const static inline QString FORMAT_DATE_FORMAT = QStringLiteral("format/dateFormat");
+ const static inline QString FORMAT_DATE_STRING = QStringLiteral("format/dateFormatString");
+ const static inline QString FORMAT_TIME_FORMAT = QStringLiteral("format/timeFormat");
+ const static inline QString FORMAT_TIME_STRING = QStringLiteral("format/timeFormatString");
+
+
};
#endif // SETTINGS_H
diff --git a/src/classes/style.cpp b/src/classes/style.cpp
index f9a48e54..f79e2994 100644
--- a/src/classes/style.cpp
+++ b/src/classes/style.cpp
@@ -50,21 +50,22 @@ QLatin1String Style::DARK_PALETTE = QLatin1String("Dark-Palette");
*/
void Style::setup()
{
- if (!Settings::read(Settings::Main::SetupComplete).toBool()) // Use system default for first run
+ if (!Settings::getSetupCompleted()) // Use system default for first run
return;
+// if (!Settings::read(Settings::Main::SetupComplete).toBool()) // Use system default for first run
+// return;
// Set Font
- if (!Settings::read(Settings::Main::UseSystemFont).toBool()) {
- QFont font(Settings::read(Settings::Main::Font).toString());
- font.setPointSize(Settings::read(Settings::Main::FontSize).toUInt());
+ if (!Settings::getUseSystemFont()) {
+ const QFont font(Settings::getApplicationFontName(), Settings::getApplicationFontSize());
qApp->setFont(font);
LOG << "Application Font set: " << font.toString().split(',').first();
}
// Set style, stylesheet or palette
- QString style_setting = Settings::read(Settings::Main::Style).toString();
+ const QString style_setting = Settings::getApplicationStyle();
if (style_setting == DARK_PALETTE) {
Style::setStyle(Style::darkPalette());
- Settings::write(Settings::Main::Style, style_setting);
+ Settings::setApplicationStyle(style_setting);
return;
}
for (const auto &style_name : styles) {
diff --git a/src/classes/styleddatedelegate.cpp b/src/classes/styleddatedelegate.cpp
new file mode 100644
index 00000000..296ef86b
--- /dev/null
+++ b/src/classes/styleddatedelegate.cpp
@@ -0,0 +1,13 @@
+#include "styleddatedelegate.h"
+#include "src/classes/date.h"
+
+StyledDateDelegate::StyledDateDelegate(const OPL::DateTimeFormat &dateFormat, QObject *parent)
+ :
+ QStyledItemDelegate(parent),
+ m_format(dateFormat)
+{}
+
+QString StyledDateDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ return OPL::Date(value.toInt(), m_format).toString();
+}
diff --git a/src/classes/styleddatedelegate.h b/src/classes/styleddatedelegate.h
new file mode 100644
index 00000000..34ba68ed
--- /dev/null
+++ b/src/classes/styleddatedelegate.h
@@ -0,0 +1,23 @@
+#ifndef STYLEDDATEDELEGATE_H
+#define STYLEDDATEDELEGATE_H
+
+#include
+#include "src/opl.h"
+
+/*!
+ * \brief The StyledDateDelegate class is used to display a database date value human-readable.
+ * \details The database stores dates as an integer representing the days elapsed since the
+ * beginning of the julian calendar. This integer has to be converted to a human-readable date
+ * according to the users selected date format.
+ */
+class StyledDateDelegate : public QStyledItemDelegate
+{
+public:
+ StyledDateDelegate(const OPL::DateTimeFormat &dateFormat, QObject * parent = nullptr);
+
+ QString displayText(const QVariant &value, const QLocale &locale) const override;
+private:
+ OPL::DateTimeFormat m_format;
+};
+
+#endif // STYLEDDATEDELEGATE_H
diff --git a/src/classes/styledpilotdelegate.cpp b/src/classes/styledpilotdelegate.cpp
new file mode 100644
index 00000000..c194b437
--- /dev/null
+++ b/src/classes/styledpilotdelegate.cpp
@@ -0,0 +1,13 @@
+#include "styledpilotdelegate.h"
+#include "src/database/databasecache.h"
+
+StyledPilotDelegate::StyledPilotDelegate(QObject *parent)
+ : QStyledItemDelegate{parent}
+{
+
+}
+
+QString StyledPilotDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ return DBCache->getPilotNamesMap().value(value.toInt());
+}
diff --git a/src/classes/styledpilotdelegate.h b/src/classes/styledpilotdelegate.h
new file mode 100644
index 00000000..37611d2d
--- /dev/null
+++ b/src/classes/styledpilotdelegate.h
@@ -0,0 +1,20 @@
+#ifndef STYLEDPILOTDELEGATE_H
+#define STYLEDPILOTDELEGATE_H
+
+#include
+
+/*!
+ * \brief The StyledPilotDelegate class is used to display a database date value human-readable.
+ * \details The database stores pilots as an integer representing a foreign key into a database
+ * of pilots. This delegate uses the Database cache to map this ID to a name and displays the name
+ * in the view.
+ */
+class StyledPilotDelegate : public QStyledItemDelegate
+{
+public:
+ explicit StyledPilotDelegate(QObject *parent = nullptr);
+
+ QString displayText(const QVariant &value, const QLocale &locale) const override;
+};
+
+#endif // STYLEDPILOTDELEGATE_H
diff --git a/src/classes/styledregistrationdelegate.cpp b/src/classes/styledregistrationdelegate.cpp
new file mode 100644
index 00000000..eae4278e
--- /dev/null
+++ b/src/classes/styledregistrationdelegate.cpp
@@ -0,0 +1,13 @@
+#include "styledregistrationdelegate.h"
+#include "src/database/databasecache.h"
+
+StyledRegistrationDelegate::StyledRegistrationDelegate(QObject *parent)
+ : QStyledItemDelegate{parent}
+{
+
+}
+
+QString StyledRegistrationDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ return DBCache->getTailsMap().value(value.toInt());
+}
diff --git a/src/classes/styledregistrationdelegate.h b/src/classes/styledregistrationdelegate.h
new file mode 100644
index 00000000..c93c3bcd
--- /dev/null
+++ b/src/classes/styledregistrationdelegate.h
@@ -0,0 +1,20 @@
+#ifndef STYLEDREGISTRATIONDELEGATE_H
+#define STYLEDREGISTRATIONDELEGATE_H
+
+#include
+
+/*!
+ * \brief The StyledRegistrationDelegate class is used to display a database date value human-readable.
+ * \details The database stores tails as an integer representing a foreign key into a database
+ * of tails. This delegate uses the Database cache to map this ID to a registration to display
+ * in the view.
+ */
+class StyledRegistrationDelegate : public QStyledItemDelegate
+{
+public:
+ explicit StyledRegistrationDelegate(QObject *parent = nullptr);
+
+ QString displayText(const QVariant &value, const QLocale &locale) const override;
+};
+
+#endif // STYLEDREGISTRATIONDELEGATE_H
diff --git a/src/classes/styledtimedelegate.cpp b/src/classes/styledtimedelegate.cpp
new file mode 100644
index 00000000..56b8df0b
--- /dev/null
+++ b/src/classes/styledtimedelegate.cpp
@@ -0,0 +1,12 @@
+#include "styledtimedelegate.h"
+#include "src/classes/time.h"
+
+StyledTimeDelegate::StyledTimeDelegate(const OPL::DateTimeFormat &format, QObject *parent)
+ : QStyledItemDelegate{parent}, m_format(format)
+{}
+
+QString StyledTimeDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ const OPL::Time time(value.toInt(), m_format);
+ return time.toString();
+}
diff --git a/src/classes/styledtimedelegate.h b/src/classes/styledtimedelegate.h
new file mode 100644
index 00000000..ee722178
--- /dev/null
+++ b/src/classes/styledtimedelegate.h
@@ -0,0 +1,22 @@
+#ifndef STYLEDTIMEDELEGATE_H
+#define STYLEDTIMEDELEGATE_H
+
+#include "src/opl.h"
+#include
+
+/*!
+ * \brief The StyledTimeDelegate class is used to convert the database time format to a human-readable format.
+ * \details The database stores time values as an integer representing minutes elapsed since midnight. This
+ * delegate can be used in a QTableView to format the database value as "hh:mm"
+ */
+class StyledTimeDelegate : public QStyledItemDelegate
+{
+public:
+ explicit StyledTimeDelegate(const OPL::DateTimeFormat &format, QObject *parent = nullptr);
+
+ QString displayText(const QVariant &value, const QLocale &locale) const override;
+private:
+ OPL::DateTimeFormat m_format;
+};
+
+#endif // STYLEDTIMEDELEGATE_H
diff --git a/src/classes/styledtypedelegate.cpp b/src/classes/styledtypedelegate.cpp
new file mode 100644
index 00000000..8825fa51
--- /dev/null
+++ b/src/classes/styledtypedelegate.cpp
@@ -0,0 +1,14 @@
+#include "styledtypedelegate.h"
+#include "src/database/databasecache.h"
+
+StyledTypeDelegate::StyledTypeDelegate(QObject *parent)
+ : QStyledItemDelegate{parent}
+{
+
+}
+
+QString StyledTypeDelegate::displayText(const QVariant &value, const QLocale &locale) const
+{
+ Q_UNUSED(locale);
+ return DBCache->getTypesMap().value(value.toInt());
+}
diff --git a/src/classes/styledtypedelegate.h b/src/classes/styledtypedelegate.h
new file mode 100644
index 00000000..eec64e68
--- /dev/null
+++ b/src/classes/styledtypedelegate.h
@@ -0,0 +1,16 @@
+#ifndef STYLEDTYPEDELEGATE_H
+#define STYLEDTYPEDELEGATE_H
+
+#include
+#include
+
+class StyledTypeDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ explicit StyledTypeDelegate(QObject *parent = nullptr);
+
+ QString displayText(const QVariant &value, const QLocale &locale) const override;
+};
+
+#endif // STYLEDTYPEDELEGATE_H
diff --git a/src/classes/time.cpp b/src/classes/time.cpp
index db3e2c14..2d5f8027 100644
--- a/src/classes/time.cpp
+++ b/src/classes/time.cpp
@@ -1,20 +1,47 @@
#include "time.h"
+#include "math.h"
namespace OPL {
-Time::Time()
+Time::Time(const DateTimeFormat &format)
+ : m_format(format),
+ m_minutes(-1)
+{}
+
+Time::Time(const QTime &qTime, const DateTimeFormat &format)
{
+ m_minutes = qTime.isValid() ? qTime.minute() + qTime.hour() * 60 : -1;
}
+Time::Time(int32_t minutes, const DateTimeFormat &format)
+ : m_minutes(minutes), m_format(format)
+{}
+
bool Time::isValidTimeOfDay() const
{
- return m_minutes <= MINUTES_PER_DAY;
+ return isValid() && m_minutes <= MINUTES_PER_DAY;
+}
+
+bool Time::isValid() const
+{
+ return m_minutes >= 0;
}
const QString Time::toString() const
{
- // convert to hh:mm
- return QString::number(m_minutes / 60).rightJustified(2, '0') + QLatin1Char(':') + QString::number(m_minutes % 60).rightJustified(2, '0');
+ switch(m_format.timeFormat()) {
+ case DateTimeFormat::TimeFormat::Default:
+ return QString::number(m_minutes / 60).rightJustified(2, '0')
+ + ':'
+ + QString::number(m_minutes % 60).rightJustified(2, '0');
+ case DateTimeFormat::TimeFormat::Decimal:
+ return QString::number(m_minutes / 60.0, 'f', 2);
+ break;
+ case DateTimeFormat::TimeFormat::Custom:
+ return QTime(0, m_minutes, 0).toString(m_format.timeFormatString());
+ default:
+ return QString();
+ }
}
int32_t Time::toMinutes() const
@@ -22,20 +49,38 @@ int32_t Time::toMinutes() const
return m_minutes;
}
-Time Time::fromString(const QString &timeString)
+Time Time::fromString(const QString &timeString, const DateTimeFormat &format)
{
- const QStringList parts = timeString.split(QChar(':'));
- if(parts.size() < 2)
- return {};
-
+ switch(format.timeFormat()) {
+ case DateTimeFormat::TimeFormat::Default:
+ {
+ const auto qTime = QTime::fromString(timeString, QStringLiteral("hh:mm"));
+ return Time(qTime, format);
+ break;
+ }
+ case DateTimeFormat::TimeFormat::Decimal:
+ {
+ // try to convert string to double
+ bool ok = false;
+ const double timeValue = timeString.toDouble(&ok);
- int32_t hours = parts[0].toInt();
- int32_t minutes = parts[1].toInt();
+ if(!ok) {
+ return {-1, format};
+ }
- if(hours < 0 || minutes < 0)
- return{};
+ // extract integer and fractional part
+ double hours, minutes;
+ hours = modf(timeValue, &minutes);
- return Time(hours * 60 + minutes);
+ // create the Time Object
+ return(Time(hours * 60 + minutes, format));
+ break;
+ }
+ case DateTimeFormat::TimeFormat::Custom:
+ const auto qTime = QTime::fromString(timeString, format.timeFormatString());
+ return Time(qTime, format);
+ break;
+ }
}
Time Time::blockTime(const Time &offBlocks, const Time &onBlocks)
@@ -43,16 +88,18 @@ Time Time::blockTime(const Time &offBlocks, const Time &onBlocks)
// make sure both times are in 24h range
bool bothTimesAreValid = offBlocks.isValidTimeOfDay() && onBlocks.isValidTimeOfDay();
if(!bothTimesAreValid)
- return {};
+ return {-1, offBlocks.m_format};
// calculate the block time
if(onBlocks.m_minutes > offBlocks.m_minutes) {
// take-off and landing on the same day
- return Time(onBlocks.m_minutes - offBlocks.m_minutes);
+ return Time(onBlocks.m_minutes - offBlocks.m_minutes, offBlocks.m_format);
} else {
+ if(offBlocks.m_minutes == onBlocks.m_minutes)
+ return Time(0, offBlocks.m_format);
// landing the day after take off
int minutesToMidnight = MINUTES_PER_DAY - offBlocks.m_minutes;
- return Time(minutesToMidnight + onBlocks.m_minutes);
+ return Time(minutesToMidnight + onBlocks.m_minutes, offBlocks.m_format);
}
}
diff --git a/src/classes/time.h b/src/classes/time.h
index a708cf52..65383c9c 100644
--- a/src/classes/time.h
+++ b/src/classes/time.h
@@ -1,6 +1,7 @@
#ifndef TIME_H
#define TIME_H
+#include "src/opl.h"
#include
namespace OPL {
@@ -8,18 +9,17 @@ namespace OPL {
* \brief The Time class handles conversions between user input / user-facing time data display and
* database format.
* \details Time data in the database is stored as an integer value of minutes, whereas the user-facing
- * time data is normally displayed in the Qt::ISODATE format. A database value of 72 would for example be
- * displayed as 01:12 (1 hour and 12 minutes).
+ * time data is normally displayed in accordance with the selected DateTimeFormat, by default "hh:mm".
*/
class Time
{
-private:
- const static inline int MINUTES_PER_DAY = 24 * 60;
- int32_t m_minutes = 0;
-
public:
- Time();
- Time(int32_t minutes) : m_minutes(minutes) {};
+ Time() = delete;
+ Time(const DateTimeFormat &format);
+ Time(const QTime &qTime, const DateTimeFormat &format);
+ Time(int32_t minutes, const DateTimeFormat &format);;
+
+ enum TimeFrame {Day, Week, Year};
/**
* @brief isValidTimeOfDay - determines whether the instance can be converted to a time hh:mm
@@ -27,8 +27,13 @@ class Time
*/
bool isValidTimeOfDay() const;
+ /*!
+ * \brief a time is considered valid if it has a time value of >= 0
+ */
+ bool isValid() const;
+
/**
- * @brief toString returns the time as hh:mm
+ * @brief toString returns the time in the specified format
*/
const QString toString() const;
@@ -42,17 +47,49 @@ class Time
* @param timeString the input string
* @return the Time Object corresponding to the string, equivalent to 0 minutes if conversion fails.
*/
- static Time fromString(const QString& timeString);
+ static Time fromString(const QString& timeString, const DateTimeFormat &format);
- /**
- * @brief timeDifference returns the time difference between this time and another time object.
- * @param other - The other time object
- * @return the number of minutes of time difference, or 0 if one of the two objects is greater than 24h
+ /*!
+ * \brief Calculate the elapsed time between two events
+ * \param offBlocks - The start tmie
+ * \param onBlocks - the end time
+ * \return The elapsed time
*/
- int32_t timeElapsed(const Time &other);
-
static Time blockTime(const Time &offBlocks, const Time& onBlocks);
+
+ /*!
+ * \brief Calculate elapsed time between two events
+ * \param offBlocks - The start time
+ * \param onBlocks - The end time
+ * \return the elapsed time in minutes
+ */
static int32_t blockMinutes(const Time &offBlocks, const Time& onBlocks);
+
+ /*!
+ * \brief toMinutes returns the number of minutes in the given time frame
+ * \param count - The number of time frames (e.g. '7' days)
+ * \return
+ */
+ static constexpr int timeFrameToMinutes(TimeFrame timeFrame, int count) {
+ switch (timeFrame) {
+ case Day:
+ return count * MINUTES_PER_DAY;
+ case Week:
+ return count * 7 * MINUTES_PER_DAY;
+ case Year:
+ return count * 7 * 52 * MINUTES_PER_DAY;
+ default:
+ return 0;
+ }
+ }
+
+
+private:
+ static constexpr int MINUTES_PER_DAY = 24 * 60;
+
+ const DateTimeFormat m_format;
+ int32_t m_minutes;
+
};
}// namespace OPL
diff --git a/src/database/airportentry.cpp b/src/database/airportentry.cpp
index f7508831..abd1c7cb 100644
--- a/src/database/airportentry.cpp
+++ b/src/database/airportentry.cpp
@@ -46,4 +46,27 @@ const QString AirportEntry::getIcaoCode() const
return getData().value(ICAO).toString();
}
+const QString AirportEntry::getAirportName() const
+{
+ return getData().value(NAME).toString();
+}
+
+const QString AirportEntry::getAirportDescriptor() const
+{
+ if(getIataCode().isEmpty()) {
+ if(getAirportName().isEmpty()) {
+ return getIcaoCode();
+ }
+ return getIcaoCode()
+ + QStringLiteral(" - ")
+ + getAirportName();
+ }
+ return getIcaoCode()
+ + QStringLiteral(" - ")
+ + getAirportName()
+ + QStringLiteral(" (")
+ + getIataCode()
+ + QLatin1Char(')');
+}
+
} // namespace OPL
diff --git a/src/database/airportentry.h b/src/database/airportentry.h
index aed9096c..c63ddf90 100644
--- a/src/database/airportentry.h
+++ b/src/database/airportentry.h
@@ -43,6 +43,18 @@ class AirportEntry : public Row
*/
const QString getIcaoCode() const;
+ /*!
+ * \brief Returns the airport common given name
+ */
+ const QString getAirportName() const;
+
+ /*!
+ * \brief return a string describing the airport
+ * \details The string consists of the Airport ICAO Code, and if available
+ * IATA Code and Airport Name
+ */
+ const QString getAirportDescriptor() const;
+
/*!
* \brief The ICAO code is a 4-letter alphanumeric identifier for airports
*/
diff --git a/src/database/currencyentry.cpp b/src/database/currencyentry.cpp
index 42f57515..d23663e5 100644
--- a/src/database/currencyentry.cpp
+++ b/src/database/currencyentry.cpp
@@ -19,14 +19,6 @@
namespace OPL {
-CurrencyEntry::CurrencyEntry()
- : Row(DbTable::Currencies, 0)
-{}
-
-CurrencyEntry::CurrencyEntry(const RowData_T &row_data)
- : Row(DbTable::Currencies, 0, row_data)
-{}
-
CurrencyEntry::CurrencyEntry(int row_id, const RowData_T &row_data)
: Row(DbTable::Currencies, row_id, row_data)
{}
@@ -36,4 +28,28 @@ const QString CurrencyEntry::getTableName() const
return TABLE_NAME;
}
+void CurrencyEntry::setName(const QString &displayName)
+{
+ auto data = getData();
+ data.insert(NAME, displayName);
+ setData(data);
+}
+
+const QString CurrencyEntry::getName() const
+{
+ return getData().value(NAME).toString();
+}
+
+void CurrencyEntry::setExpiryDate(const Date &date)
+{
+ auto data = getData();
+ data.insert(EXPIRYDATE, date.toJulianDay());
+ setData(data);
+}
+
+const Date CurrencyEntry::getExpiryDate(const OPL::DateTimeFormat &format) const
+{
+ return OPL::Date(getData().value(EXPIRYDATE).toInt(), format);
+}
+
} // namespace OPL
diff --git a/src/database/currencyentry.h b/src/database/currencyentry.h
index f3d0a2ba..32c1c882 100644
--- a/src/database/currencyentry.h
+++ b/src/database/currencyentry.h
@@ -18,6 +18,7 @@
#ifndef CURRENCYENTRY_H
#define CURRENCYENTRY_H
#include "src/database/row.h"
+#include "src/classes/date.h"
namespace OPL {
@@ -29,23 +30,39 @@ namespace OPL {
*/
class CurrencyEntry : public Row
{
- const static inline QString TABLE_NAME = QStringLiteral("currencies");
public:
- CurrencyEntry();
- CurrencyEntry(const RowData_T &row_data);
+
+ enum Currency {Licence = 1, TypeRating = 2, LineCheck = 3, Medical = 4, Custom1 = 5, Custom2 = 6, TakeOffLanding = 7};
+
+ CurrencyEntry() = delete;
+ CurrencyEntry(const RowData_T &row_data) = delete;
CurrencyEntry(int row_id, const RowData_T &row_data);
const QString getTableName() const override;
+ void setName(const QString& displayName);
+ const QString getName() const;
+
+ void setExpiryDate(const OPL::Date &date);
+ const OPL::Date getExpiryDate(const OPL::DateTimeFormat &format) const;
+
+private:
+
+ /*!
+ * \brief The sql column name for the row id
+ */
+ const static inline QString ROW_ID = QStringLiteral("currency_id");
+ /*!
+ * \brief The sql column name for the display name
+ */
+ const static inline QString NAME = QStringLiteral("currencyName");
/*!
* \brief The sql column name for the expiry date
*/
const static inline QString EXPIRYDATE = QStringLiteral("expiryDate");
- /*!
- * \brief The sql column name for the currency name
- */
- const static inline QString CURRENCYNAME = QStringLiteral("currencyName");
+
+ const static inline QString TABLE_NAME = QStringLiteral("currencies");
};
} // namespace OPL
diff --git a/src/database/database.cpp b/src/database/database.cpp
index 82e0eb1d..d42d3205 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -517,6 +517,7 @@ const RowData_T Database::getTotals(bool includePreviousExperience)
return entry_data;
}
+ // name the return types for easy mapping to QLineEdit names
statement = "SELECT"
" SUM(tblk) AS tblk,"
" SUM(tSPSE) AS tSPSE,"
@@ -563,10 +564,10 @@ const RowData_T Database::getTotals(bool includePreviousExperience)
int entryValue = entry_data.value(it.key()).toInt();
const QVariant sum = prevXpValue + entryValue;
- it.value() = sum;
+ entry_data.insert(it.key(), sum);
}
- return prev_exp_data;
+ return entry_data;
}
QList Database::getForeignKeyConstraints(int foreign_row_id, OPL::DbTable table)
diff --git a/src/database/database.h b/src/database/database.h
index 9d0cb8ff..568be471 100644
--- a/src/database/database.h
+++ b/src/database/database.h
@@ -277,10 +277,10 @@ class Database : public QObject {
/*!
* \brief Retreives a currency entry from the database. See row class for details.
*/
- inline OPL::CurrencyEntry getCurrencyEntry(int row_id)
+ inline OPL::CurrencyEntry getCurrencyEntry(OPL::CurrencyEntry::Currency currency)
{
- const auto data = getRowData(OPL::DbTable::Currencies, row_id);
- return OPL::CurrencyEntry(row_id, data);
+ const auto data = getRowData(OPL::DbTable::Currencies, currency);
+ return OPL::CurrencyEntry(currency, data);
}
/*!
diff --git a/src/database/databasecache.cpp b/src/database/databasecache.cpp
index 6cf68653..dd9d1174 100644
--- a/src/database/databasecache.cpp
+++ b/src/database/databasecache.cpp
@@ -58,6 +58,11 @@ const IdMap DatabaseCache::fetchMap(CompleterTarget target)
case Tails:
statement.append(QStringLiteral("SELECT ROWID, registration FROM tails"));
break;
+ case Types:
+ statement.append(QStringLiteral("SELECT ROWID, make||' '||model FROM tails WHERE model IS NOT NULL AND variant IS NULL "
+ " UNION "
+ " SELECT ROWID, make||' '||model||'-'||variant FROM tails WHERE variant IS NOT NULL"));
+ break;
case AircraftTypes:
statement.append(QStringLiteral("SELECT ROWID, make||' '||model FROM aircraft WHERE model IS NOT NULL AND variant IS NULL "
"UNION "
@@ -132,6 +137,7 @@ void DatabaseCache::updateTails()
reg = copy + " (" + reg + QLatin1Char(')');
}
}
+ typesMap = fetchMap(Types);
}
void DatabaseCache::updateAirports()
@@ -144,7 +150,7 @@ void DatabaseCache::updateAirports()
void DatabaseCache::updateSimulators()
{
- TODO << "not yet implemented";
+ TODO << "Simulators map not yet cached";
}
void DatabaseCache::updatePilots()
@@ -239,6 +245,11 @@ const IdMap &DatabaseCache::getTailsMap() const
return tailsMap;
}
+const IdMap &DatabaseCache::getTypesMap() const
+{
+ return typesMap;
+}
+
} // namespace OPL
diff --git a/src/database/databasecache.h b/src/database/databasecache.h
index ef76b869..6f7738f8 100644
--- a/src/database/databasecache.h
+++ b/src/database/databasecache.h
@@ -44,7 +44,7 @@ class DatabaseCache : public QObject
DatabaseCache(DatabaseCache const&) = delete;
void operator=(DatabaseCache const&) = delete;
- enum CompleterTarget {PilotNames, Tails, AircraftTypes, AirportsAny, AirportsICAO, AirportNames, AirportsIATA, Companies};
+ enum CompleterTarget {PilotNames, Tails, AircraftTypes, AirportsAny, AirportsICAO, AirportNames, AirportsIATA, Companies, Types};
void init();
@@ -52,6 +52,7 @@ class DatabaseCache : public QObject
const IdMap &getAirportsMapIATA() const;
const IdMap &getPilotNamesMap() const;
const IdMap &getTailsMap() const;
+ const IdMap &getTypesMap() const;
const QStringList &getPilotNamesList() const;
const QStringList &getTailsList() const;
@@ -74,7 +75,14 @@ class DatabaseCache : public QObject
IdMap airportsMapIATA;
IdMap airportsMapNames;
IdMap pilotNamesMap;
+ /*!
+ * \brief key: tail_id / value: registration
+ */
IdMap tailsMap;
+ /*!
+ * \brief key: tail_id value: type string ("Boeing 737-800")
+ */
+ IdMap typesMap;
IdMap aircraftMap;
// Lists
QStringList pilotNamesList;
diff --git a/src/database/flightentry.cpp b/src/database/flightentry.cpp
index 9f685716..68fef2a2 100644
--- a/src/database/flightentry.cpp
+++ b/src/database/flightentry.cpp
@@ -16,6 +16,8 @@
*along with this program. If not, see .
*/
#include "flightentry.h"
+#include "src/classes/date.h"
+#include "src/classes/time.h"
namespace OPL {
@@ -36,4 +38,26 @@ const QString FlightEntry::getTableName() const
return TABLE_NAME;
}
+const QString FlightEntry::getFlightSummary() const
+{
+ using namespace OPL;
+ if(!isValid())
+ return QString();
+
+ auto tableData = getData();
+ QString flight_summary;
+ const auto space = QLatin1Char(' ');
+ flight_summary.append(Date(tableData.value(FlightEntry::DOFT).toInt(), DateTimeFormat()).toString() + space);
+ flight_summary.append(tableData.value(FlightEntry::DEPT).toString() + space);
+ flight_summary.append(Time(tableData.value(FlightEntry::TOFB).toInt(), DateTimeFormat()).toString()
+ + space);
+ flight_summary.append(Time(tableData.value(FlightEntry::TONB).toInt(), DateTimeFormat()).toString()
+ + space);
+ flight_summary.append(tableData.value(FlightEntry::DEST).toString());
+
+ return flight_summary;
+}
+
+
+
} // namespace OPL
diff --git a/src/database/flightentry.h b/src/database/flightentry.h
index c5a03db3..fd30fe19 100644
--- a/src/database/flightentry.h
+++ b/src/database/flightentry.h
@@ -34,6 +34,11 @@ class FlightEntry : public Row
const QString getTableName() const override;
+ /*!
+ * \brief returns a String representation of the key data of this flight
+ */
+ const QString getFlightSummary() const;
+
const static inline QString ROWID = QStringLiteral("flight_id");
const static inline QString DOFT = QStringLiteral("doft");
const static inline QString DEPT = QStringLiteral("dept");
diff --git a/src/database/tailentry.cpp b/src/database/tailentry.cpp
index bd3a09de..a708d933 100644
--- a/src/database/tailentry.cpp
+++ b/src/database/tailentry.cpp
@@ -42,7 +42,22 @@ const QString TailEntry::registration() const
}
const QString TailEntry::type() const {
- return getData().value(MAKE).toString();
+ const auto &data = getData();
+
+ if(data.value(VARIANT).toString().isEmpty()) {
+ if(data.value(MODEL).toString().isEmpty()) {
+ return data.value(MAKE).toString();
+ }
+ return data.value(MAKE).toString()
+ + QLatin1Char(' ')
+ + data.value(MODEL).toString();
+ }
+
+ return data.value(MAKE).toString()
+ + QLatin1Char(' ')
+ + data.value(MODEL).toString()
+ + QLatin1Char('-')
+ + data.value(VARIANT).toString();
}
} // namespace OPL
diff --git a/src/database/tailentry.h b/src/database/tailentry.h
index 67686a1e..62f9d3aa 100644
--- a/src/database/tailentry.h
+++ b/src/database/tailentry.h
@@ -44,9 +44,9 @@ class TailEntry : public Row
*/
const QString registration() const;
/*!
- * \brief Return the aircraft type
+ * \brief Return the aircraft type (Make and - if available - Model and Variant)
*/
- const QString type() const; //TODO - Create String for make-model-variant
+ const QString type() const;
/*!
* \brief The entries row id in the database
@@ -102,6 +102,11 @@ class TailEntry : public Row
* <\ul>
*/
static const inline QString WEIGHT_CLASS = QStringLiteral("weightClass");
+
+ /*!
+ * \brief The aircraft type string ("Make Model-Variant")
+ */
+ static const inline QString TYPE_STRING = QStringLiteral("typeString");
};
} // namespace OPL
diff --git a/src/database/views/logbookviewinfo.h b/src/database/views/logbookviewinfo.h
new file mode 100644
index 00000000..05f14165
--- /dev/null
+++ b/src/database/views/logbookviewinfo.h
@@ -0,0 +1,186 @@
+#ifndef LOGBOOKVIEWINFO_H
+#define LOGBOOKVIEWINFO_H
+
+#include "src/opl.h"
+#include
+
+namespace OPL {
+
+
+/*!
+ * \brief The LogbookViewInfo class is a base class for classes that encapsulate information
+ * about a LogbookView
+ * \details In the logbook display, SQL views are used instead of raw table data, since in
+ * some cases data is aggregated from different tables. Using views avoid
+ */
+class LogbookViewInfo : public QObject {
+ Q_OBJECT // enable tr()
+public:
+
+ /*!
+ * \brief Return the column in the view which contains the date of flight
+ */
+ static constexpr int getDateColumn(LogbookView view)
+ {
+ return DATE_COLUMNS.at(static_cast(view));
+ }
+
+ /*!
+ * \brief Return the column in the view which contains the aircrafts type
+ */
+ static constexpr int getTypeColumn(LogbookView view)
+ {
+ return TYPE_COLUMNS.at(static_cast(view));
+ }
+
+ /*!
+ * \brief Return the column(s) in the view which contain pilot names
+ */
+ static constexpr int getPicColumn(LogbookView view)
+ {
+ return PIC_COLUMNS.at(static_cast(view));
+ }
+
+ /*!
+ * \brief Return the column(s) in the view which contain Time entries
+ */
+ static constexpr std::vector getTimeColumns(LogbookView view)
+ {
+ switch (view) {
+ case LogbookView::Default:
+ return { 3, 5, 6 };
+ case LogbookView::DefaultWithSim:
+ return { 3, 5, 6, 11 };
+ case LogbookView::Easa:
+ return { 3, 5, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20 };
+ case LogbookView::EasaWithSim:
+ return { 3, 5, 8, 9, 10, 11, 15, 16, 17, 18, 19, 20, 22 };
+ default:
+ assert(((void)"View is not implemented", false));
+ return { 0 };
+ }
+ }
+
+ // translations need to be done at runtime
+ static const QStringList getTableHeaders(LogbookView view)
+ {
+ switch (view) {
+ case LogbookView::Default:
+ return {
+ QStringLiteral("flight_id"), // flight id column - hidden
+ tr("Date of Flight"),
+ tr("Dept"),
+ tr("Time"),
+ tr("Dest"),
+ tr("Time"),
+ tr("Total"),
+ tr("Name PIC"),
+ tr("Type"),
+ tr("Registration"),
+ tr("Flight Number"),
+ tr("Remarks"),
+ };
+ case LogbookView::DefaultWithSim:
+ return {
+ QStringLiteral("flight_id"), // flight id column - hidden
+ tr("Date of Flight"),
+ tr("Dept"),
+ tr("Time"),
+ tr("Dest"),
+ tr("Time"),
+ tr("Total"),
+ tr("Name PIC"),
+ tr("Type"),
+ tr("Registration"),
+ tr("Sim Type"),
+ tr("Time of Session"),
+ tr("Remarks"),
+ };
+ case LogbookView::Easa:
+ return {
+ QStringLiteral("flight_id"), // flight id column - hidden
+ tr("Date of Flight"),
+ tr("Dept"),
+ tr("Time"),
+ tr("Dest"),
+ tr("Time"),
+ tr("Type"),
+ tr("Registration"),
+ tr("SP SE"),
+ tr("SP ME"),
+ tr("MP"),
+ tr("Total"),
+ tr("Name PIC"),
+ tr("L/D"),
+ tr("L/N"),
+ tr("Night"),
+ tr("IFR"),
+ tr("PIC"),
+ tr("SIC"),
+ tr("Dual"),
+ tr("FI"),
+ tr("Remarks"),
+ };
+ case LogbookView::EasaWithSim:
+ return {
+ QStringLiteral("flight_id"), // flight id column - hidden
+ tr("Date of Flight"),
+ tr("Dept"),
+ tr("Time"),
+ tr("Dest"),
+ tr("Time"),
+ tr("Type"),
+ tr("Registration"),
+ tr("SP SE"),
+ tr("SP ME"),
+ tr("MP"),
+ tr("Total"),
+ tr("Name PIC"),
+ tr("L/D"),
+ tr("L/N"),
+ tr("Night"),
+ tr("IFR"),
+ tr("PIC"),
+ tr("SIC"),
+ tr("Dual"),
+ tr("FI"),
+ tr("Sim Type"),
+ tr("Time of Session"),
+ tr("Remarks"),
+ };
+ default:
+ assert(((void)"View is not implemented", false));
+ return {};
+ }
+ }
+
+private:
+
+ static constexpr std::array DATE_COLUMNS {
+ 1, // Default
+ 1, // Default With Sim
+ 1, // Easa
+ 1, // Easa With Sim
+ 1, // Simulator Only
+ };
+
+ static constexpr std::array TYPE_COLUMNS {
+ 8, // Default
+ 8, // Default With Sim
+ 6, // Easa
+ 6, // Easa With Sim
+ 1, // Simulator Only
+ };
+
+ static constexpr std::array PIC_COLUMNS {
+ 7, // Default
+ 7, // Default With Sim
+ 12, // Easa
+ 12, // Easa With Sim
+ -1, // Simulator Only
+ };
+
+};
+
+} // namespace OPL
+#endif // LOGBOOKVIEWINFO_H
diff --git a/src/functions/calc.cpp b/src/functions/calc.cpp
index 7cae53de..097533c0 100644
--- a/src/functions/calc.cpp
+++ b/src/functions/calc.cpp
@@ -343,7 +343,7 @@ void OPL::Calc::updateAutoTimes(int acft_id)
*/
void OPL::Calc::updateNightTimes()
{
- const int night_angle = Settings::read(Settings::FlightLogging::NightAngle).toInt();
+ int night_angle = Settings::getNightAngle();
//find all flights for aircraft
auto statement = QStringLiteral("SELECT ROWID FROM flights");
diff --git a/src/functions/calc.h b/src/functions/calc.h
index 7d3f83a8..30332b4b 100644
--- a/src/functions/calc.h
+++ b/src/functions/calc.h
@@ -144,8 +144,8 @@ struct NightTimeValues{
{
nightMinutes = calculateNightTime(dept, dest, departure_time, block_minutes, night_angle);
- nightTime = OPL::Time(nightMinutes);
- totalTime = OPL::Time(block_minutes);
+ OPL::Time nightTime = OPL::Time(nightMinutes, DateTimeFormat());
+ OPL::Time totalTime = OPL::Time(block_minutes, DateTimeFormat());
if (nightMinutes == 0) { // all day
takeOffNight = false;
@@ -167,13 +167,13 @@ struct NightTimeValues{
};
- NightTimeValues(bool to_night, bool ldg_night, int night_minutes, OPL::Time night_time, OPL::Time total_time)
- : takeOffNight(to_night), landingNight(ldg_night), nightMinutes(night_minutes), nightTime(night_time), totalTime(total_time){};
+// NightTimeValues(bool to_night, bool ldg_night, int night_minutes, OPL::Time night_time, OPL::Time total_time)
+// : takeOffNight(to_night), landingNight(ldg_night), nightMinutes(night_minutes), nightTime(night_time), totalTime(total_time){};
bool takeOffNight;
bool landingNight;
int nightMinutes;
- OPL::Time nightTime;
- OPL::Time totalTime;
+// OPL::Time nightTime;
+// OPL::Time totalTime;
inline bool isAllDay() {return (!takeOffNight && !landingNight);}
inline bool isAllNight() {return ( takeOffNight && landingNight);}
diff --git a/src/functions/datetime.h b/src/functions/datetime.h
index 4e9ec963..bee0d4ba 100644
--- a/src/functions/datetime.h
+++ b/src/functions/datetime.h
@@ -1,10 +1,17 @@
#ifndef DATETIME_H
#define DATETIME_H
#include "src/opl.h"
+#include "src/classes/date.h"
+#include "src/classes/time.h"
namespace OPL {
class DateTime {
+
+public:
+// DateTime(const OPL::Date date, const OPL::Time &time);
+
+
public:
const inline static QString ISO_FORMAT_STRING = QStringLiteral("yyyy-MM-dd");
const inline static QString DE_FORMAT_STRING = QStringLiteral("dd.MM.yyyy");
@@ -69,11 +76,11 @@ class DateTime {
* \brief dateTimeToString formats a QDateTime object into a string in a uniform way.
* \return
*/
- static inline const QString dateTimeToString (const QDateTime& date_time, OPL::DateTimeFormat format) {
+ static inline const QString dateTimeToString (const QDateTime& date_time, OPL::DateTimeFormat_deprecated format) {
switch (format) {
- case OPL::DateTimeFormat::Default:
+ case OPL::DateTimeFormat_deprecated::Default:
return date_time.toString(Qt::ISODate);
- case OPL::DateTimeFormat::Backup:
+ case OPL::DateTimeFormat_deprecated::Backup:
return date_time.toString(QStringLiteral("yyyy_MM_dd_T_hh_mm"));
default:
return QString();
diff --git a/src/functions/statistics.cpp b/src/functions/statistics.cpp
index fbf92019..5779fb46 100644
--- a/src/functions/statistics.cpp
+++ b/src/functions/statistics.cpp
@@ -35,21 +35,21 @@ int OPL::Statistics::totalTime(TimeFrame time_frame)
break;
case TimeFrame::CalendarYear:
start.setDate(QDate::currentDate().year(), 1, 1);
- start_date = start.toString(Qt::ISODate);
+ start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
break;
case TimeFrame::Rolling12Months:
start = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - 365);
- start_date = start.toString(Qt::ISODate);
+ start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
break;
case TimeFrame::Rolling28Days:
start = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - 28);
- start_date = start.toString(Qt::ISODate);
+ start_date = QString::number(start.toJulianDay());
start_date.append(QLatin1Char('\''));
start_date.prepend(QLatin1Char('\''));
statement = QLatin1String("SELECT SUM(tblk) FROM flights WHERE doft >= ") + start_date;
@@ -72,16 +72,17 @@ int OPL::Statistics::totalTime(TimeFrame time_frame)
*/
QVector OPL::Statistics::countTakeOffLanding(int days)
{
- QDate start = QDate::fromJulianDay(QDate::currentDate().toJulianDay() - days);
- QString startdate = start.toString(Qt::ISODate);
- startdate.append(QLatin1Char('\''));
- startdate.prepend(QLatin1Char('\''));
+ QString startDate = QString::number(QDate::fromJulianDay(QDate::currentDate().toJulianDay() - days).toJulianDay());
+
+ // QString startdate = start.toString(Qt::ISODate);
+ startDate.append(QLatin1Char('\''));
+ startDate.prepend(QLatin1Char('\''));
QString statement = QLatin1String("SELECT "
" SUM(IFNULL(flights.toDay,0) + IFNULL(flights.toNight,0)) AS 'TO', "
" SUM(IFNULL(flights.ldgDay,0) + IFNULL(flights.ldgNight,0)) AS 'LDG' "
" FROM flights "
- " WHERE doft >=") + startdate;
+ " WHERE doft >=") + startDate;
QVector result = DB->customQuery(statement, 2);
// make sure a value is returned instead of NULL
diff --git a/src/gui/dialogues/entryeditdialog.cpp b/src/gui/dialogues/entryeditdialog.cpp
new file mode 100644
index 00000000..b664088d
--- /dev/null
+++ b/src/gui/dialogues/entryeditdialog.cpp
@@ -0,0 +1,13 @@
+#include "entryeditdialog.h"
+
+EntryEditDialog::EntryEditDialog(QWidget *parent)
+ : QDialog{parent}
+{
+ rowID = 0;
+}
+
+EntryEditDialog::EntryEditDialog(int rowID, QWidget *parent)
+ : QDialog{parent}, rowID(rowID)
+{
+
+}
diff --git a/src/gui/dialogues/entryeditdialog.h b/src/gui/dialogues/entryeditdialog.h
new file mode 100644
index 00000000..4981eb80
--- /dev/null
+++ b/src/gui/dialogues/entryeditdialog.h
@@ -0,0 +1,35 @@
+#ifndef ENTRYEDITDIALOG_H
+#define ENTRYEDITDIALOG_H
+
+#include
+#include
+
+/*!
+ * \brief The EntryEditDialog class is a base class for Dialogs that enable editing of individual database entries
+ */
+class EntryEditDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ EntryEditDialog() = delete;
+ EntryEditDialog(QWidget *parent = nullptr);
+ EntryEditDialog(int rowID, QWidget *parent = nullptr);
+
+ /*!
+ * \brief load an entry from the database for editing
+ * \param rowID - The row ID of the entry
+ */
+ virtual void loadEntry(int rowID) = 0;
+
+ /*!
+ * \brief delete an entry from the database
+ * \param rowID - the row ID to be deleted
+ * \return true on success
+ */
+ virtual bool deleteEntry(int rowID) = 0;
+
+protected:
+ int rowID;
+};
+
+#endif // ENTRYEDITDIALOG_H
diff --git a/src/gui/dialogues/exporttocsvdialog.cpp b/src/gui/dialogues/exporttocsvdialog.cpp
index eac4c4dc..099bea89 100644
--- a/src/gui/dialogues/exporttocsvdialog.cpp
+++ b/src/gui/dialogues/exporttocsvdialog.cpp
@@ -56,7 +56,7 @@ void ExportToCsvDialog::selectRows()
// create a QSqlTableModel based on the selected views
const auto model = new QSqlTableModel(this);
if(ui->viewComboBox->currentIndex() < 4)
- model->setTable(OPL::GLOBALS->getViewIdentifier(OPL::DbViewName(ui->viewComboBox->currentIndex())));
+ model->setTable(OPL::GLOBALS->getViewIdentifier(OPL::LogbookView(ui->viewComboBox->currentIndex())));
else
model->setTable(exportView);
model->select();
diff --git a/src/gui/dialogues/firstrundialog.cpp b/src/gui/dialogues/firstrundialog.cpp
index fd16c2dc..1042fcf6 100644
--- a/src/gui/dialogues/firstrundialog.cpp
+++ b/src/gui/dialogues/firstrundialog.cpp
@@ -150,7 +150,7 @@ bool FirstRunDialog::finishSetup()
} // if database file exists
if (!DB->connect()) {
- QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+ QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed (connect)"),
tr("Errors have ocurred creating the database."
"Without a working database The application will not be usable.
"
"The following error has ocurred:
"
@@ -160,7 +160,7 @@ bool FirstRunDialog::finishSetup()
}
if (!setupDatabase()) {
- QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+ QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed (create schema)"),
tr("Errors have ocurred creating the database."
"Without a working database The application will not be usable.
"
"The following error has ocurred:
%1"
@@ -170,7 +170,7 @@ bool FirstRunDialog::finishSetup()
}
if (!createUserEntry()) {
- QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+ QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed (user entry)"),
tr("Unable to execute database query
"
"The following error has occured:
%1"
).arg(DB->lastError.text()));
@@ -179,7 +179,7 @@ bool FirstRunDialog::finishSetup()
}
if (!setupPreviousExperienceEntry()) {
- QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+ QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed (previous Experience)"),
tr("Unable to execute database query
"
"The following error has occured:
%1"
).arg(DB->lastError.text()));
@@ -187,14 +187,10 @@ bool FirstRunDialog::finishSetup()
return false;
}
- if (!writeCurrencies()) {
- QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
- tr("Unable to execute database query
"
- "The following error has occured:
%1"
- ).arg(DB->lastError.text()));
- message_box.exec();
- return false;
- }
+ // non-critical error
+ if(!writeCurrencies())
+ LOG << "Error writing currencies during initial setup.";
+
DB->disconnect(); // Connection will be re-established by MainWindow
return true;
}
@@ -274,23 +270,24 @@ bool FirstRunDialog::verifyTemplates()
void FirstRunDialog::writeSettings()
{
Settings::resetToDefaults();
+ Settings::setPilotFunction(OPL::PilotFunction(ui->functionComboBox->currentIndex()));
+ Settings::setApproachType(ui->approachComboBox->currentText());
+ Settings::setNightLoggingEnabled(ui->nightComboBox->currentIndex());
+ Settings::setLogIfr(ui->rulesComboBox->currentIndex());
+ Settings::setFlightNumberPrefix(ui->prefixLineEdit->text());
+ Settings::setLogbookView(OPL::LogbookView(ui->logbookViewComboBox->currentIndex()));
+ Settings::setApplicationStyle(ui->styleComboBox->currentText());
- Settings::write(Settings::FlightLogging::Function, ui->functionComboBox->currentIndex());
- Settings::write(Settings::FlightLogging::Approach, ui->approachComboBox->currentIndex());
- Settings::write(Settings::FlightLogging::NightLoggingEnabled, ui->nightComboBox->currentIndex());
switch (ui->nightRulesComboBox->currentIndex()) {
case 0:
- Settings::write(Settings::FlightLogging::NightAngle, -6);
+ Settings::setNightAngle(-6);
break;
case 1:
- Settings::write(Settings::FlightLogging::NightAngle, 0);
+ Settings::setNightAngle(0);
break;
}
- Settings::write(Settings::FlightLogging::LogIFR, ui->rulesComboBox->currentIndex());
- Settings::write(Settings::FlightLogging::FlightNumberPrefix, ui->prefixLineEdit->text());
- Settings::write(Settings::UserData::DisplaySelfAs, ui->aliasComboBox->currentIndex());
- Settings::write(Settings::Main::LogbookView, ui->logbookViewComboBox->currentIndex());
- Settings::write(Settings::Main::Style, ui->styleComboBox->currentText());
+
+ Settings::setShowSelfAs(ui->aliasComboBox->currentIndex());
Settings::sync();
}
@@ -352,39 +349,32 @@ bool FirstRunDialog::setupPreviousExperienceEntry()
bool FirstRunDialog::writeCurrencies()
{
- const QMap currencies_list = {
- {OPL::CurrencyName::Licence, ui->currLicDateEdit},
- {OPL::CurrencyName::TypeRating, ui->currTrDateEdit},
- {OPL::CurrencyName::LineCheck, ui->currLckDateEdit},
- {OPL::CurrencyName::Medical, ui->currMedDateEdit},
- {OPL::CurrencyName::Custom1, ui->currCustom1DateEdit},
- {OPL::CurrencyName::Custom2, ui->currCustom2DateEdit},
- };
- const QMap settings_list = {
- {OPL::CurrencyName::Licence, Settings::UserData::ShowLicCurrency },
- {OPL::CurrencyName::TypeRating, Settings::UserData::ShowTrCurrency },
- {OPL::CurrencyName::LineCheck, Settings::UserData::ShowLckCurrency },
- {OPL::CurrencyName::Medical, Settings::UserData::ShowMedCurrency },
- {OPL::CurrencyName::Custom1, Settings::UserData::ShowCustom1Currency },
- {OPL::CurrencyName::Custom2, Settings::UserData::ShowCustom2Currency },
+ const QList> currencies = {
+ { ui->currLicLabel->text(), ui->currLicDateEdit },
+ { ui->currTrLabel->text(), ui->currTrDateEdit },
+ { ui->currLckLabel->text(), ui->currLckDateEdit },
+ { ui->currMedLabel->text(), ui->currMedDateEdit },
+ { ui->currCustom1LineEdit->text(), ui->currCustom1DateEdit },
+ { ui->currCustom2LineEdit->text(), ui->currCustom2DateEdit },
};
- QDate today = QDate::currentDate();
- for (const auto &date_edit : currencies_list) {
- const auto enum_value = currencies_list.key(date_edit);
- // only write dates that have been edited
- if (date_edit->date() != today) {
- OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date_edit->date().toString(Qt::ISODate)}};
- if (enum_value == OPL::CurrencyName::Custom1)
- row_data.insert(OPL::CurrencyEntry::CURRENCYNAME, ui->currCustom1LineEdit->text());
- else if(enum_value == OPL::CurrencyName::Custom2)
- row_data.insert(OPL::CurrencyEntry::CURRENCYNAME, ui->currCustom2LineEdit->text());
-
- Settings::write(settings_list.value(enum_value), true); // Show selected currency on Home Screen
- OPL::CurrencyEntry entry(static_cast(enum_value), row_data);
- if (!DB->commit(entry))
- return false;
+ const QDate today = QDate::currentDate();
+
+ for(const auto &pair : currencies) {
+ // list 0-indexed, db row indexes start at 1
+ OPL::CurrencyEntry currencyEntry = OPL::CurrencyEntry(currencies.indexOf(pair) + 1, OPL::RowData_T());
+
+ currencyEntry.setName(pair.first);
+
+ // only set expiry date if user has modified it
+ const QDate date = pair.second->date();
+ if(date != today) {
+ int julianDay = date.toJulianDay();
+ currencyEntry.setExpiryDate(OPL::Date(julianDay, m_format));
}
+
+ if(!DB->commit(currencyEntry))
+ return false;
}
return true;
}
@@ -434,16 +424,6 @@ void FirstRunDialog::on_styleComboBox_currentTextChanged(const QString &new_styl
}
}
-void FirstRunDialog::on_currCustom1LineEdit_editingFinished()
-{
- Settings::write(Settings::UserData::Custom1CurrencyName, ui->currCustom1LineEdit->text());
-}
-
-void FirstRunDialog::on_currCustom2LineEdit_editingFinished()
-{
- Settings::write(Settings::UserData::Custom2CurrencyName, ui->currCustom2LineEdit->text());
-}
-
void FirstRunDialog::on_importPushButton_clicked()
{
QString filename = QDir::toNativeSeparators(QFileDialog::getOpenFileName(
diff --git a/src/gui/dialogues/firstrundialog.h b/src/gui/dialogues/firstrundialog.h
index 9e116aed..d801581e 100644
--- a/src/gui/dialogues/firstrundialog.h
+++ b/src/gui/dialogues/firstrundialog.h
@@ -18,6 +18,7 @@
#ifndef FIRSTRUNDIALOG_H
#define FIRSTRUNDIALOG_H
+#include "src/database/currencyentry.h"
#include
#include
#include
@@ -85,8 +86,6 @@ private slots:
void on_previousPushButton_clicked();
void on_nextPushButton_clicked();
void on_styleComboBox_currentTextChanged(const QString &new_style_setting);
- void on_currCustom1LineEdit_editingFinished();
- void on_currCustom2LineEdit_editingFinished();
/*!
* \brief Import an existing database instead of creating a new one
@@ -97,6 +96,14 @@ private slots:
Ui::FirstRunDialog *ui;
bool useRessourceData;
+ //TODO load from settings
+ OPL::DateTimeFormat m_format = OPL::DateTimeFormat(
+ OPL::DateTimeFormat::DateFormat::Default,
+ QStringLiteral("yyyy-MM-dd"),
+ OPL::DateTimeFormat::TimeFormat::Default,
+ QStringLiteral("hh:mm")
+ );
+
/*!
* \brief finishSetup - once all the necessary data is entered by the user, this functions executes the steps necessary
* to collect the data, process it and create the database
diff --git a/src/gui/dialogues/firstrundialog.ui b/src/gui/dialogues/firstrundialog.ui
index b6efa358..16fd0b36 100644
--- a/src/gui/dialogues/firstrundialog.ui
+++ b/src/gui/dialogues/firstrundialog.ui
@@ -175,7 +175,7 @@
-
- <html><head/><body><p align="center"><span style=" font-size:20pt;">Welcome to openPilotLog!</span></p><p align="center"><span style=" font-size:14pt;">The Free and Open Source Logbook application</span></p><p><br/></p><p>If you would like to keep track of your license and/or medical expiration dates, you can enter them here. By default, only Take-Off and Landing currency is shown on the home page, but any other currency can also be shown as well. This can be enabled in the settings menu.</p></body></html>
+ <html><head/><body><p align="center"><span style=" font-size:20pt;">Welcome to openPilotLog!</span></p><p align="center"><span style=" font-size:14pt;">The Free and Open Source Logbook application</span></p><p><br/></p><p>If you would like to keep track of your license and/or medical expiration dates, you can enter them here. Your currencies are tracked and you will be warned about impending expiries. These warnings can be disabled in the Settings Menu.</p></body></html>
Qt::RichText
diff --git a/src/gui/dialogues/newairportdialog.cpp b/src/gui/dialogues/newairportdialog.cpp
index b10ac495..fdf60470 100644
--- a/src/gui/dialogues/newairportdialog.cpp
+++ b/src/gui/dialogues/newairportdialog.cpp
@@ -8,19 +8,18 @@
#include "src/database/row.h"
NewAirportDialog::NewAirportDialog(QWidget *parent) :
- QDialog(parent), ui(new Ui::NewAirportDialog)
+ EntryEditDialog(parent), ui(new Ui::NewAirportDialog)
{
- rowId = 0; // new entry
+ m_rowId = 0; // new entry
ui->setupUi(this);
setValidators();
loadTimeZones();
}
NewAirportDialog::NewAirportDialog(int row_id, QWidget *parent)
- : QDialog(parent), ui(new Ui::NewAirportDialog), rowId(row_id)
+ : EntryEditDialog(parent), ui(new Ui::NewAirportDialog), m_rowId(row_id)
{
ui->setupUi(this);
- this->setWindowTitle(tr("Edit Airport"));
setValidators();
loadTimeZones();
loadAirportData(row_id);
@@ -47,8 +46,8 @@ void NewAirportDialog::loadTimeZones()
void NewAirportDialog::loadAirportData(int row_id)
{
+ this->setWindowTitle(tr("Edit Airport"));
const auto airport_data = DB->getAirportEntry(row_id).getData();
- //const auto airport_data = airport.getData();
DEB << "Filling Airport Data: " << airport_data;
ui->nameLineEdit->setText(airport_data.value(OPL::AirportEntry::NAME).toString());
@@ -118,7 +117,7 @@ void NewAirportDialog::on_buttonBox_accepted()
{OPL::AirportEntry::COUNTRY, ui->countryLineEdit->text()},
};
- OPL::AirportEntry entry(rowId, airport_data);
+ OPL::AirportEntry entry(m_rowId, airport_data);
if(DB->commit(entry))
QDialog::accept();
else {
@@ -142,3 +141,16 @@ void NewAirportDialog::on_buttonBox_rejected()
QDialog::reject();
}
+// EntryEditDialog interface
+void NewAirportDialog::loadEntry(int rowId)
+{
+ m_rowId = rowId;
+ loadAirportData(rowId);
+}
+
+bool NewAirportDialog::deleteEntry(int rowId)
+{
+ auto entry = DB->getAirportEntry(rowId);
+ return DB->remove(entry);
+}
+
diff --git a/src/gui/dialogues/newairportdialog.h b/src/gui/dialogues/newairportdialog.h
index 8387be3d..e1c2a817 100644
--- a/src/gui/dialogues/newairportdialog.h
+++ b/src/gui/dialogues/newairportdialog.h
@@ -1,13 +1,13 @@
#ifndef NEWAIRPORTDIALOG_H
#define NEWAIRPORTDIALOG_H
-#include
+#include "src/gui/dialogues/entryeditdialog.h"
namespace Ui {
class NewAirportDialog;
}
-class NewAirportDialog : public QDialog
+class NewAirportDialog : public EntryEditDialog
{
Q_OBJECT
@@ -17,6 +17,7 @@ class NewAirportDialog : public QDialog
~NewAirportDialog();
+
private slots:
void on_buttonBox_accepted();
@@ -28,12 +29,19 @@ private slots:
private:
Ui::NewAirportDialog *ui;
+ int m_rowId;
+
void setValidators();
void loadTimeZones();
bool confirmTimezone();
void loadAirportData(int row_id);
bool verifyInput();
- int rowId;
+
+
+ // EntryEditDialog interface
+public:
+ virtual void loadEntry(int rowId) override;
+ virtual bool deleteEntry(int rowId) override;
};
#endif // NEWAIRPORTDIALOG_H
diff --git a/src/gui/dialogues/newflightdialog.cpp b/src/gui/dialogues/newflightdialog.cpp
index b0b14295..d79ecc5c 100644
--- a/src/gui/dialogues/newflightdialog.cpp
+++ b/src/gui/dialogues/newflightdialog.cpp
@@ -16,9 +16,11 @@
*along with this program. If not, see .
*/
#include "newflightdialog.h"
+#include "QtWidgets/qcalendarwidget.h"
#include "src/classes/time.h"
#include "src/database/database.h"
#include "src/database/databasecache.h"
+#include "src/gui/dialogues/newairportdialog.h"
#include "src/gui/verification/airportinput.h"
#include "src/gui/verification/completerprovider.h"
#include "src/gui/verification/pilotinput.h"
@@ -28,6 +30,7 @@
#include "src/opl.h"
#include "src/functions/datetime.h"
#include "src/classes/settings.h"
+#include "src/classes/date.h"
#include "src/functions/calc.h"
#include "src/gui/dialogues/newtaildialog.h"
#include "src/gui/dialogues/newpilotdialog.h"
@@ -37,28 +40,18 @@
NewFlightDialog::NewFlightDialog(QWidget *parent)
- : QDialog(parent),
+ : EntryEditDialog(parent),
ui(new Ui::NewFlightDialog)
{
init();
- // Set up UI (New Flight)
- LOG << Settings::read(Settings::FlightLogging::Function);
- if(Settings::read(Settings::FlightLogging::Function).toInt() == static_cast(OPL::PilotFunction::PIC)){
- ui->picNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(0);
- emit ui->picNameLineEdit->editingFinished();
- }
- if (Settings::read(Settings::FlightLogging::Function).toInt() == static_cast(OPL::PilotFunction::SIC)) {
- ui->sicNameLineEdit->setText(self);
- ui->functionComboBox->setCurrentIndex(2);
- emit ui->sicNameLineEdit->editingFinished();
- }
- ui->doftLineEdit->setText(OPL::DateTime::currentDate());
- emit ui->doftLineEdit->editingFinished();
+ setPilotFunction();
+
+ ui->doftLineEdit->setText(OPL::Date::today(m_format).toString());
+// emit ui->doftLineEdit->editingFinished();
}
NewFlightDialog::NewFlightDialog(int row_id, QWidget *parent)
- : QDialog(parent),
+ : EntryEditDialog(parent),
ui(new Ui::NewFlightDialog)
{
init();
@@ -71,6 +64,20 @@ NewFlightDialog::~NewFlightDialog()
delete ui;
}
+void NewFlightDialog::setPilotFunction()
+{
+ const QString &self = DBCache->getPilotNamesMap().value(1);
+ if(Settings::getPilotFunction() == OPL::PilotFunction::PIC){
+ ui->picNameLineEdit->setText(self);
+ ui->functionComboBox->setCurrentIndex(0);
+ }
+ if (Settings::getPilotFunction() == OPL::PilotFunction::SIC) {
+ ui->sicNameLineEdit->setText(self);
+ ui->functionComboBox->setCurrentIndex(2);
+ }
+ ui->pilotFlyingCheckBox->setCheckState(Qt::Checked);
+}
+
void NewFlightDialog::init()
{
// Setup UI
@@ -94,6 +101,11 @@ void NewFlightDialog::init()
OPL::GLOBALS->loadApproachTypes(ui->approachComboBox);
OPL::GLOBALS->loadPilotFunctios(ui->functionComboBox);
+ // allocate a widget for date selection
+ calendar = new QCalendarWidget(this);
+ calendar->setVisible(false);
+ calendar->setWindowFlags(Qt::Dialog); // pop-up calendar
+
setupRawInputValidation();
setupSignalsAndSlots();
readSettings();
@@ -140,6 +152,9 @@ void NewFlightDialog::setupSignalsAndSlots()
for (const auto& line_edit : *pilotNameLineEdits)
QObject::connect(line_edit, &QLineEdit::editingFinished,
this, &NewFlightDialog::onPilotNameLineEdit_editingFinshed);
+
+ QObject::connect(calendar, &QCalendarWidget::selectionChanged,
+ this, &NewFlightDialog::calendarDateSelected);
}
/*!
@@ -167,10 +182,12 @@ bool NewFlightDialog::eventFilter(QObject *object, QEvent *event)
*/
void NewFlightDialog::readSettings()
{
- ui->functionComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Function).toInt());
- ui->approachComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Approach).toInt());
- ui->flightRulesComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::LogIFR).toInt());
- ui->flightNumberLineEdit->setText(Settings::read(Settings::FlightLogging::FlightNumberPrefix).toString());
+ ui->functionComboBox->setCurrentIndex(static_cast(Settings::getPilotFunction()));
+ ui->approachComboBox->setCurrentText(Settings::getApproachType());
+ ui->flightRulesComboBox->setCurrentIndex(Settings::getLogIfr());
+ ui->flightNumberLineEdit->setText(Settings::getFlightNumberPrefix());
+
+ m_format = Settings::getDisplayFormat();
}
/*!
@@ -181,55 +198,54 @@ void NewFlightDialog::fillWithEntryData()
{
DEB << "Restoring Flight: ";
DEB << flightEntry;
+ using namespace OPL;
const auto &flight_data = flightEntry.getData();
// Date of Flight
- ui->doftLineEdit->setText(flight_data.value(OPL::FlightEntry::DOFT).toString());
+ const QDate date = QDate::fromJulianDay(flight_data.value(FlightEntry::DOFT).toInt());
+ calendar->setSelectedDate(date);
+ ui->doftLineEdit->setText(Date(date, m_format).toString());
+
// Location
ui->deptLocationLineEdit->setText(flight_data.value(OPL::FlightEntry::DEPT).toString());
ui->destLocationLineEdit->setText(flight_data.value(OPL::FlightEntry::DEST).toString());
// Times
- ui->tofbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TOFB).toInt()).toString());
- ui->tonbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TONB).toInt()).toString());
+ ui->tofbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TOFB).toInt(), m_format).toString());
+ ui->tonbTimeLineEdit->setText(OPL::Time(flight_data.value(OPL::FlightEntry::TONB).toInt(), m_format).toString());
ui->acftLineEdit->setText(DBCache->getTailsMap().value(flight_data.value(OPL::FlightEntry::ACFT).toInt()));
ui->picNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::PIC).toInt()));
ui->sicNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::SECONDPILOT).toInt()));
ui->thirdPilotNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::FlightEntry::THIRDPILOT).toInt()));
//Function
- const QHash functions = {
- {0, OPL::FlightEntry::TPIC},
- {1, OPL::FlightEntry::TPICUS},
- {2, OPL::FlightEntry::TSIC},
- {3, OPL::FlightEntry::TDUAL},
- {4, OPL::FlightEntry::TFI},
- };
for (int i = 0; i < 5; i++) { // QHash::iterator not guarenteed to be in ordetr
- if(flight_data.value(functions.value(i)).toInt() != 0)
+ if(flight_data.value(pilotFuncionsMap.value(i)).toInt() != 0)
ui->functionComboBox->setCurrentIndex(i);
}
// Approach ComboBox
- const QString& app = flight_data.value(OPL::FlightEntry::APPROACHTYPE).toString();
- if(app != QString()){
+ const QString app = flight_data.value(OPL::FlightEntry::APPROACHTYPE).toString();
+ if(app != QString()) {
ui->approachComboBox->setCurrentText(app);
}
- // Flight Rules
+ // Flight Rules, check if tIFR > 0
bool time_ifr = flight_data.value(OPL::FlightEntry::TIFR).toBool();
- int rulesIndex = time_ifr ? 1 : 0;
- ui->flightRulesComboBox->setCurrentIndex(rulesIndex);
+ ui->flightRulesComboBox->setCurrentIndex(time_ifr);
+
// Take-Off and Landing
- int takeOffCount = flight_data.value(OPL::FlightEntry::TODAY).toInt()
+ int takeOffCount = flight_data.value(OPL::FlightEntry::TODAY).toInt()
+ flight_data.value(OPL::FlightEntry::TONIGHT).toInt();
int landingCount = flight_data.value(OPL::FlightEntry::LDGDAY).toInt()
+ flight_data.value(OPL::FlightEntry::LDGNIGHT).toInt();
ui->takeOffSpinBox->setValue(takeOffCount);
ui->landingSpinBox->setValue(landingCount);
- // Remarks
+ ui->pilotFlyingCheckBox->setChecked(flight_data.value(OPL::FlightEntry::PILOTFLYING).toBool());
+
+ // Remarks and Flight Number
ui->remarksLineEdit->setText(flight_data.value(OPL::FlightEntry::REMARKS).toString());
- // Flight Number
ui->flightNumberLineEdit->setText(flight_data.value(OPL::FlightEntry::FLIGHTNUMBER).toString());
+ // re-trigger input verification
for(const auto &line_edit : *mandatoryLineEdits)
emit line_edit->editingFinished();
}
@@ -262,7 +278,10 @@ void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
validationState.validate(mandatoryLineEdits->indexOf(line_edit));
if (validationState.timesValid()) {
- updateBlockTimeLabel();
+ const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text(), m_format);
+ const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
+ const OPL::Time tblk = OPL::Time::blockTime(tofb, tonb);
+ ui->tblkDisplayLabel->setText(tblk.toString());
}
}
@@ -278,81 +297,90 @@ void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
validationState.printValidationStatus();
}
-void NewFlightDialog::updateBlockTimeLabel()
+bool NewFlightDialog::addNewDatabaseElement(QLineEdit *parent, OPL::DbTable table)
{
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
- const OPL::Time tblk = OPL::Time::blockTime(tofb, tonb);
-
- ui->tblkDisplayLabel->setText(tblk.toString());
-}
+ QDialog *dialog = nullptr;
+ if(userWantsToAddNewEntry(table)) {
+ switch (table) {
+ case OPL::DbTable::Pilots:
+ dialog = new NewPilotDialog(parent->text(), this);
+ break;
+ case OPL::DbTable::Tails:
+ dialog = new NewTailDialog(ui->acftLineEdit->text(), this);
+ break;
+ case OPL::DbTable::Airports:
+ dialog = new NewAirportDialog(this);
+ break;
+ default:
+ return false;
+ break;
+ }
+ } else
+ return false;
-/*!
- * \brief NewFlightDialog::addNewTail If the user input is not in the aircraftList, the user
- * is prompted if he wants to add a new entry to the database
- */
-bool NewFlightDialog::addNewTail(QLineEdit& parent_line_edit)
-{
- QMessageBox::StandardButton reply;
- reply = QMessageBox::question(this, tr("No Aircraft found"),
- tr("No aircraft with this registration found.
"
- "If this is the first time you log a flight with this aircraft, "
- "you have to add the registration to the database first."
- "
Would you like to add a new aircraft to the database?"),
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes) {
- // create and open new aircraft dialog
- NewTailDialog nt(ui->acftLineEdit->text(), this);
- int ret = nt.exec();
- // update map and list, set line edit
- if (ret == QDialog::Accepted) {
- DEB << "New Tail Entry added:";
- DEB << DB->getTailEntry(DB->getLastEntry(OPL::DbTable::Tails));
-
- // update Line Edit with newly added tail
- parent_line_edit.setText(DBCache->getTailsMap().value(DB->getLastEntry(OPL::DbTable::Tails)));
- emit parent_line_edit.editingFinished();
- return true;
- } else {
+ // execute the dialog and check for success. Set the line edit to the newly created entry.
+ if(dialog->exec() == QDialog::Accepted) {
+ delete dialog;
+ int latestEntry = DB->getLastEntry(table);
+ switch (table) {
+ case OPL::DbTable::Pilots:
+ parent->setText(DBCache->getPilotNamesMap().value(latestEntry));
+ break;
+ case OPL::DbTable::Tails:
+ parent->setText(DBCache->getTailsMap().value(latestEntry));
+ break;
+ case OPL::DbTable::Airports:
+ parent->setText(DBCache->getAirportsMapICAO().value(latestEntry));
+ break;
+ default:
return false;
+ break;
}
} else {
+ delete dialog;
return false;
}
+
+ // re-emit editing finished to trigger input validation
+ emit parent->editingFinished();
+ return true;
}
-/*!
- * \brief NewFlightDialog::addNewPilot If the user input is not in the pilotNameList, the user
- * is prompted if he wants to add a new entry to the database
- */
-bool NewFlightDialog::addNewPilot(QLineEdit& parent_line_edit)
+bool NewFlightDialog::userWantsToAddNewEntry(OPL::DbTable table)
{
QMessageBox::StandardButton reply;
- reply = QMessageBox::question(this, tr("No Pilot found"),
- tr("No pilot found.
Please enter the Name as"
- "
Lastname, Firstname
"
- "If this is the first time you log a flight with this pilot, "
- "you have to add the pilot to the database first."
- "
Would you like to add a new pilot to the database?"),
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes) {
- // create and open new pilot dialog
- NewPilotDialog np(this);
- int ret = np.exec();
- // update map and list, set line edit
- if (ret == QDialog::Accepted) {
- DEB << "New Pilot Entry added:";
- DEB << DB->getPilotEntry(DB->getLastEntry(OPL::DbTable::Pilots));
-
- // update Line Edit with newly added pilot
- parent_line_edit.setText(DBCache->getPilotNamesMap().value(DB->getLastEntry(OPL::DbTable::Pilots)));
- emit parent_line_edit.editingFinished();
- return true;
- } else {
- return false;
- }
- } else
- return false;
+ switch (table) {
+ case OPL::DbTable::Pilots:
+ reply = QMessageBox::question(this, tr("No Pilot found"),
+ tr("No pilot found.
Please enter the Name as"
+ "
Lastname, Firstname
"
+ "If this is the first time you log a flight with this pilot, "
+ "you have to add the pilot to the database first."
+ "
Would you like to add a new pilot to the database?"),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton::Yes);
+ break;
+ case OPL::DbTable::Tails:
+ reply = QMessageBox::question(this, tr("No Aircraft found"),
+ tr("No aircraft with this registration found.
"
+ "If this is the first time you log a flight with this aircraft, "
+ "you have to add the registration to the database first."
+ "
Would you like to add a new aircraft to the database?"),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton::Yes);
+ break;
+ case OPL::DbTable::Airports:
+ reply = QMessageBox::question(this, tr("No Airport found"),
+ tr("No Airport with this identifier found.
"
+ "If this is the first time you log a flight to this airport, "
+ "you have to add the airport to the database first."
+ "
Would you like to add a new airport to the database?"),
+ QMessageBox::Yes|QMessageBox::No, QMessageBox::StandardButton::Yes);
+ break;
+ default:
+ reply = QMessageBox::No;
+ break;
+ }
+
+ return reply == QMessageBox::Yes;
}
/*!
@@ -369,15 +397,15 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
OPL::RowData_T new_data;
// Calculate Block and Night Time
- const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
- const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
+ const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text(), m_format);
+ const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
- QDateTime departure_date_time = OPL::DateTime::fromString(ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
+ const QDateTime departure_date_time = OPL::DateTime::fromString(ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
const auto night_time_data = OPL::Calc::NightTimeValues(ui->deptLocationLineEdit->text(), ui->destLocationLineEdit->text(),
- departure_date_time, block_minutes, Settings::read(Settings::FlightLogging::NightAngle).toInt());
+ departure_date_time, block_minutes, Settings::getNightAngle());
// Mandatory data
- new_data.insert(OPL::FlightEntry::DOFT, ui->doftLineEdit->text());
+ new_data.insert(OPL::FlightEntry::DOFT, QDate::fromString(ui->doftLineEdit->text(), Qt::ISODate).toJulianDay());
new_data.insert(OPL::FlightEntry::DEPT, ui->deptLocationLineEdit->text());
new_data.insert(OPL::FlightEntry::TOFB, tofb.toMinutes());
new_data.insert(OPL::FlightEntry::DEST, ui->destLocationLineEdit->text());
@@ -461,7 +489,7 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
new_data.insert(OPL::FlightEntry::AUTOLAND, ui->landingSpinBox->value());
// Pilot flying / Pilot monitoring
- bool isPilotFlying = toDay + toNight + ldgDay + ldgNight > 0;
+ bool isPilotFlying = toDay + toNight + ldgDay + ldgNight;
new_data.insert(OPL::FlightEntry::PILOTFLYING, isPilotFlying);
// Additional Data
@@ -485,15 +513,28 @@ void NewFlightDialog::toUpper(const QString &text)
void NewFlightDialog::onTimeLineEdit_editingFinished()
{
- auto line_edit = this->findChild(sender()->objectName());
- verifyUserInput(line_edit, TimeInput(line_edit->text()));
+ const auto line_edit = this->findChild(sender()->objectName());
+
+ if(!verifyUserInput(line_edit, TimeInput(line_edit->text(), m_format))) {
+ onBadInputReceived(line_edit);
+ }
}
void NewFlightDialog::onPilotNameLineEdit_editingFinshed()
{
auto line_edit = this->findChild(sender()->objectName());
+ if(line_edit->text() == QString())
+ return;
+
+ // create a copy to refill line edit and pass through to creation dialog if verification fails
+ QString userInput = line_edit->text();
+
if(!verifyUserInput(line_edit, PilotInput(line_edit->text()))) {
- if(!addNewPilot(*line_edit))
+ {
+ QSignalBlocker blocker(line_edit);
+ line_edit->setText(userInput);
+ }
+ if(!addNewDatabaseElement(line_edit, OPL::DbTable::Pilots))
onBadInputReceived(line_edit);
}
}
@@ -514,17 +555,31 @@ void NewFlightDialog::onLocationLineEdit_editingFinished()
name_label->setText(DBCache->getAirportsMapNames().value(
DBCache->getAirportsMapICAO().key(
line_edit->text())));
- } else
+ } else {
name_label->setText("Unknown Airport");
+ addNewDatabaseElement(line_edit, OPL::DbTable::Airports);
+ }
}
void NewFlightDialog::on_acftLineEdit_editingFinished()
{
const auto line_edit = ui->acftLineEdit;
+ if(line_edit->text().isEmpty()){
+ return;
+ }
+
+ const QString user_input = line_edit->text(); // keep around for adding new tail if needed
- if(!verifyUserInput(line_edit, TailInput(line_edit->text())))
- if(!addNewTail(*line_edit))
+ if(!verifyUserInput(line_edit, TailInput(line_edit->text()))) {
+ // re-populate user input to hand through to NewTailDialog
+ {
+ QSignalBlocker blocker(line_edit);
+ line_edit->setText(user_input);
+ }
+ if(!addNewDatabaseElement(line_edit, OPL::DbTable::Tails)) {
onBadInputReceived(line_edit);
+ }
+ }
const auto space = QLatin1Char(' ');
if(line_edit->text().contains(space))
@@ -534,21 +589,19 @@ void NewFlightDialog::on_acftLineEdit_editingFinished()
void NewFlightDialog::on_doftLineEdit_editingFinished()
{
const auto line_edit = ui->doftLineEdit;
- auto text = ui->doftLineEdit->text();
- auto label = ui->doftDisplayLabel;
-
- TODO << "Non-default Date formats not implemented yet.";
- OPL::DateFormat date_format = OPL::DateFormat::ISODate;
- auto date = OPL::DateTime::parseInput(text, date_format);
- if (date.isValid()) {
- label->setText(date.toString(Qt::TextDate));
- line_edit->setText(OPL::DateTime::dateToString(date, date_format));
- onGoodInputReceived(line_edit);
+ OPL::Date date(ui->doftLineEdit->text(), m_format);
+
+
+ LOG << "Date: " << date.toString();
+ LOG << "is valid? " << date.isValid();
+
+ line_edit->setText(date.toString());
+ if(ui->doftLineEdit->text().isEmpty()) {
+ onBadInputReceived(line_edit);
return;
}
- label->setText(tr("Invalid Date."));
- onBadInputReceived(line_edit);
+ onGoodInputReceived(line_edit);
}
void NewFlightDialog::on_pilotFlyingCheckBox_stateChanged(int arg1)
@@ -577,18 +630,45 @@ void NewFlightDialog::on_approachComboBox_currentTextChanged(const QString &arg1
*/
void NewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
{
- if (index == static_cast(OPL::PilotFunction::PIC)) {
+ int picPilotId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
+ int sicPilotId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
+ int thirdPilotId = DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text());
+ const QString &self = DBCache->getPilotNamesMap().value(1);
+
+ switch (index) {
+ case static_cast(OPL::PilotFunction::PIC):
+ DEB << "PIC selected...";
ui->picNameLineEdit->setText(self);
emit ui->picNameLineEdit->editingFinished();
- if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
- == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
- ui->sicNameLineEdit->setText(QString());
- } else if (index == static_cast(OPL::PilotFunction::SIC)) {
+ picPilotId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
+
+ if (picPilotId == sicPilotId) {
+ ui->sicNameLineEdit->setText(QString());
+ onBadInputReceived(ui->sicNameLineEdit);
+ }
+ if (picPilotId == thirdPilotId) {
+ ui->thirdPilotNameLineEdit->setText(QString());
+ onBadInputReceived(ui->thirdPilotNameLineEdit);
+ }
+ break;
+ case static_cast(OPL::PilotFunction::SIC):
+ DEB << "SIC selected...";
ui->sicNameLineEdit->setText(self);
emit ui->sicNameLineEdit->editingFinished();
- if (DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text())
- == DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()))
+ sicPilotId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
+
+ if (sicPilotId == picPilotId) {
ui->picNameLineEdit->setText(QString());
+ onBadInputReceived(ui->picNameLineEdit);
+ }
+ if (sicPilotId == thirdPilotId) {
+ ui->thirdPilotNameLineEdit->setText(QString());
+ onBadInputReceived(ui->thirdPilotNameLineEdit);
+ }
+ break;
+ default:
+ break;
+
}
}
@@ -601,7 +681,7 @@ void NewFlightDialog::on_functionComboBox_currentIndexChanged(int index)
* \param error_msg - the error string displayed to the user
* \return
*/
-bool NewFlightDialog::checkPilotFunctionsValid()
+bool NewFlightDialog::pilotFunctionsInvalid()
{
int pic_id = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
int function_index = ui->functionComboBox->currentIndex();
@@ -610,17 +690,52 @@ bool NewFlightDialog::checkPilotFunctionsValid()
if (!(function_index == static_cast(OPL::PilotFunction::PIC) || function_index == static_cast(OPL::PilotFunction::FI))) {
INFO(tr("The PIC is set to %1 but the Pilot Function is set to %2")
.arg(ui->picNameLineEdit->text(), ui->functionComboBox->currentText()));
- return false;
+ return true;
}
} else {
if (function_index == static_cast(OPL::PilotFunction::PIC) || function_index == static_cast(OPL::PilotFunction::FI)) {
INFO(tr("The Pilot Function is set to %1, but the PIC is set to %2")
.arg(ui->functionComboBox->currentText(), ui->picNameLineEdit->text()));
- return false;
+ return true;
}
}
- return true;
+ return false;
+}
+
+bool NewFlightDialog::duplicateNamesPresent()
+{
+ const int picId = DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text());
+ const int sicId = DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text());
+ const int thirdPilotId = DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text());
+
+ // this is a bit explicit but better point out to the user what the case is
+ if (picId == sicId) {
+ INFO(tr("PIC and SIC names are the same."));
+ return true;
+ }
+ if (picId == thirdPilotId && picId > 0) {
+ INFO(tr("PIC and third Pilot names are the same."));
+ return true;
+ }
+ if (sicId == thirdPilotId && sicId > 0) {
+ INFO(tr("SIC and third Pilot names are the same."));
+ return true;
+ }
+
+ return false;
+}
+
+bool NewFlightDialog::flightTimeIsZero()
+{
+ const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text(), m_format);
+ const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text(), m_format);
+ const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
+ if(block_minutes == 0) {
+ INFO(tr("Total time of flight is zero."));
+ return true;
+ }
+ return false;
}
/*!
@@ -638,17 +753,12 @@ void NewFlightDialog::on_buttonBox_accepted()
emit le->editingFinished();
// If input verification is passed, continue, otherwise prompt user to correct
if (!validationState.allValid()) {
- const auto display_names = QHash {
- {ValidationState::ValidationItem::doft, QObject::tr("Date of Flight")}, {ValidationState::ValidationItem::dept, QObject::tr("Departure Airport")},
- {ValidationState::ValidationItem::dest, QObject::tr("Destination Airport")}, {ValidationState::ValidationItem::tofb, QObject::tr("Time Off Blocks")},
- {ValidationState::ValidationItem::tonb, QObject::tr("Time on Blocks")}, {ValidationState::ValidationItem::pic, QObject::tr("PIC Name")},
- {ValidationState::ValidationItem::acft, QObject::tr("Aircraft Registration")}
- };
+
QString missing_items;
for (int i=0; i < mandatoryLineEdits->size(); i++) {
if (!validationState.validAt(i)){
- missing_items.append(display_names.value(static_cast(i)) + "
");
- mandatoryLineEdits->at(i)->setStyleSheet(QStringLiteral("border: 1px solid red"));
+ missing_items.append(validationItemsDisplayNames.value(static_cast(i)) + "
");
+ mandatoryLineEdits->at(i)->setStyleSheet(OPL::CssStyles::RED_BORDER);
}
}
@@ -660,7 +770,11 @@ void NewFlightDialog::on_buttonBox_accepted()
return;
}
- if(!checkPilotFunctionsValid())
+ if(pilotFunctionsInvalid())
+ return;
+ if(duplicateNamesPresent())
+ return;
+ if(flightTimeIsZero())
return;
// If input verification passed, collect input and submit to database
@@ -682,3 +796,30 @@ void NewFlightDialog::on_buttonBox_accepted()
}
}
+
+void NewFlightDialog::on_calendarPushButton_clicked()
+{
+ calendar->setVisible(true);
+}
+
+void NewFlightDialog::calendarDateSelected()
+{
+ calendar->setVisible(false);
+ ui->doftLineEdit->setText(OPL::Date(calendar->selectedDate(), m_format).toString());
+ emit ui->doftLineEdit->editingFinished();
+}
+
+// EntryEditDialog interface
+
+void NewFlightDialog::loadEntry(int rowID)
+{
+ flightEntry = DB->getFlightEntry(rowID);
+ fillWithEntryData();
+}
+
+bool NewFlightDialog::deleteEntry(int rowID)
+{
+ const auto entry = DB->getFlightEntry(rowID);
+ return DB->remove(entry);
+}
+
diff --git a/src/gui/dialogues/newflightdialog.h b/src/gui/dialogues/newflightdialog.h
index eaf2717e..899d5615 100644
--- a/src/gui/dialogues/newflightdialog.h
+++ b/src/gui/dialogues/newflightdialog.h
@@ -24,10 +24,14 @@
#include
#include
+#include "QtWidgets/qcalendarwidget.h"
+#include "src/database/database.h"
#include "src/database/flightentry.h"
+#include "src/gui/dialogues/entryeditdialog.h"
#include "src/gui/verification/userinput.h"
#include "src/opl.h"
#include "src/gui/verification/validationstate.h"
+#include "src/classes/date.h"
namespace Ui {
class NewFlightDialog;
@@ -57,7 +61,7 @@ class NewFlightDialog;
* Once the user is satisfied with his entries, a final set of input verification is triggered and the entry is submitted to the database,
* see on_buttonBox_accepted() and Database::commit()
*/
-class NewFlightDialog : public QDialog
+class NewFlightDialog : public EntryEditDialog
{
Q_OBJECT
@@ -74,9 +78,13 @@ class NewFlightDialog : public QDialog
explicit NewFlightDialog(int row_id, QWidget* parent = nullptr);
~NewFlightDialog();
+
+
private:
Ui::NewFlightDialog *ui;
ValidationState validationState;
+ QCalendarWidget *calendar;
+ OPL::DateTimeFormat m_format;
/*!
* \brief a AFlightEntry object that is used to store either position data
@@ -88,23 +96,47 @@ class NewFlightDialog : public QDialog
/*!
* \brief timeLineEdits - Line Edits for time Off Blocks and Time On Blocks
*/
- static const inline QList* timeLineEdits;
+ static const inline QList *timeLineEdits;
/*!
* \brief locationLineEdits - Line Edits for Departure and Destination Airports
*/
- static const inline QList* locationLineEdits;
+ static const inline QList *locationLineEdits;
/*!
* \brief pilotNameLineEdits - Line Edits for Pilot in Command, Second in Command (Co-Pilot) and Third Pilot
*/
- static const inline QList* pilotNameLineEdits;
+ static const inline QList *pilotNameLineEdits;
/*!
* \brief mandatoryLineEdits - Contains the Line Edits that are needed for logging a complete flight from A to B.
* The list is ordered like the ValidationItem enum so that indexed access is possible using the enum.
*/
- static const inline QList* mandatoryLineEdits;
- static const inline QLatin1String self = QLatin1String("self");
+ static const inline QList *mandatoryLineEdits;
+ // static const inline QLatin1String self = QLatin1String("self");
+ static const inline QHash pilotFuncionsMap = {
+ {0, OPL::FlightEntry::TPIC},
+ {1, OPL::FlightEntry::TPICUS},
+ {2, OPL::FlightEntry::TSIC},
+ {3, OPL::FlightEntry::TDUAL},
+ {4, OPL::FlightEntry::TFI},
+ };
+ static const inline QHash validationItemsDisplayNames = {
+ {ValidationState::ValidationItem::doft, QObject::tr("Date of Flight")},
+ {ValidationState::ValidationItem::dept, QObject::tr("Departure Airport")},
+ {ValidationState::ValidationItem::dest, QObject::tr("Destination Airport")},
+ {ValidationState::ValidationItem::tofb, QObject::tr("Time Off Blocks")},
+ {ValidationState::ValidationItem::tonb, QObject::tr("Time on Blocks")},
+ {ValidationState::ValidationItem::pic, QObject::tr("PIC Name")},
+ {ValidationState::ValidationItem::acft, QObject::tr("Aircraft Registration")},
+ };
+ /*!
+ * \brief init - set up the UI
+ */
void init();
+ /*!
+ * \brief setPilotFunction - Reads the application setting and pre-fills the logbook owners
+ * desired function
+ */
+ void setPilotFunction();
void setupRawInputValidation();
void setupSignalsAndSlots();
void readSettings();
@@ -124,14 +156,30 @@ class NewFlightDialog : public QDialog
*/
void onBadInputReceived(QLineEdit *line_edit);
- void updateBlockTimeLabel();
- void setNightCheckboxes();
+ /*!
+ * \brief addNewDatabaseElement Adds a new element to the database
+ * \param parent - The line edit that triggered the event
+ * \param table - The table to which the new element is added
+ * \return true on success
+ * \details The flights database has a couple of NOT NULL constraints which
+ * must be met before a new flight can be submitted. If the user enters a
+ * constrained field which does not exist in a related table (pilots, tails
+ * or airports), the user is prompted to add a new entry to one of those
+ * tables before proceeding to log a flight with the missing element.
+ */
+ bool addNewDatabaseElement(QLineEdit* parent, OPL::DbTable table);
- bool addNewTail(QLineEdit& parent_line_edit);
- bool addNewPilot(QLineEdit& parent_line_edit);
+ /*!
+ * \brief userWantsToAddNewEntry - Asks the user if he wants to add a new entry to the database
+ * \param table - The table to which the entry will be committed.
+ * \return true if the reply is QMessageBox::Yes
+ */
+ bool userWantsToAddNewEntry(OPL::DbTable table);
- bool checkPilotFunctionsValid();
+ bool pilotFunctionsInvalid();
+ bool duplicateNamesPresent();
+ bool flightTimeIsZero();
OPL::RowData_T prepareFlightEntryData();
const static inline auto CAT_3 = QLatin1String(OPL::GLOBALS->getApproachTypes()[3].toLatin1());
@@ -148,8 +196,17 @@ private slots:
void on_approachComboBox_currentTextChanged(const QString &arg1);
void on_functionComboBox_currentIndexChanged(int index);
+ void on_calendarPushButton_clicked();
+
+ void calendarDateSelected();
+
protected:
bool eventFilter(QObject* object, QEvent* event) override;
+
+ // EntryEditDialog interface
+public:
+ virtual void loadEntry(int rowID) override;
+ virtual bool deleteEntry(int rowID) override;
};
diff --git a/src/gui/dialogues/newflightdialog.ui b/src/gui/dialogues/newflightdialog.ui
index 2ec380fa..dd911b16 100644
--- a/src/gui/dialogues/newflightdialog.ui
+++ b/src/gui/dialogues/newflightdialog.ui
@@ -6,48 +6,67 @@
0
0
- 767
- 362
+ 799
+ 391
Add New Flight
- -
-
+
-
+
+
+ false
+
- 160
+ 200
0
- 120
+ 200
16777215
+
+
+ true
+
+
+
+
+
- -
-
-
-
- 160
- 0
-
+
-
+
+
+ Function
-
-
- 120
- 16777215
-
+
+
+ -
+
+
+ Off Blocks
- -
-
+
-
+
+
+ PIC
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
160
@@ -62,42 +81,35 @@
- -
-
+
-
+
- Take Off
+ Aircraft
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
- -
-
-
- false
-
-
-
- 200
- 0
-
-
-
-
- 200
- 16777215
-
-
-
-
- true
-
+
-
+
+
+ Approach
+
+
+ -
+
-
+ Third Pilot
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
- -
-
+
-
+
160
@@ -112,8 +124,12 @@
- -
-
+
-
+
+
+ Date Of flight
+
+
-
@@ -122,8 +138,8 @@
- -
-
+
-
+
160
@@ -136,17 +152,27 @@
16777215
+
+ YYYY-MM-DD
+
- -
+
-
+
+
+ Flight Rules
+
+
+
+ -
On Blocks
- -
-
+
-
+
160
@@ -161,81 +187,68 @@
- -
-
+
-
+
- Total Time
+ SIC
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
- -
-
-
-
- 160
- 0
-
-
+
-
+
- 00:00
+ Landing
- -
-
+
-
+
- true
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+ false
-
-
- -
-
- 160
+ 200
0
- 120
+ 200
16777215
-
-
- -
-
- Destination
+
- -
-
-
- Aircraft
+
-
+
+
+ -
+
+
+
+ 160
+ 0
+
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ true
+
-
-
- -
-
- Off Blocks
+ 00:00
- -
-
+
-
+
160
@@ -248,35 +261,40 @@
16777215
-
- YYYY-MM-DD
-
- -
-
-
- false
-
+
-
+
- 200
+ 160
0
- 200
+ 120
16777215
-
-
-
- -
-
+
-
+
+
-
+
+ VFR
+
+
+ -
+
+ IFR
+
+
+
+
+ -
+
160
@@ -291,11 +309,8 @@
- -
-
-
- false
-
+
-
+
200
@@ -308,40 +323,29 @@
16777215
-
-
- true
-
-
- -
-
-
- false
-
+
-
+
- 200
+ 160
0
- 200
+ 120
16777215
-
-
-
- -
-
+
-
+
160
@@ -356,17 +360,23 @@
- -
-
-
- Remarks
+
-
+
+
+
+ 160
+ 0
+
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+ 120
+ 16777215
+
- -
+
-
Flight Number
@@ -376,59 +386,18 @@
- -
-
-
- PIC
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- SIC
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- Date of flight
-
-
-
- -
-
-
- Third Pilot
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
-
-
-
- -
-
-
- Function
-
-
-
-
-
+
- Approach
+ Total Time
- -
-
+
-
+
+
+ -
+
160
@@ -443,45 +412,24 @@
- -
-
-
- Flight Rules
+
-
+
+
+ true
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
- VFR
-
-
- -
-
- IFR
-
-
-
-
- -
-
-
- Landing
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
- -
-
-
- -
-
+
-
+
+
+ false
+
200
@@ -499,8 +447,21 @@
- -
-
+
-
+
+
+ Remarks
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+ false
+
200
@@ -513,6 +474,45 @@
16777215
+
+
+ true
+
+
+
+
+
+
+
+ -
+
+
+ Destination
+
+
+
+ -
+
+
+ -
+
+
+ Take Off
+
+
+
+ -
+
+
+ -
+
+
+ Pilot Flying
+
+
+
+ -
+
@@ -521,17 +521,18 @@
+ doftLineEdit
deptLocationLineEdit
destLocationLineEdit
tofbTimeLineEdit
tonbTimeLineEdit
+ acftLineEdit
picNameLineEdit
sicNameLineEdit
thirdPilotNameLineEdit
flightNumberLineEdit
remarksLineEdit
- takeOffSpinBox
- approachComboBox
+ calendarPushButton
diff --git a/src/gui/dialogues/newpilotdialog.cpp b/src/gui/dialogues/newpilotdialog.cpp
index aaa8a8a3..a3c5ffe5 100644
--- a/src/gui/dialogues/newpilotdialog.cpp
+++ b/src/gui/dialogues/newpilotdialog.cpp
@@ -21,16 +21,18 @@
#include "src/opl.h"
#include "src/database/database.h"
-#include "src/database/row.h"
/*!
* \brief NewPilotDialog::NewPilotDialog - creates a new pilot dialog which can be used to add a new entry to the database
*/
-NewPilotDialog::NewPilotDialog(QWidget *parent) :
- QDialog(parent),
+NewPilotDialog::NewPilotDialog(QString userInput, QWidget* parent)
+ : EntryEditDialog{parent},
ui(new Ui::NewPilot)
{
setup();
+ if(userInput != QString()) {
+ ui->lastnameLineEdit->setText(userInput.replace(0, 1, userInput.first(1).toUpper()));
+ }
ui->lastnameLineEdit->setFocus();
}
@@ -39,7 +41,7 @@ NewPilotDialog::NewPilotDialog(QWidget *parent) :
* \param rowId - the rowid of the entry to be edited in the database
*/
NewPilotDialog::NewPilotDialog(int rowId, QWidget *parent) :
- QDialog(parent),
+ EntryEditDialog{rowId, parent},
ui(new Ui::NewPilot)
{
setup();
@@ -58,7 +60,9 @@ NewPilotDialog::~NewPilotDialog()
void NewPilotDialog::setup()
{
ui->setupUi(this);
- ui->companyLineEdit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Companies));
+ auto completer = QCompleterProvider.getCompleter(CompleterProvider::Companies);
+ completer->setCompletionMode(QCompleter::InlineCompletion);
+ ui->companyLineEdit->setCompleter(completer);
}
void NewPilotDialog::on_buttonBox_accepted()
@@ -107,3 +111,17 @@ void NewPilotDialog::submitForm()
QDialog::accept();
}
}
+
+bool NewPilotDialog::deleteEntry(int rowId)
+{
+ auto entry = DB->getPilotEntry(rowId);
+ return DB->remove(entry);
+
+}
+
+void NewPilotDialog::loadEntry(int rowId)
+{
+ pilotEntry = DB->getPilotEntry(rowId);
+ formFiller();
+ ui->lastnameLineEdit->setFocus();
+}
diff --git a/src/gui/dialogues/newpilotdialog.h b/src/gui/dialogues/newpilotdialog.h
index d29ff90a..16081a1d 100644
--- a/src/gui/dialogues/newpilotdialog.h
+++ b/src/gui/dialogues/newpilotdialog.h
@@ -24,6 +24,7 @@
#include
#include
#include "src/database/pilotentry.h"
+#include "src/gui/dialogues/entryeditdialog.h"
namespace Ui {
class NewPilot;
@@ -41,14 +42,17 @@ class NewPilot;
* come in all different forms and shapes around the world. In order to maintain a maximum
* amount of flexibility, any unicode input is allowed.
*/
-class NewPilotDialog : public QDialog
+class NewPilotDialog : public EntryEditDialog
{
Q_OBJECT
public:
- explicit NewPilotDialog(QWidget *parent = nullptr);
+ explicit NewPilotDialog(QString userInput = QString(), QWidget *parent = nullptr);
explicit NewPilotDialog(int rowId, QWidget *parent = nullptr);
~NewPilotDialog();
+
+
+
private slots:
void on_buttonBox_accepted();
private:
@@ -67,6 +71,12 @@ private slots:
* \brief submitForm - retreives the input from the line edits and commits to the database.
*/
void submitForm();
+
+ // EntryEditDialog interface
+public:
+ virtual bool deleteEntry(int rowId) override;
+ virtual void loadEntry(int rowId) override;
+
};
diff --git a/src/gui/dialogues/newsimdialog.cpp b/src/gui/dialogues/newsimdialog.cpp
index 9207a1e9..1a5ede94 100644
--- a/src/gui/dialogues/newsimdialog.cpp
+++ b/src/gui/dialogues/newsimdialog.cpp
@@ -4,33 +4,33 @@
#include "ui_newsimdialog.h"
#include "src/opl.h"
#include "src/classes/time.h"
-#include "src/functions/datetime.h"
#include "src/database/database.h"
+#include "src/classes/settings.h"
#include
/*!
* \brief create a NewSimDialog to add a new Simulator Entry to the database
*/
-NewSimDialog::NewSimDialog(QWidget *parent) :
- QDialog(parent),
+NewSimDialog::NewSimDialog(QWidget *parent)
+ : EntryEditDialog(parent),
ui(new Ui::NewSimDialog)
{
- //entry = ASimulatorEntry();
ui->setupUi(this);
- ui->dateLineEdit->setText(OPL::DateTime::currentDate());
init();
+
+ ui->dateLineEdit->setText(OPL::Date::today(m_format).toString());
}
/*!
* \brief create a NewSimDialog to edit an existing Simulator Entry
* \param row_id of the entry to be edited
*/
-NewSimDialog::NewSimDialog(int row_id, QWidget *parent) :
- QDialog(parent),
+NewSimDialog::NewSimDialog(int row_id, QWidget *parent)
+ : EntryEditDialog(parent),
ui(new Ui::NewSimDialog)
{
-
ui->setupUi(this);
- entry = DB->getSimEntry(row_id);
init();
+
+ entry = DB->getSimEntry(row_id);
fillEntryData();
}
@@ -47,6 +47,8 @@ void NewSimDialog::init()
completer->setCompletionMode(QCompleter::PopupCompletion);
completer->setFilterMode(Qt::MatchContains);
ui->aircraftTypeLineEdit->setCompleter(completer);
+
+ m_format = Settings::getDisplayFormat();
}
/*!
@@ -55,8 +57,8 @@ void NewSimDialog::init()
void NewSimDialog::fillEntryData()
{
const auto& data = entry.getData();
- ui->dateLineEdit->setText(data.value(OPL::SimulatorEntry::DATE).toString());
- ui->totalTimeLineEdit->setText(OPL::Time(data.value(OPL::SimulatorEntry::TIME).toInt()).toString());
+ ui->dateLineEdit->setText(OPL::Date(data.value(OPL::SimulatorEntry::DATE).toInt(), m_format).toString());
+ ui->totalTimeLineEdit->setText(OPL::Time(data.value(OPL::SimulatorEntry::TIME).toInt(), m_format).toString());
ui->deviceTypeComboBox->setCurrentIndex(data.value(OPL::SimulatorEntry::TYPE).toInt());
ui->aircraftTypeLineEdit->setText(data.value(OPL::SimulatorEntry::ACFT).toString());
ui->registrationLineEdit->setText(data.value(OPL::SimulatorEntry::REG).toString());
@@ -70,12 +72,9 @@ NewSimDialog::~NewSimDialog()
void NewSimDialog::on_dateLineEdit_editingFinished()
{
- auto text = ui->dateLineEdit->text();
-
- OPL::DateFormat date_format = OPL::DateFormat::ISODate;
- auto date = OPL::DateTime::parseInput(text, date_format);
- if (date.isValid()) {
- ui->dateLineEdit->setText(OPL::DateTime::dateToString(date, date_format));
+ const auto date = OPL::Date(ui->dateLineEdit->text(), m_format);
+ if(date.isValid()) {
+ ui->dateLineEdit->setText(date.toString());
ui->dateLineEdit->setStyleSheet(QString());
return;
} else {
@@ -87,7 +86,7 @@ void NewSimDialog::on_dateLineEdit_editingFinished()
void NewSimDialog::on_totalTimeLineEdit_editingFinished()
{
- const auto input = TimeInput(ui->totalTimeLineEdit->text());
+ const auto input = TimeInput(ui->totalTimeLineEdit->text(), m_format);
if(input.isValid())
return;
else {
@@ -122,9 +121,7 @@ void NewSimDialog::on_helpPushButton_clicked()
bool NewSimDialog::verifyInput(QString& error_msg)
{
// Date
- auto text = ui->dateLineEdit->text();
- OPL::DateFormat date_format = OPL::DateFormat::ISODate;
- const auto date = OPL::DateTime::parseInput(text, date_format);
+ const auto date = OPL::Date(ui->dateLineEdit->text(), m_format);
if (!date.isValid()) {
ui->dateLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
@@ -133,10 +130,10 @@ bool NewSimDialog::verifyInput(QString& error_msg)
return false;
}
// Time
- if(!TimeInput(ui->totalTimeLineEdit->text()).isValid())
+ if(!TimeInput(ui->totalTimeLineEdit->text(), m_format).isValid())
return false;
- const OPL::Time time = OPL::Time::fromString(ui->totalTimeLineEdit->text());
+ const OPL::Time time = OPL::Time::fromString(ui->totalTimeLineEdit->text(), m_format);
if (!time.isValidTimeOfDay()) {
ui->totalTimeLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
@@ -159,9 +156,10 @@ OPL::RowData_T NewSimDialog::collectInput()
{
OPL::RowData_T new_entry;
// Date
- new_entry.insert(OPL::SimulatorEntry::DATE, ui->dateLineEdit->text());
+ const auto date = OPL::Date(ui->dateLineEdit->text(), m_format);
+ new_entry.insert(OPL::SimulatorEntry::DATE, date.toJulianDay());
// Time
- new_entry.insert(OPL::SimulatorEntry::TIME, OPL::Time::fromString(ui->totalTimeLineEdit->text()).toMinutes());
+ new_entry.insert(OPL::SimulatorEntry::TIME, OPL::Time::fromString(ui->totalTimeLineEdit->text(), m_format).toMinutes());
// Device Type
new_entry.insert(OPL::SimulatorEntry::TYPE, ui->deviceTypeComboBox->currentText());
// Aircraft Type
@@ -193,3 +191,17 @@ void NewSimDialog::on_buttonBox_accepted()
else
WARN(tr("Unable to commit entry to database. The following error has ocurred
%1").arg(DB->lastError.text()));
}
+
+// EntryEdit interface
+void NewSimDialog::loadEntry(int rowID)
+{
+ entry = DB->getSimEntry(rowID);
+ init();
+ fillEntryData();
+}
+
+bool NewSimDialog::deleteEntry(int rowID)
+{
+ const auto entry = DB->getSimEntry(rowID);
+ return DB->remove(entry);
+}
diff --git a/src/gui/dialogues/newsimdialog.h b/src/gui/dialogues/newsimdialog.h
index fb2a0770..a9ce411a 100644
--- a/src/gui/dialogues/newsimdialog.h
+++ b/src/gui/dialogues/newsimdialog.h
@@ -2,7 +2,10 @@
#define NEWSIMDIALOG_H
#include
+#include "src/database/database.h"
#include "src/database/simulatorentry.h"
+#include "src/gui/dialogues/entryeditdialog.h"
+#include "src/classes/date.h"
namespace Ui {
class NewSimDialog;
@@ -17,7 +20,7 @@ class NewSimDialog;
*
* A QCompleter provides in-line completion for the aircraft type field.
*/
-class NewSimDialog : public QDialog
+class NewSimDialog : public EntryEditDialog
{
Q_OBJECT
@@ -39,12 +42,24 @@ private slots:
private:
Ui::NewSimDialog *ui;
+ //TODO load from settings
+ OPL::DateTimeFormat m_format = OPL::DateTimeFormat(
+ OPL::DateTimeFormat::DateFormat::Default,
+ QStringLiteral("yyyy-MM-dd"),
+ OPL::DateTimeFormat::TimeFormat::Default,
+ QStringLiteral("hh:mm")
+ );
+
void init();
void fillEntryData();
bool verifyInput(QString &error_msg);
OPL::RowData_T collectInput();
-
OPL::SimulatorEntry entry;
+
+ // EntryEditDialog interface
+public:
+ virtual void loadEntry(int rowID) override;
+ virtual bool deleteEntry(int rowID) override;
};
#endif // NEWSIMDIALOG_H
diff --git a/src/gui/dialogues/newtaildialog.cpp b/src/gui/dialogues/newtaildialog.cpp
index 77c9ad59..a1634ad7 100644
--- a/src/gui/dialogues/newtaildialog.cpp
+++ b/src/gui/dialogues/newtaildialog.cpp
@@ -22,7 +22,7 @@
#include "src/opl.h"
NewTailDialog::NewTailDialog(const QString &new_registration, QWidget *parent) :
- QDialog(parent),
+ EntryEditDialog(parent),
ui(new Ui::NewTail)
{
ui->setupUi(this);
@@ -38,7 +38,7 @@ NewTailDialog::NewTailDialog(const QString &new_registration, QWidget *parent) :
}
NewTailDialog::NewTailDialog(int row_id, QWidget *parent) :
- QDialog(parent),
+ EntryEditDialog(parent),
ui(new Ui::NewTail)
{
ui->setupUi(this);
@@ -202,6 +202,12 @@ void NewTailDialog::submitForm()
//create db object
entry.setData(new_data);
+
+ // add type string
+ auto data = entry.getData();
+ data.insert(OPL::TailEntry::TYPE_STRING, entry.type());
+ entry.setData(data);
+
LOG << "Commiting: " << entry;
if (!DB->commit(entry)) {
QMessageBox message_box(this);
@@ -271,15 +277,32 @@ void NewTailDialog::onSearchCompleterActivated()
const auto &text = ui->searchLineEdit->text();
if (aircraftList.contains(text)) {
- DEB << "Template Selected. aircraft_id is: " << idMap.key(text);
- //call autofiller for dialog
- fillForm(DB->getAircraftEntry(idMap.key(text)), true);
- ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid green"));
- ui->searchLabel->setText(text);
- } else {
- //for example, editing finished without selecting a result from Qcompleter
- ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid orange"));
- }
+ DEB << "Template Selected. aircraft_id is: " << idMap.key(text);
+ //call autofiller for dialog
+ fillForm(DB->getAircraftEntry(idMap.key(text)), true);
+ ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid green"));
+ ui->searchLabel->setText(text);
+ } else {
+ //for example, editing finished without selecting a result from Qcompleter
+ ui->searchLineEdit->setStyleSheet(QStringLiteral("border: 1px solid orange"));
+ }
+}
+
+bool NewTailDialog::deleteEntry(int rowID)
+{
+ auto entry = DB->getTailEntry(rowID);
+ return DB->remove(entry);
+}
+
+void NewTailDialog::loadEntry(int rowId)
+{
+ ui->searchLabel->hide();
+ ui->searchLineEdit->hide();
+ ui->line->hide();
+
+ setupValidators();
+ entry = DB->getTailEntry(rowId);
+ fillForm(entry, false);
}
void NewTailDialog::on_registrationLineEdit_textChanged(const QString &arg1)
diff --git a/src/gui/dialogues/newtaildialog.h b/src/gui/dialogues/newtaildialog.h
index f2cdf240..437e2f0d 100644
--- a/src/gui/dialogues/newtaildialog.h
+++ b/src/gui/dialogues/newtaildialog.h
@@ -26,6 +26,7 @@
#include "src/database/row.h"
#include "src/database/tailentry.h"
+#include "src/gui/dialogues/entryeditdialog.h"
namespace Ui {
class NewTail;
@@ -55,7 +56,7 @@ class NewTail;
*
*
*/
-class NewTailDialog : public QDialog
+class NewTailDialog : public EntryEditDialog
{
Q_OBJECT
@@ -64,7 +65,7 @@ class NewTailDialog : public QDialog
* \brief NewTailDialog - create a new ATailEntry and submit it to the database
* \param new_registration - when called from the NewFlightDialog, pre-fills the registration already entered.
*/
- explicit NewTailDialog(const QString& new_registration, QWidget *parent = nullptr);
+ explicit NewTailDialog(const QString &new_registration, QWidget *parent = nullptr);
/*!
* \brief NewTailDialog - edit an existing Tail Entry
* \param row_id - the ROW_ID of the entry to be edited in the database
@@ -73,6 +74,8 @@ class NewTailDialog : public QDialog
~NewTailDialog();
+
+
signals:
void tailDataChanged();
private:
@@ -102,6 +105,11 @@ private slots:
void on_buttonBox_accepted();
void onSearchCompleterActivated();
+
+ // EntryEditDialog interface
+public:
+ virtual bool deleteEntry(int rowID) override;
+ virtual void loadEntry(int rowId) override;
};
#endif // NEWTAIL_H
diff --git a/src/gui/verification/timeinput.cpp b/src/gui/verification/timeinput.cpp
index 7f4ed810..aa869dd5 100644
--- a/src/gui/verification/timeinput.cpp
+++ b/src/gui/verification/timeinput.cpp
@@ -1,10 +1,11 @@
#include "timeinput.h"
+#include "src/classes/time.h"
#include "src/opl.h"
#include
bool TimeInput::isValid() const
{
- return QTime::fromString(input, OPL::Format::TIME_FORMAT).isValid();
+ return OPL::Time::fromString(input, m_format).isValid();
}
/*!
@@ -14,8 +15,23 @@ bool TimeInput::isValid() const
*/
QString TimeInput::fixup() const
{
- QString fixed = input;
+ switch(m_format.timeFormat()) {
+ case OPL::DateTimeFormat::TimeFormat::Default:
+ return fixDefaultFormat();
+ case OPL::DateTimeFormat::TimeFormat::Decimal:
+ return fixDecimalFormat();
+ case OPL::DateTimeFormat::TimeFormat::Custom:
+ return input; // custom formats cannot be fixed
+ break;
+ }
+}
+const QString TimeInput::fixDefaultFormat() const
+{
+ if(input == QString())
+ return QStringLiteral("00:00");
+ // try inserting a ':' for hhmm inputs
+ QString fixed = input;
if (input.contains(':')) { // contains seperator
if(input.length() == 4)
fixed.prepend(QLatin1Char('0'));
@@ -29,6 +45,20 @@ QString TimeInput::fixup() const
}
}
- QTime time = QTime::fromString(fixed, OPL::Format::TIME_FORMAT);
- return time.toString(OPL::Format::TIME_FORMAT);
+ OPL::Time fixedTime = OPL::Time::fromString(fixed, m_format);
+ if(fixedTime.isValid()) {
+ return OPL::Time::fromString(fixed, m_format).toString();
+ } else {
+ return QString();
+ }
+
+
+}
+
+const QString TimeInput::fixDecimalFormat() const
+{
+ // try to replace an erroneus decimal seperator
+ QString fixed = input;
+ return OPL::Time::fromString(fixed.replace(QLatin1Char(','), OPL::DECIMAL_SEPERATOR), m_format).toString();
}
+
diff --git a/src/gui/verification/timeinput.h b/src/gui/verification/timeinput.h
index 87c7dd60..f86d5e82 100644
--- a/src/gui/verification/timeinput.h
+++ b/src/gui/verification/timeinput.h
@@ -1,13 +1,15 @@
#ifndef TIMEINPUT_H
#define TIMEINPUT_H
+#include "src/opl.h"
#include "userinput.h"
class TimeInput : public UserInput
{
public:
TimeInput() = delete;
- TimeInput(const QString &input) : UserInput(input) {}
+ TimeInput(const QString &input, const OPL::DateTimeFormat &format)
+ : UserInput(input), m_format(format) {}
/*!
* \brief Checks if a user entered String is a valid time input
@@ -25,6 +27,10 @@ class TimeInput : public UserInput
*/
QString fixup() const override;
private:
+ const OPL::DateTimeFormat &m_format;
+
+ const QString fixDefaultFormat() const;
+ const QString fixDecimalFormat() const;
};
#endif // TIMEINPUT_H
diff --git a/src/gui/widgets/airporttableeditwidget.cpp b/src/gui/widgets/airporttableeditwidget.cpp
new file mode 100644
index 00000000..cde2de3c
--- /dev/null
+++ b/src/gui/widgets/airporttableeditwidget.cpp
@@ -0,0 +1,79 @@
+#include "airporttableeditwidget.h"
+#include "src/database/database.h"
+#include "src/gui/dialogues/newairportdialog.h"
+
+AirportTableEditWidget::AirportTableEditWidget(QWidget *parent)
+ : TableEditWidget(Vertical, parent)
+{}
+
+void AirportTableEditWidget::setupModelAndView()
+{
+ m_model = new QSqlTableModel(this, DB->database());
+ m_model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Airports));
+ m_model->select();
+
+ for(int i = 0; i < HEADER_NAMES.size(); i++) {
+ m_model->setHeaderData(i + 1, Qt::Horizontal, HEADER_NAMES.at(i));
+ }
+
+ m_view->setModel(m_model);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+ m_view->resizeColumnsToContents();
+ m_view->verticalHeader()->hide();
+ m_view->setAlternatingRowColors(true);
+ m_view->hideColumn(COL_ROWID);
+
+}
+
+void AirportTableEditWidget::setupUI()
+{
+ // the base class does most of the setup
+ TableEditWidget::setupUI();
+
+ // only need to set the table specific labels and combo box items
+ m_addNewEntryPushButton->setText(tr("Add New Airport"));
+ m_deleteEntryPushButton->setText(tr("Delete Selected Airport"));
+ for(const int i : FILTER_COLUMNS) {
+ m_filterSelectionComboBox->addItem(HEADER_NAMES.at(i));
+ }
+}
+
+QString AirportTableEditWidget::deleteErrorString(int rowId)
+{
+ return tr("
Unable to delete.
The following error has ocurred: %1"
+ ).arg(DB->lastError.text());
+}
+
+QString AirportTableEditWidget::confirmDeleteString(int rowId)
+{
+ const auto entry = DB->getAirportEntry(rowId);
+ return tr("The following airport will be deleted:
"
+ "%1
"
+ "Deleting airports is irreversible.
Do you want to proceed?"
+ ).arg(entry.getAirportDescriptor());
+}
+
+EntryEditDialog *AirportTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+ return new NewAirportDialog(parent);
+}
+
+void AirportTableEditWidget::filterTextChanged(const QString &filterString)
+{
+ if(filterString.isEmpty()) {
+ m_model->setFilter(QString());
+ return;
+ }
+
+ int i = m_filterSelectionComboBox->currentIndex();
+ const QString filter =
+ QLatin1Char('\"')
+ + HEADER_NAMES.at(FILTER_COLUMNS[i])
+ + QLatin1String("\" LIKE '%")
+ + filterString
+ + QLatin1String("%'");
+ m_model->setFilter(filter);
+}
diff --git a/src/gui/widgets/airporttableeditwidget.h b/src/gui/widgets/airporttableeditwidget.h
new file mode 100644
index 00000000..ab52b07e
--- /dev/null
+++ b/src/gui/widgets/airporttableeditwidget.h
@@ -0,0 +1,52 @@
+#ifndef AIRPORTTABLEEDITWIDGET_H
+#define AIRPORTTABLEEDITWIDGET_H
+
+#include "tableeditwidget.h"
+#include
+#include "src/database/airportentry.h"
+
+class AirportTableEditWidget : public TableEditWidget
+{
+ Q_OBJECT
+public:
+ AirportTableEditWidget() = delete;
+ AirportTableEditWidget(QWidget *parent = nullptr);
+
+ // TableEditWidget interface
+ virtual void setupModelAndView() override;
+ virtual void setupUI() override;
+ virtual QString deleteErrorString(int rowId) override;
+ virtual QString confirmDeleteString(int rowId) override;
+ virtual EntryEditDialog *getEntryEditDialog(QWidget *parent) override;
+
+ // table columns and header names
+
+ const int COL_ROWID = 0;
+
+ // used to display the Header Views and Fill the FilterComboBox
+ const QStringList HEADER_NAMES = {
+ tr("ICAO"),
+ tr("IATA"),
+ tr("Name"),
+ tr("Latitude"),
+ tr("Longitude"),
+ tr("Country"),
+ tr("Time Zone"),
+ };
+
+ // These are indexes into HEADER_NAMES
+ const int FILTER_COLUMNS[4] = {0, 1, 2, 5};
+
+ // The sql column names corresponding to the entries of the FilterComboBox index
+ const static inline QStringList FILTER_COLUMN_NAMES = {
+ OPL::AirportEntry::ICAO,
+ OPL::AirportEntry::IATA,
+ OPL::AirportEntry::NAME,
+ OPL::AirportEntry::TZ_OLSON,
+ };
+
+private slots:
+ virtual void filterTextChanged(const QString &filterString) override;
+};
+
+#endif // AIRPORTTABLEEDITWIDGET_H
diff --git a/src/gui/widgets/backupwidget.cpp b/src/gui/widgets/backupwidget.cpp
index bfec0eff..d4712e72 100644
--- a/src/gui/widgets/backupwidget.cpp
+++ b/src/gui/widgets/backupwidget.cpp
@@ -22,6 +22,8 @@
#include "src/functions/datetime.h"
#include "src/database/dbsummary.h"
#include "src/gui/dialogues/firstrundialog.h"
+#include "src/classes/settings.h"
+#include "src/classes/styleddatedelegate.h"
#include
#include
@@ -39,6 +41,12 @@ BackupWidget::BackupWidget(QWidget *parent) :
model->setHorizontalHeaderLabels(QStringList{tr("Total Time"),tr("Flights"), tr("Aircraft"),
tr("Pilots"), tr("Last Flight"), tr("Backup File")});
view = ui->tableView;
+
+
+ // julian day to Date Format
+ const auto dateDelegate = new StyledDateDelegate(Settings::getDisplayFormat(), model);
+ view->setItemDelegateForColumn(DATE_COLUMN, dateDelegate);
+
refresh();
}
@@ -86,8 +94,8 @@ const QString BackupWidget::absoluteBackupPath()
const QString BackupWidget::backupName()
{
auto owner = DB->getPilotEntry(1);
- return QString("logbook_backup_%1_%2.db").arg(
- OPL::DateTime::dateTimeToString(QDateTime::currentDateTime(), OPL::DateTimeFormat::Backup),
+ return QStringLiteral("logbook_backup_%1_%2.db").arg(
+ OPL::DateTime::dateTimeToString(QDateTime::currentDateTime(), OPL::DateTimeFormat_deprecated::Backup),
owner.getLastName()
);
}
diff --git a/src/gui/widgets/backupwidget.h b/src/gui/widgets/backupwidget.h
index 13819825..ee80ff78 100644
--- a/src/gui/widgets/backupwidget.h
+++ b/src/gui/widgets/backupwidget.h
@@ -96,6 +96,8 @@ private slots:
QList selectedRows;
void refresh();
+ static constexpr int DATE_COLUMN = 4;
+
protected:
/*!
* \brief Handles change events, like updating the UI to new localisation
diff --git a/src/gui/widgets/currencywidget.cpp b/src/gui/widgets/currencywidget.cpp
new file mode 100644
index 00000000..98a79bf3
--- /dev/null
+++ b/src/gui/widgets/currencywidget.cpp
@@ -0,0 +1,264 @@
+#include "currencywidget.h"
+#include "QtSql/qsqltablemodel.h"
+#include "QtWidgets/qheaderview.h"
+#include "qgridlayout.h"
+#include "src/classes/easaftl.h"
+#include "src/classes/styleddatedelegate.h"
+#include "src/classes/time.h"
+#include "src/database/database.h"
+#include "src/functions/statistics.h"
+#include "src/classes/settings.h"
+#include
+#include
+#include
+
+CurrencyWidget::CurrencyWidget(QWidget *parent)
+ : QWidget{parent}
+{
+ m_format = Settings::getDisplayFormat();
+ setupModelAndView();
+ setupUI();
+
+ fillTakeOffAndLandingCurrencies();
+ fillFlightTimeLimitations();
+
+ warnAboutExpiries();
+}
+
+void CurrencyWidget::setupModelAndView()
+{
+ model = new QSqlTableModel(this, DB->database());
+ model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Currencies));
+ model->select();
+ model->setHeaderData(EXPIRY_DATE_COLUMN, Qt::Horizontal, tr("Expiry Date"));
+ model->setHeaderData(CURRENCY_NAME_COLUMN, Qt::Horizontal, tr("Name"));
+
+ view = new QTableView(this);
+ view->setModel(model);
+ view->setSelectionMode(QAbstractItemView::SingleSelection);
+ view->setSelectionBehavior(QAbstractItemView::SelectItems);
+ view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ view->resizeColumnsToContents();
+ view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+ view->verticalHeader()->hide();
+ view->setAlternatingRowColors(true);
+ view->hideColumn(ROWID_COLUMN);
+
+ const auto dateDelegate = new StyledDateDelegate(Settings::getDisplayFormat(), this);
+ view->setItemDelegateForColumn(EXPIRY_DATE_COLUMN, dateDelegate);
+}
+
+void CurrencyWidget::setupUI()
+{
+ // create a 3-column grid layout
+ int colL = 0; // left column
+ int colM = 1; // middle column
+ int colR = 2; // right column
+ int allColSpan = 3; // span all columns
+ int singleRowSpan = 1; // span only a single row
+ int row = 0;
+ auto gridLayout = new QGridLayout(this);
+
+ // Take-off and Landing Currency
+ gridLayout->addWidget(takeOffLandingHeaderLabel, row, colM, Qt::AlignCenter);
+ row++;
+ gridLayout->addWidget(getHorizontalLine(), row, colL, singleRowSpan, allColSpan);
+ row++;
+
+ gridLayout->addWidget(takeOffCountLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(takeOffCountDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ gridLayout->addWidget(landingCountLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(landingCountDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ gridLayout->addWidget(takeOffLandingExpiryLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(takeOffLandingExpiryDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ // Flight Time Limitations
+ gridLayout->addWidget(flightTimeHeaderLabel, row, colM, Qt::AlignCenter);
+ row++;
+ gridLayout->addWidget(getHorizontalLine(), row, colL, singleRowSpan, allColSpan);
+ row++;
+
+ gridLayout->addWidget(flightTime28DaysLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(flightTime28DaysDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ gridLayout->addWidget(flightTime365DaysLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(flightTime365DaysDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ gridLayout->addWidget(flightTimeCalendarYearLabel, row, colL, Qt::AlignLeft);
+ gridLayout->addWidget(flightTimeCalendarYearDisplayLabel, row, colR, Qt::AlignRight);
+ row++;
+
+ // Expiries (currencies table)
+ gridLayout->addWidget(expiriesHeaderLabel, row, colM, Qt::AlignCenter);
+ row++;
+ gridLayout->addWidget(getHorizontalLine(), row, colL, singleRowSpan, allColSpan);
+ row++;
+ gridLayout->addWidget(view, row, colL, singleRowSpan, allColSpan);
+
+ // set the layout active
+ layout = gridLayout;
+
+ // allocate a widget for date selection
+ calendar = new QCalendarWidget(this);
+ calendar->setVisible(false);
+ calendar->setWindowFlags(Qt::Dialog); // pop-up calendar
+
+
+ // connect signals
+ QObject::connect(view, &QTableView::activated,
+ this, &CurrencyWidget::editRequested);
+ QObject::connect(calendar, &QCalendarWidget::selectionChanged,
+ this, &CurrencyWidget::newExpiryDateSelected);
+}
+
+void CurrencyWidget::fillTakeOffAndLandingCurrencies()
+{
+ const auto takeoff_landings = OPL::Statistics::countTakeOffLanding();
+ LOG << "Currencies: " << takeoff_landings;
+ if(takeoff_landings.isEmpty() || takeoff_landings.size() != 2)
+ return;
+
+ QList displayLabels = {
+ takeOffCountDisplayLabel,
+ landingCountDisplayLabel
+ };
+
+ for(int i = 0; i < 2; i++) {
+ int count = takeoff_landings[i].toInt();
+ if(count < 3)
+ setLabelColour(displayLabels[i], Colour::Red);
+ displayLabels[i]->setText(displayLabels[i]->text().arg(count));
+ }
+ QDate expiration_date = OPL::Statistics::currencyTakeOffLandingExpiry();
+ if (expiration_date <= QDate::currentDate())
+ setLabelColour(takeOffLandingExpiryDisplayLabel, Colour::Red);
+ takeOffLandingExpiryDisplayLabel->setText(expiration_date.toString(Qt::TextDate));
+}
+
+void CurrencyWidget::fillFlightTimeLimitations()
+{
+ const QList> limits =
+ {
+ { flightTime28DaysDisplayLabel, OPL::Statistics::TimeFrame::Rolling28Days },
+ { flightTime365DaysDisplayLabel, OPL::Statistics::TimeFrame::Rolling12Months },
+ { flightTimeCalendarYearDisplayLabel, OPL::Statistics::TimeFrame::CalendarYear },
+ };
+
+ double ftlWarningThreshold = Settings::getFtlWarningThreshold();
+ for (const auto &pair : limits) {
+ int accruedMinutes = OPL::Statistics::totalTime(pair.second);
+ int limitMinutes = EasaFTL::getLimit(pair.second);
+ pair.first->setText(OPL::Time(accruedMinutes, m_format).toString());
+
+
+ if (accruedMinutes >= limitMinutes)
+ setLabelColour(pair.first, Colour::Red);
+ else if (accruedMinutes >= limitMinutes * ftlWarningThreshold)
+ setLabelColour(pair.first, Colour::Orange);
+ }
+}
+
+void CurrencyWidget::editRequested(const QModelIndex &index)
+{
+ if(index.column() == EXPIRY_DATE_COLUMN) {
+ expiryDateEditRequested(index);
+ }
+
+ if(index.column() == CURRENCY_NAME_COLUMN) {
+ displayNameEditRequested(index);
+ }
+}
+
+
+
+void CurrencyWidget::refresh()
+{
+ model->select();
+ fillTakeOffAndLandingCurrencies();
+ fillFlightTimeLimitations();
+
+ view->resizeColumnsToContents();
+ view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+}
+
+void CurrencyWidget::displayNameEditRequested(const QModelIndex &index)
+{
+ QString oldData = index.data().toString();
+ bool textEdited;
+ const QString text = QInputDialog::getText(
+ this,
+ tr("Edit Currency Name"),
+ tr("Please enter a name for this currency"),
+ QLineEdit::Normal,
+ oldData,
+ &textEdited);
+
+ if(textEdited) {
+ model->setData(index, text);
+ model->submitAll();
+ }
+}
+
+void CurrencyWidget::expiryDateEditRequested(const QModelIndex &index)
+{
+ const int selectedDate = index.data().toInt();
+
+ if(selectedDate > 0) {
+ const QSignalBlocker blocker(calendar);
+ calendar->setSelectedDate(QDate::fromJulianDay(selectedDate));
+ calendar->show();
+ } else {
+ calendar->show();
+ }
+ // calendars date selected signal is connected to newExpiryDateSelected()
+}
+
+void CurrencyWidget::newExpiryDateSelected()
+{
+ calendar->hide();
+ model->setData(view->selectionModel()->currentIndex(), calendar->selectedDate().toJulianDay());
+ model->submitAll();
+ model->select();
+}
+
+void CurrencyWidget::warnAboutExpiries()
+{
+ int warningThreshold = Settings::getCurrencyWarningThreshold();
+ if(warningThreshold < 1) {
+ return;
+ }
+
+ const QDate today = QDate::currentDate();
+
+ for(int i = 0; i < model->rowCount(); i++) {
+ const QModelIndex dateIndex = model->index(i, EXPIRY_DATE_COLUMN);
+ if(dateIndex.data().toInt() == 0) {
+ continue;
+ }
+ const auto expiryDate = QDate::fromJulianDay(dateIndex.data().toInt());
+ const auto warningDate = QDate::fromJulianDay(expiryDate.toJulianDay() - warningThreshold);
+
+ if(today >= warningDate) {
+ const QString dateString = expiryDate.toString(Qt::ISODate);
+ const QString nameString = model->index(i, CURRENCY_NAME_COLUMN).data().toString();
+ const QString daysLeft = QString::number(expiryDate.toJulianDay() - today.toJulianDay());
+
+ QString msg = tr("Your %1 expires in %2 days:
%3").arg(nameString, daysLeft, dateString);
+ WARN(msg);
+ }
+ }
+}
+
+QFrame *CurrencyWidget::getHorizontalLine()
+{
+ QFrame* newFrame = new QFrame(this);
+ newFrame->setFrameShape(QFrame::HLine);
+ return newFrame;
+}
diff --git a/src/gui/widgets/currencywidget.h b/src/gui/widgets/currencywidget.h
new file mode 100644
index 00000000..828b8b39
--- /dev/null
+++ b/src/gui/widgets/currencywidget.h
@@ -0,0 +1,84 @@
+#ifndef CURRENCYWIDGET_H
+#define CURRENCYWIDGET_H
+
+#include "src/opl.h"
+#include
+#include
+#include
+#include
+#include
+class CurrencyWidget : public QWidget
+{
+ Q_OBJECT
+ QLayout* layout;
+ QTableView *view;
+ QSqlTableModel *model;
+ QCalendarWidget *calendar;
+ QModelIndex lastSelection;
+ OPL::DateTimeFormat m_format;
+
+ int ROWID_COLUMN = 0;
+ int CURRENCY_NAME_COLUMN = 1;
+ int EXPIRY_DATE_COLUMN = 2;
+
+ void setupModelAndView();
+ void setupUI();
+ void fillTakeOffAndLandingCurrencies();
+ void fillFlightTimeLimitations();
+ void warnAboutExpiries();
+
+ void displayNameEditRequested(const QModelIndex &index);
+ void expiryDateEditRequested(const QModelIndex &index);
+
+ QFrame *getHorizontalLine();
+ QLabel *takeOffLandingHeaderLabel = new QLabel(tr("Take-off and Landing Currency<\b>"), this);
+ QLabel *takeOffCountLabel = new QLabel(tr("Take offs (last 90 days)"), this);
+ QLabel *takeOffCountDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *landingCountLabel = new QLabel(tr("Landings (last 90 days)"), this);
+ QLabel *landingCountDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *takeOffLandingExpiryLabel = new QLabel(tr("3 Take-offs and Landings expiry date"), this);
+ QLabel *takeOffLandingExpiryDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *flightTimeHeaderLabel = new QLabel(tr("Flight Time Limitations"), this);
+ QLabel *flightTime28DaysLabel = new QLabel(tr("Flight time (last 28 days)"), this);
+ QLabel *flightTime28DaysDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *flightTime365DaysLabel = new QLabel(tr("FLight time (last 365 days)"), this);
+ QLabel *flightTime365DaysDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *flightTimeCalendarYearLabel = new QLabel(tr("Flight time (this calendar year"),this);
+ QLabel *flightTimeCalendarYearDisplayLabel = new QLabel(QStringLiteral("%1"), this);
+ QLabel *expiriesHeaderLabel = new QLabel(tr("Expiries<\b>"), this);
+
+ enum class Colour {Red, Orange, None};
+ inline void setLabelColour(QLabel* label, Colour colour)
+ {
+ switch (colour) {
+ case Colour::None:
+ label->setStyleSheet(QString());
+ break;
+ case Colour::Red:
+ label->setStyleSheet(QStringLiteral("color: red"));
+ break;
+ case Colour::Orange:
+ label->setStyleSheet(QStringLiteral("color: orange"));
+ break;
+ default:
+ label->setStyleSheet(QString());
+ break;
+ }
+ }
+
+
+private slots:
+ void editRequested(const QModelIndex &index);
+ void newExpiryDateSelected();
+
+public slots:
+ void refresh();
+
+public:
+ explicit CurrencyWidget(QWidget *parent = nullptr);
+
+signals:
+
+};
+
+#endif // CURRENCYWIDGET_H
diff --git a/src/gui/widgets/debugwidget.cpp b/src/gui/widgets/debugwidget.cpp
index 68a8cd2e..60af1496 100644
--- a/src/gui/widgets/debugwidget.cpp
+++ b/src/gui/widgets/debugwidget.cpp
@@ -300,6 +300,6 @@ void DebugWidget::on_debug2LineEdit_editingFinished()
void DebugWidget::on_pushButton_clicked()
{
Settings::resetToDefaults();
- Settings::write(Settings::Main::SetupComplete, false);
+ Settings::setSetupCompleted(false);
}
diff --git a/src/gui/widgets/homewidget.cpp b/src/gui/widgets/homewidget.cpp
index 822f2d9a..c139e653 100644
--- a/src/gui/widgets/homewidget.cpp
+++ b/src/gui/widgets/homewidget.cpp
@@ -16,46 +16,23 @@
*along with this program. If not, see .
*/
#include "homewidget.h"
-#include "src/functions/statistics.h"
+#include "src/gui/widgets/currencywidget.h"
#include "src/gui/widgets/totalswidget.h"
#include "ui_homewidget.h"
#include "src/database/database.h"
-#include "src/classes/time.h"
-#include "src/classes/settings.h"
-#include "src/database/row.h"
-
-// EASA FTL Limitations in minutes
-// 100 hours per 28 days
-static const int ROLLING_28_DAYS = 6000;
-// 900 hours per calendar year
-static const int CALENDAR_YEAR = 54000;
-// 1000 hours per rolling 12 months
-static const int ROLLING_12_MONTHS = 60000;
-// Todo: Encapsulate and plan to also use non-EASA (FAA,...) options
HomeWidget::HomeWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::HomeWidget)
{
ui->setupUi(this);
- today = QDate::currentDate();
- ftlWarningThreshold = Settings::read(Settings::UserData::FtlWarningThreshold).toDouble();
- currWarningThreshold = Settings::read(Settings::UserData::CurrWarningThreshold).toInt();
- auto logo = QPixmap(OPL::Assets::LOGO);
+
+ const auto logo = QPixmap(OPL::Assets::LOGO);
ui->logoLabel->setPixmap(logo);
ui->welcomeLabel->setText(tr("Welcome to openPilotLog, %1!").arg(getLogbookOwnerName()));
-
- limitationDisplayLabels = {
- ui->TakeOffDisplayLabel, ui->LandingsDisplayLabel,
- ui->FlightTime28dDisplayLabel, ui->FlightTimeCalYearDisplayLabel,
- ui->FlightTime12mDisplayLabel
- };
-
- LOG << "Filling Home Widget...";
fillTotals();
- fillSelectedCurrencies();
- fillLimitations();
+ fillCurrencies();
QObject::connect(DB, &OPL::Database::dataBaseUpdated,
this, &HomeWidget::onPilotsDatabaseChanged);
@@ -66,23 +43,20 @@ HomeWidget::~HomeWidget()
delete ui;
}
-void HomeWidget::refresh()
+void HomeWidget::fillTotals()
{
- LOG << "Updating HomeWidget...";
- const auto label_list = this->findChildren();
- for (const auto label : label_list)
- label->setVisible(true);
- for (const auto &label : qAsConst(limitationDisplayLabels))
- label->setStyleSheet(QString());
+ auto tw = new TotalsWidget(TotalsWidget::TotalTimeWidget, this);
+ ui->tabWidget->insertTab(0, tw, tr("Totals"));
+}
- fillTotals();
- fillSelectedCurrencies();
- fillLimitations();
+void HomeWidget::fillCurrencies()
+{
+ auto cw = new CurrencyWidget(this);
+ ui->tabWidget->insertTab(1, cw, tr("Currencies"));
}
void HomeWidget::onPilotsDatabaseChanged(const OPL::DbTable table)
{
- // maybe logbook owner name has changed, redraw
if (table == OPL::DbTable::Pilots)
ui->welcomeLabel->setText(tr("Welcome to openPilotLog, %1!").arg(getLogbookOwnerName()));
}
@@ -94,144 +68,12 @@ void HomeWidget::changeEvent(QEvent *event)
ui->retranslateUi(this);
}
-/*!
- * \brief HomeWidget::fillTotals Retreives a Database Summary of Total Flight Time via the OPL::Statistics::totals
- * function and parses the return to fill out the QLineEdits.
- */
-void HomeWidget::fillTotals()
-{
- auto tw = new TotalsWidget(TotalsWidget::TotalTimeWidget, this);
- ui->totalsStackedWidget->addWidget(tw);
- ui->totalsStackedWidget->setCurrentWidget(tw);
-}
-
-void HomeWidget::fillCurrency(OPL::CurrencyName currency_name, QLabel* display_label)
-{
- const auto currency_entry = DB->getCurrencyEntry(static_cast(currency_name));
-
- if (currency_name == OPL::CurrencyName::Custom1) {
- ui->currCustom1Label->setText(currency_entry.getData().value(OPL::CurrencyEntry::CURRENCYNAME).toString());
- } else if (currency_name == OPL::CurrencyName::Custom2) {
- ui->currCustom2Label->setText(currency_entry.getData().value(OPL::CurrencyEntry::CURRENCYNAME).toString());
- }
-
- if (currency_entry.isValid()) {
- const auto currency_date = QDate::fromString(currency_entry.getData().value(
- OPL::CurrencyEntry::EXPIRYDATE).toString(),
- Qt::ISODate);
- display_label->setText(currency_date.toString(Qt::TextDate));
- setLabelColour(display_label, Colour::None);
-
- if (today >= currency_date) { // is expired
- setLabelColour(display_label, Colour::Red);
- return;
- } else if (today.addDays(currWarningThreshold) >=currency_date) { // expires less than days from current Date
-
- setLabelColour(display_label, Colour::Orange);
- }
- } else {
- display_label->setText(tr("Invalid Date"));
- }
-}
-
-/*!
- * \brief HomeWidget::fillSelectedCurrencies Checks whether a currency is selected and
- * retreives and displays relevant data.
- */
-void HomeWidget::fillSelectedCurrencies()
-{
- fillCurrencyTakeOffLanding();
-
- Settings::read(Settings::UserData::ShowLicCurrency).toBool() ?
- fillCurrency(OPL::CurrencyName::Licence, ui->currLicDisplayLabel)
- : hideLabels(ui->currLicLabel, ui->currLicDisplayLabel);
- Settings::read(Settings::UserData::ShowTrCurrency).toBool() ?
- fillCurrency(OPL::CurrencyName::TypeRating, ui->currTrDisplayLabel)
- : hideLabels(ui->currTrLabel, ui->currTrDisplayLabel);
- Settings::read(Settings::UserData::ShowLckCurrency).toBool() ?
- fillCurrency(OPL::CurrencyName::LineCheck, ui->currLckDisplayLabel)
- : hideLabels(ui->currLckLabel, ui->currLckDisplayLabel);
- Settings::read(Settings::UserData::ShowMedCurrency).toBool() ?
- fillCurrency(OPL::CurrencyName::Medical, ui->currMedDisplayLabel)
- : hideLabels(ui->currMedLabel, ui->currMedDisplayLabel);
- Settings::read(Settings::UserData::ShowCustom1Currency).toBool() ?
- fillCurrency(OPL::CurrencyName::Custom1, ui->currCustom1DisplayLabel)
- : hideLabels(ui->currCustom1Label, ui->currCustom1DisplayLabel);
- Settings::read(Settings::UserData::ShowCustom1Currency).toBool() ?
- fillCurrency(OPL::CurrencyName::Custom1, ui->currCustom1DisplayLabel)
- : hideLabels(ui->currCustom1Label, ui->currCustom1DisplayLabel);
- Settings::read(Settings::UserData::ShowCustom2Currency).toBool() ?
- fillCurrency(OPL::CurrencyName::Custom2, ui->currCustom2DisplayLabel)
- : hideLabels(ui->currCustom2Label, ui->currCustom2DisplayLabel);
-}
-
-/*!
- * \brief HomeWidget::fillCurrencyTakeOffLanding Uses OPL::Statistics::countTakeOffLandings to determine
- * the amount of Take-Offs and Landings in the last 90 days and displays data and notifications
- * as required.
- */
-void HomeWidget::fillCurrencyTakeOffLanding()
-{
- const auto takeoff_landings = OPL::Statistics::countTakeOffLanding();
- if(takeoff_landings.isEmpty())
- return;
-
- ui->TakeOffDisplayLabel->setText(takeoff_landings[0].toString());
- if (takeoff_landings[0].toUInt() < 3)
- setLabelColour(ui->TakeOffDisplayLabel, Colour::Red);
- ui->LandingsDisplayLabel->setText(takeoff_landings[1].toString());
- if (takeoff_landings[1].toUInt() < 3)
- setLabelColour(ui->LandingsDisplayLabel, Colour::Red);
-
- if (Settings::read(Settings::UserData::ShowToLgdCurrency).toBool()) {
- QDate expiration_date = OPL::Statistics::currencyTakeOffLandingExpiry();
- if (expiration_date <= QDate::currentDate())
- setLabelColour(ui->currToLdgDisplayLabel, Colour::Red);
- ui->currToLdgDisplayLabel->setText(expiration_date.toString(Qt::TextDate));
- } else {
- ui->currToLdgLabel->hide();
- ui->currToLdgDisplayLabel->hide();
- }
-}
-
-/*!
- * \brief HomeWidget::fillLimitations Queries OPL::Statistics to obtain information regarding cumulative
- * Flight Times and Calculates and Notifies about approaching Flight Time Limitations
- */
-void HomeWidget::fillLimitations()
-{
- int minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::Rolling28Days);
- ui->FlightTime28dDisplayLabel->setText(OPL::Time(minutes).toString());
- if (minutes >= ROLLING_28_DAYS) {
- setLabelColour(ui->FlightTime28dDisplayLabel, Colour::Red);
- } else if (minutes >= ROLLING_28_DAYS * ftlWarningThreshold) {
- setLabelColour(ui->FlightTime28dDisplayLabel, Colour::Orange);
- }
-
- minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::Rolling12Months);
- ui->FlightTime12mDisplayLabel->setText(OPL::Time(minutes).toString());
- if (minutes >= ROLLING_12_MONTHS) {
- setLabelColour(ui->FlightTime12mDisplayLabel, Colour::Red);
- } else if (minutes >= ROLLING_12_MONTHS * ftlWarningThreshold) {
- setLabelColour(ui->FlightTime12mDisplayLabel, Colour::Orange);
- }
-
- minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::CalendarYear);
- ui->FlightTimeCalYearDisplayLabel->setText(OPL::Time(minutes).toString());
- if (minutes >= CALENDAR_YEAR) {
- setLabelColour(ui->FlightTimeCalYearDisplayLabel, Colour::Red);
- } else if (minutes >= CALENDAR_YEAR * ftlWarningThreshold) {
- setLabelColour(ui->FlightTimeCalYearDisplayLabel, Colour::Orange);
- }
-}
-
-const QString HomeWidget::getLogbookOwnerName()
+const QString HomeWidget::getLogbookOwnerName() const
{
OPL::PilotEntry owner = DB->getLogbookOwner();
QString name = owner.getFirstName();
if(name.isEmpty()) {
name = owner.getLastName();
}
- DEB << "owner name: " << name;
return name;
}
diff --git a/src/gui/widgets/homewidget.h b/src/gui/widgets/homewidget.h
index 072d5116..e191572c 100644
--- a/src/gui/widgets/homewidget.h
+++ b/src/gui/widgets/homewidget.h
@@ -18,12 +18,12 @@
#ifndef HOMEWIDGET_H
#define HOMEWIDGET_H
+#include "src/opl.h"
#include
#include
#include
#include
#include
-#include "src/database/database.h"
namespace Ui {
class HomeWidget;
@@ -62,10 +62,7 @@ class HomeWidget : public QWidget
double ftlWarningThreshold;
void fillTotals();
- void fillSelectedCurrencies();
- void fillCurrencyTakeOffLanding();
- void fillCurrency(OPL::CurrencyName currency_name, QLabel *display_label);
- void fillLimitations();
+ void fillCurrencies();
enum class Colour {Red, Orange, None};
inline void setLabelColour(QLabel* label, Colour colour)
@@ -94,11 +91,9 @@ class HomeWidget : public QWidget
/*!
* \brief Retreives the users first name from the database.
*/
- const QString getLogbookOwnerName();
+ const QString getLogbookOwnerName() const;
public slots:
- void refresh();
-
void onPilotsDatabaseChanged(const OPL::DbTable table);
protected:
diff --git a/src/gui/widgets/homewidget.ui b/src/gui/widgets/homewidget.ui
index ad35a565..7602d047 100644
--- a/src/gui/widgets/homewidget.ui
+++ b/src/gui/widgets/homewidget.ui
@@ -6,396 +6,24 @@
0
0
- 1087
- 777
+ 670
+ 442
Form
-
- -
-
-
-
-
-
- Flight Time (last 28 days)
-
-
-
- -
-
-
- Qt::LeftToRight
-
-
- 0
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Flight Time (this calendar year)
-
-
-
- -
-
-
- Qt::LeftToRight
-
-
- 0
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Flight Time (last 12 calendar months)
-
-
-
- -
-
-
- Qt::LeftToRight
-
-
- 0
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
- -
-
-
-
-
-
- Take offs (last 90 days)
-
-
-
- -
-
-
-
- true
-
-
-
- Qt::LeftToRight
-
-
- 0
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- Landings (last 90 days)
-
-
-
- -
-
-
-
- true
-
-
-
- Qt::LeftToRight
-
-
- 0
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Take-Off / Landing
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Licence
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Type Rating
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Line Check
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Medical
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Custom1
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
- false
-
-
-
- Custom2
-
-
-
- -
-
-
-
- true
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- true
-
-
-
- Currency
-
-
- Qt::AlignBottom|Qt::AlignHCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
-
- true
-
-
-
- Your Totals
-
-
- Qt::AlignBottom|Qt::AlignHCenter
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
+
-
-
+ [openPilotLog Logo]
Qt::AlignCenter
- -
-
-
- Qt::Horizontal
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
-
@@ -406,27 +34,13 @@
- -
-
-
-
- true
-
-
-
- Limitations
-
-
- Qt::AlignBottom|Qt::AlignHCenter
+
-
+
+
+ -1
- -
-
-
-
-
-
diff --git a/src/gui/widgets/logbooktableeditwidget.cpp b/src/gui/widgets/logbooktableeditwidget.cpp
new file mode 100644
index 00000000..151b4fd8
--- /dev/null
+++ b/src/gui/widgets/logbooktableeditwidget.cpp
@@ -0,0 +1,188 @@
+#include "logbooktableeditwidget.h"
+#include "src/classes/settings.h"
+#include "src/classes/styleddatedelegate.h"
+#include "src/classes/styledpilotdelegate.h"
+#include "src/classes/styledtimedelegate.h"
+#include "src/classes/styledtypedelegate.h"
+#include "src/database/database.h"
+#include "src/database/views/logbookviewinfo.h"
+#include "src/gui/dialogues/newflightdialog.h"
+#include "src/gui/dialogues/newsimdialog.h"
+
+LogbookTableEditWidget::LogbookTableEditWidget(QWidget *parent)
+ : TableEditWidget(Vertical, parent)
+{}
+
+
+// TableEditWidget implementation
+
+void LogbookTableEditWidget::setupModelAndView()
+{
+ m_logbookView = Settings::getLogbookView();
+ m_model = new QSqlTableModel(this, DB->database());
+ m_model->setTable(OPL::GLOBALS->getViewIdentifier(m_logbookView));
+ m_model->select();
+
+ const auto headers = OPL::LogbookViewInfo::getTableHeaders(m_logbookView);
+ for(int i = 0; i < headers.size(); i++) {
+ m_model->setHeaderData(i, Qt::Horizontal, headers[i]);
+ }
+
+ m_view->setModel(m_model);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+ m_view->verticalHeader()->hide();
+ m_view->setAlternatingRowColors(true);
+ m_view->hideColumn(COL_ROWID);
+
+ setupDelegates();
+ m_view->resizeColumnsToContents();
+}
+
+void LogbookTableEditWidget::setupUI()
+{
+ TableEditWidget::setupUI();
+ m_addNewEntryPushButton->setText(tr("Add new Flight"));
+ m_deleteEntryPushButton->setText(tr("Delete selected Entry"));
+ m_filterWidget->hide();
+ m_stackedWidget->hide();
+
+ m_format = Settings::getDisplayFormat();
+}
+
+QString LogbookTableEditWidget::deleteErrorString(int rowId)
+{
+ return tr("
Unable to delete.
The following error has ocurred: %1"
+ ).arg(DB->lastError.text());
+}
+
+QString LogbookTableEditWidget::confirmDeleteString(int rowId)
+{
+ if(rowId > 0) {
+ const auto selectedEntry = DB->getFlightEntry(rowId);
+ return tr("The following flight will be deleted:
"
+ "%1
"
+ "Deleting flights is irreversible.
Do you want to proceed?"
+ ).arg(selectedEntry.getFlightSummary());
+
+ }
+
+ return tr("Deleting entries is irreversible.
Do you want to proceed?");
+}
+
+EntryEditDialog *LogbookTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+ return new NewFlightDialog(parent);
+}
+
+void LogbookTableEditWidget::filterTextChanged(const QString &filterString)
+{}
+
+void LogbookTableEditWidget::editEntryRequested(const QModelIndex &selectedIndex)
+{
+ showEditWidget();
+ const auto idx = m_view->selectionModel()->currentIndex();
+ const auto rowId = m_model->index(idx.row(), 0).data().toInt();
+ if(rowId > 0) {
+ auto nfd = NewFlightDialog(rowId, this);
+ m_stackedWidget->addWidget(&nfd);
+ m_stackedWidget->setCurrentWidget(&nfd);
+ nfd.exec();
+ } else {
+ auto nsd = NewSimDialog(rowId * -1, this);
+ m_stackedWidget->addWidget(&nsd);
+ m_stackedWidget->setCurrentWidget(&nsd);
+ nsd.exec();
+ }
+ hideEditWidget();
+}
+
+void LogbookTableEditWidget::deleteEntryRequested()
+{
+ const QModelIndex selectedIndex = m_view->selectionModel()->currentIndex();
+ if(!selectedIndex.isValid()) {
+ WARN(tr("No entry selected."));
+ return;
+ }
+ m_stackedWidget->hide();
+
+ int rowId = m_model->index(selectedIndex.row(), 0).data().toInt();
+ m_view->selectionModel()->reset();
+
+ // get user confirmation
+ QMessageBox confirm(this);
+ confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ confirm.setDefaultButton(QMessageBox::No);
+ confirm.setIcon(QMessageBox::Question);
+ confirm.setWindowTitle(tr("Confirm Deletion"));
+
+ confirm.setText(confirmDeleteString(rowId));
+ if (confirm.exec() == QMessageBox::Yes) {
+ if(rowId > 0) {
+ const auto selectedEntry = DB->getFlightEntry(rowId);
+ if(!DB->remove(selectedEntry))
+ WARN(deleteErrorString(rowId));
+ } else {
+ const auto selectedEntry = DB->getSimEntry(rowId * - 1);
+ if(!DB->remove(selectedEntry))
+ WARN(deleteErrorString(rowId));
+ }
+ }
+}
+
+// private implementations
+
+void LogbookTableEditWidget::addSimulatorEntryRequested()
+{
+ showEditWidget();
+
+ auto nsd = NewSimDialog(this);
+ m_stackedWidget->addWidget(&nsd);
+ m_stackedWidget->setCurrentWidget(&nsd);
+ nsd.exec();
+
+ hideEditWidget();
+}
+
+void LogbookTableEditWidget::viewSelectionChanged(SettingsWidget::SettingSignal widget)
+{
+ for(auto i = m_defaultDelegates.constBegin(); i != m_defaultDelegates.constEnd(); i++) {
+ m_view->setItemDelegateForColumn(i.key(), i.value());
+ // should probably delete the old custom delegate, Qt docs say the
+ // view does not take ownership of the delegates so they might be leaking
+ // https://doc.qt.io/qt-6/qabstractitemdelegate.html
+ }
+
+ if(widget == SettingsWidget::SettingSignal::LogbookWidget)
+ setupModelAndView();
+}
+
+void LogbookTableEditWidget::setupDelegates()
+{
+ // minutes to hh:mm
+ const auto timeDelegate = new StyledTimeDelegate(m_format, m_model);
+ for(const auto col : OPL::LogbookViewInfo::getTimeColumns(m_logbookView)) {
+ m_defaultDelegates.insert(col, m_view->itemDelegateForColumn(col));
+ m_view->setItemDelegateForColumn(col, timeDelegate);
+ }
+
+ // julian day to Date Format
+ const int dateCol = OPL::LogbookViewInfo::getDateColumn(m_logbookView);
+ const auto dateDelegate = new StyledDateDelegate(Settings::getDisplayFormat(), m_model);
+ m_defaultDelegates.insert(dateCol, m_view->itemDelegateForColumn(dateCol));
+ m_view->setItemDelegateForColumn(dateCol, dateDelegate);
+
+ // pilot_id to names
+ const int pilCol = OPL::LogbookViewInfo::getPicColumn(m_logbookView);
+ const auto pilotDelegate = new StyledPilotDelegate(m_model);
+ m_defaultDelegates.insert(pilCol, m_view->itemDelegateForColumn(pilCol));
+ m_view->setItemDelegateForColumn(pilCol, pilotDelegate);
+
+ // tail_id to aircraft type and registration
+ const int typeCol = OPL::LogbookViewInfo::getTypeColumn(m_logbookView);
+ const auto typeDelegate = new StyledTypeDelegate(m_model);
+ m_defaultDelegates.insert(typeCol, m_view->itemDelegateForColumn(typeCol));
+ m_view->setItemDelegateForColumn(typeCol, typeDelegate);
+}
diff --git a/src/gui/widgets/logbooktableeditwidget.h b/src/gui/widgets/logbooktableeditwidget.h
new file mode 100644
index 00000000..365ef0f0
--- /dev/null
+++ b/src/gui/widgets/logbooktableeditwidget.h
@@ -0,0 +1,67 @@
+#ifndef LOGBOOKTABLEEDITWIDGET_H
+#define LOGBOOKTABLEEDITWIDGET_H
+
+#include "settingswidget.h"
+#include "tableeditwidget.h"
+#include "src/opl.h"
+#include
+
+/*!
+ * \brief The LogbookTableEditWidget allows editing of logbook entries.
+ *
+ * \details This widget differs from the other TableEditWidget implementations in that
+ * instead of a table, it uses a [view](https://sqlite.org/lang_createview.html) as the source of the display model.
+ *
+ * The user can select a view from a list of available views in the SettingsWidget.
+ *
+ * Some of the selectable views aggregate data from the flights and simulators table. In those views, flight
+ * entries have positive row id's whereas the simulators have inverse (negative) row id's. This necessitates
+ * checking the row id's value before deciding on the apropriate EntryEditDialog.
+ */
+class LogbookTableEditWidget : public TableEditWidget
+{
+ Q_OBJECT
+public:
+ LogbookTableEditWidget() = delete;
+ explicit LogbookTableEditWidget(QWidget *parent = nullptr);
+
+private:
+ OPL::LogbookView m_logbookView;
+ OPL::DateTimeFormat m_format;
+
+ /*!
+ * \brief Set up the QStyledItemDelegate instances that transform the database values to user-readable values.
+ */
+ void setupDelegates();
+
+ static constexpr int COL_ROWID = 0;
+
+ // keep track of default and custom delegates set on certain columns
+ QHash m_defaultDelegates;
+
+ // TableEditWidget interface
+public:
+ virtual void setupModelAndView() override;
+ virtual void setupUI() override;
+ virtual QString deleteErrorString(int rowId) override;
+ virtual QString confirmDeleteString(int rowId) override;
+ virtual EntryEditDialog *getEntryEditDialog(QWidget *parent) override;
+
+public slots:
+ void viewSelectionChanged(SettingsWidget::SettingSignal widget);
+
+public slots:
+ virtual void filterTextChanged(const QString &filterString) override;
+
+ virtual void editEntryRequested(const QModelIndex &selectedIndex) override;
+ virtual void deleteEntryRequested() override;
+
+ /*!
+ * \brief add a new Simulator Entry to the datbase
+ * \details The Primary Entry handled by the LogbookTableEditWidget are Flights, which are stored in the flights table.
+ * However, this widget also handles adding simulator tables which are stored in the simulators table.
+ */
+ void addSimulatorEntryRequested();
+};
+
+#endif // LOGBOOKTABLEEDITWIDGET_H
diff --git a/src/gui/widgets/logbookwidget.cpp b/src/gui/widgets/logbookwidget.cpp
deleted file mode 100644
index 934df9e8..00000000
--- a/src/gui/widgets/logbookwidget.cpp
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2023 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 "src/classes/time.h"
-#include "src/database/database.h"
-#include "logbookwidget.h"
-#include "ui_logbookwidget.h"
-#include "src/database/row.h"
-#include "src/database/database.h"
-#include "src/classes/settings.h"
-#include "src/gui/dialogues/newflightdialog.h"
-#include "src/gui/dialogues/newsimdialog.h"
-
-LogbookWidget::LogbookWidget(QWidget *parent) :
- QWidget(parent),
- ui(new Ui::LogbookWidget)
-{
- ui->setupUi(this);
-
- OPL::GLOBALS->fillViewNamesComboBox(ui->viewsComboBox);
-
- //customContextMenu for tablewidget
- menu = new QMenu(this);
- menu->addAction(ui->actionEdit_Flight);
- menu->addAction(ui->actionDelete_Flight);
-
- // Initalise the display Model and view
- displayModel = new QSqlTableModel(this);
- view = ui->tableView;
-
- setupModelAndView(Settings::read(Settings::Main::LogbookView).toInt());
- connectSignalsAndSlots();
-
-}
-
-LogbookWidget::~LogbookWidget()
-{
- delete ui;
-}
-
-/*
- * Functions
- */
-
-/*!
- * \brief LogbookWidget::setupModelAndView configures the QTableView and populates the model with data
- * according to the current view.
- * \param view_id - retreived from Settings::Main::LogbookView
- */
-void LogbookWidget::setupModelAndView(int view_id)
-{
- displayModel->setTable(OPL::GLOBALS->getViewIdentifier(OPL::DbViewName(view_id)));
- displayModel->select();
-
- view->setModel(displayModel);
- view->setSelectionBehavior(QAbstractItemView::SelectRows);
- view->setSelectionMode(QAbstractItemView::ExtendedSelection);
- view->setEditTriggers(QAbstractItemView::NoEditTriggers);
- view->setContextMenuPolicy(Qt::CustomContextMenu);
- view->resizeColumnsToContents();
- view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
- view->verticalHeader()->hide();
- view->setAlternatingRowColors(true);
- view->hideColumn(0);
- view->show();
-}
-
-void LogbookWidget::connectSignalsAndSlots()
-{
- selectionModel = view->selectionModel();
- QObject::connect(view->selectionModel(), &QItemSelectionModel::selectionChanged,
- this, &LogbookWidget::flightsTableView_selectionChanged);
-}
-
-const QString LogbookWidget::getFlightSummary(const OPL::FlightEntry &flight) const
-{
- if(!flight.isValid())
- return QString();
-
- auto tableData = flight.getData();
- QString flight_summary;
- auto space = QLatin1Char(' ');
- flight_summary.append(tableData.value(OPL::FlightEntry::DOFT).toString() + space);
- flight_summary.append(tableData.value(OPL::FlightEntry::DEPT).toString() + space);
- flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TOFB).toInt()).toString()
- + space);
- flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TONB).toInt()).toString()
- + space);
- flight_summary.append(tableData.value(OPL::FlightEntry::DEST).toString());
-
- return flight_summary;
-}
-
-void LogbookWidget::changeEvent(QEvent *event)
-{
- if (event != nullptr)
- if(event->type() == QEvent::LanguageChange)
- ui->retranslateUi(this);
-}
-
-/*!
- * \brief LogbookWidget::flightsTableView_selectionChanged saves the selected row(s)
- * to the selectedFlights member variable.
- */
-void LogbookWidget::flightsTableView_selectionChanged()
-{
- selectedEntries.clear();
- for (const auto& row : selectionModel->selectedRows()) {
- selectedEntries.append(row.data().toInt());
- DEB << "Selected Flight(s) with ID: " << selectedEntries;
- }
- if (selectedEntries.length() == 1) {
- if (isFlight(selectedEntries.first()))
- on_actionEdit_Flight_triggered();
- else
- on_actionEdit_Sim_triggered();
- }
-}
-
-/*!
- * \brief If a row is selected, query information
- * about the affected row(s) and ask the user to confirm deletion.
- */
-void LogbookWidget::on_actionDelete_Flight_triggered()
-{
- DEB << "Flights selected: " << selectedEntries.length();
- if (selectedEntries.length() == 0) {
- WARN(tr("
No flight selected.
"));
- return;
- } else if (selectedEntries.length() > 0 && selectedEntries.length() <= 10) {
- QVector flights_list;
-
- for (const auto &flight_id : qAsConst(selectedEntries)) {
- flights_list.append(DB->getFlightEntry(flight_id));
- }
-
- QString flights_list_string;
-
- for (auto &flight : flights_list) {
- flights_list_string.append(getFlightSummary(flight));
- flights_list_string.append(QStringLiteral("
"));
- }
-
- QMessageBox confirm(this);
- confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- confirm.setDefaultButton(QMessageBox::No);
- confirm.setIcon(QMessageBox::Question);
- confirm.setWindowTitle("Delete Flight");
- confirm.setText(tr("The following flight(s) will be deleted:
"
- "%1
"
- "Deleting flights is irreversible.
Do you want to proceed?"
- ).arg(flights_list_string));
- if (confirm.exec() == QMessageBox::Yes) {
- for (auto& flight : flights_list) {
- DEB << "Deleting flight: " << flight;
- if(!DB->remove(flight)) {
- WARN(tr("
Unable to delete.
The following error has ocurred: %1"
- ).arg(DB->lastError.text()));
- return;
- }
- }
- INFO(tr("%1 flights have been deleted successfully."
- ).arg(QString::number(selectedEntries.length())));
- displayModel->select();
- }
- } else if (selectedEntries.length() > 10) {
- QMessageBox confirm;
- confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
- confirm.setDefaultButton(QMessageBox::No);
- confirm.setIcon(QMessageBox::Warning);
- confirm.setWindowTitle("Delete Flight");
- confirm.setText(tr("You have selected %1 flights.
"
- "Deleting flights is irreversible.
"
- "Are you sure you want to proceed?"
- ).arg(QString::number(selectedEntries.length())));
- if(confirm.exec() == QMessageBox::Yes) {
- if (!DB->removeMany(OPL::DbTable::Flights, selectedEntries)) {
- WARN(tr("Unable to delete. No changes have been made to the database. The following error has ocurred:
%1").arg(DB->lastError.text()));
- return;
- }
- INFO(tr("%1 flights have been deleted successfully."
- ).arg(QString::number(selectedEntries.length())));
- displayModel->select();
- }
- displayModel->select();
- }
-}
-
-
-void LogbookWidget::on_tableView_customContextMenuRequested(const QPoint &pos)
-{
- menu->popup(ui->tableView->viewport()->mapToGlobal(pos));
-}
-
-void LogbookWidget::on_tableView_doubleClicked()
-{
- on_actionEdit_Flight_triggered();
-}
-
-void LogbookWidget::on_flightSearchComboBox_currentIndexChanged(int)
-{
- //emit ui->showAllButton->clicked();
-}
-
-/*!
- * \brief LogbookWidget::refresh Refreshes the view to reflect changes in the database.
- */
-void LogbookWidget::refresh()
-{
- displayModel->select();
- view->resizeColumnsToContents();
-}
-
-void LogbookWidget::onLogbookWidget_viewSelectionChanged(SettingsWidget::SettingSignal signal)
-{
- if (signal == SettingsWidget::SettingSignal::LogbookWidget)
- setupModelAndView(Settings::read(Settings::Main::LogbookView).toInt());
-}
-
-//void LogbookWidget::on_showAllButton_clicked()
-//{
-// ui->flightSearchLlineEdit->setText(QString());
-// displayModel->setFilter(QString());
-// displayModel->select();
-//}
-
-/*!
- * \brief LogbookWidget::on_flightSearchLlineEdit_textChanged applies a filter to the
- * display model allowing the user to search for flights by specified elements (date, aircraft,
- * Pilot Name)
- */
-void LogbookWidget::on_flightSearchLlineEdit_textChanged(const QString &arg1)
-{
- if(arg1.length() == 0) {
- displayModel->setFilter("");
- displayModel->select();
- return;
- }
-
- if (ui->flightSearchComboBox->currentIndex() < 3) {
- displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
- + arg1 + QLatin1String("%\""));
- return;
- } else if (ui->flightSearchComboBox->currentIndex() == 3) { // registration
- displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
- + arg1 + QLatin1String("%\""));
- return;
- } else if (ui->flightSearchComboBox->currentIndex() == 4) { // Name Pic
- displayModel->setFilter(FILTER_MAP.value(ui->flightSearchComboBox->currentIndex())
- + arg1 + QLatin1String("%\""));
- return;
- }
-}
-
-/*!
- * \brief LogbookWidget::repopulateModel (public slot) - cleanly re-populates the model to cater for a change
- * to the database connection (for example, when a backup is created or restored)
- */
-void LogbookWidget::repopulateModel()
-{
- // unset the current model and delete it to avoid leak
- view->setModel(nullptr);
- delete displayModel;
- // create a new model and populate it
- displayModel = new QSqlTableModel(this);
- setupModelAndView(Settings::read(Settings::Main::LogbookView).toInt());
- connectSignalsAndSlots();
-}
-
-void LogbookWidget::on_viewsComboBox_currentIndexChanged(int index)
-{
- setupModelAndView(index);
-}
-
-void LogbookWidget::on_actionEdit_Flight_triggered()
-{
- if(selectedEntries.length() == 1){
- NewFlightDialog nff(selectedEntries.first(), this);
- ui->stackedWidget->addWidget(&nff);
- ui->stackedWidget->setCurrentWidget(&nff);
- nff.setWindowFlag(Qt::Widget);
- nff.exec();
- displayModel->select();
- } else if (selectedEntries.isEmpty()) {
- WARN(tr("
No flight selected.
"));
- } else {
- WARN(tr("
More than one flight selected."
- "
Editing multiple entries is not yet supported."));
- }
-}
-
-void LogbookWidget::on_actionEdit_Sim_triggered()
-{
- if (selectedEntries.length() == 1) {
- NewSimDialog nsd((selectedEntries.first() * -1), this); // simulator entries have inverse row ID's in the model
- ui->stackedWidget->addWidget(&nsd);
- ui->stackedWidget->setCurrentWidget(&nsd);
- nsd.setWindowFlag(Qt::Widget);
- nsd.exec();
- displayModel->select();
- } else if (selectedEntries.isEmpty()) {
- WARN(tr("
No flight selected.
"));
- } else {
- WARN(tr("
More than one flight selected."
- "
Editing multiple entries is not yet supported."));
- }
-}
-
diff --git a/src/gui/widgets/logbookwidget.h b/src/gui/widgets/logbookwidget.h
deleted file mode 100644
index 4bdaaaae..00000000
--- a/src/gui/widgets/logbookwidget.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2023 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 .
- */
-#ifndef LOGBOOKWIDGET_H
-#define LOGBOOKWIDGET_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "src/database/flightentry.h"
-#include "src/gui/widgets/settingswidget.h"
-
-namespace Ui {
-class LogbookWidget;
-}
-
-/*!
- * \brief The LogbookWidget displays data from the database in a QSqlTableView fed by a QSqlQuery Model
- *
- * \details The LogbookWidget is the primary display interface for flights logged in the database. It fetches and stores
- * flight data from the database via a QSqlQueryModel and displays it in a QTableView. With the way the flight data is
- * written in the database, it would not be human-readable, so some processing is done on the database side to present
- * a nicely formatted, human-readable display. This is achieved by means of a [SQL View](https://sqlite.org/lang_createview.html).
- *
- * The user can select a view from a list of available views in the SettingsWidget.
- *
- */
-class LogbookWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit LogbookWidget(QWidget *parent = nullptr);
- ~LogbookWidget();
-
-private slots:
- void flightsTableView_selectionChanged();
- void on_tableView_customContextMenuRequested(const QPoint &pos);
- void on_actionDelete_Flight_triggered();
-
- void on_tableView_doubleClicked();
- void on_flightSearchLlineEdit_textChanged(const QString &arg1);
- void on_flightSearchComboBox_currentIndexChanged(int);
-
- void on_viewsComboBox_currentIndexChanged(int index);
-
- void on_actionEdit_Flight_triggered();
- void on_actionEdit_Sim_triggered();
-
-public slots:
- void refresh();
- void onLogbookWidget_viewSelectionChanged(SettingsWidget::SettingSignal signal);
- void repopulateModel();
-
-private:
- Ui::LogbookWidget *ui;
-
- QTableView* view;
-
- QSqlTableModel* displayModel;
-
- QItemSelectionModel* selectionModel;
-
- QMenu* menu;
-
- QList selectedEntries;
-
- void setupModelAndView(int view_id);
- void connectSignalsAndSlots();
-
- const QString getFlightSummary(const OPL::FlightEntry &flight) const;
-
- /*!
- * \brief isFlight Determines whether an entry shown in a view is a Flight or a Simulator.
- * \param model_row_id the row id in the QSqlTableModel used for displaying
- * \details In the composite views (SQL UNION) with Simulators included, the row_id of the
- * simulator entries is inverted to a negative value. A positive row id is thus a row id from
- * the flights table, whereas a negative rowid is a row id from the simulators table.
- */
- inline bool isFlight(int model_row_id) { return model_row_id > 0; }
-
- const static inline QHash FILTER_MAP = {
- {0, QStringLiteral("Date LIKE \"%")},
- {1, QStringLiteral("Dept LIKE \"%")},
- {2, QStringLiteral("Dest LIKE \"%")},
- {3, QStringLiteral("Registration LIKE \"%")},
- {4, QStringLiteral("\"Name PIC\" LIKE \"%")}
- };
- const static inline QRegularExpression NON_WORD_CHAR = QRegularExpression("\\W");
-
-protected:
- /*!
- * \brief Handles change events, like updating the UI to new localisation
- */
- void changeEvent(QEvent* event) override;
-};
-
-#endif // LOGBOOKWIDGET_H
diff --git a/src/gui/widgets/logbookwidget.ui b/src/gui/widgets/logbookwidget.ui
deleted file mode 100644
index 7733c6be..00000000
--- a/src/gui/widgets/logbookwidget.ui
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
- LogbookWidget
-
-
-
- 0
- 0
- 1280
- 720
-
-
-
- Form
-
-
- -
-
-
-
-
-
-
-
-
- QAbstractItemView::SingleSelection
-
-
- QAbstractItemView::SelectRows
-
-
-
- -
-
-
-
-
-
-
-
-
- 200
- 0
-
-
-
- Search Flight
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
- <html><head/><body><p>Enter the searchterm you want to filter your flights by.</p><p>For dates, make sure to use the format YYYY-MM-DD</p></body></html>
-
-
- <html><head/><body><p><br/></p></body></html>
-
-
-
- -
-
-
-
- 200
- 0
-
-
-
- Search by
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
- -
-
-
-
-
- Date of Flight
-
-
- -
-
- Departure Airport
-
-
- -
-
- Destination Airport
-
-
- -
-
- Aircraft Registration
-
-
- -
-
- Pilot Name
-
-
-
-
- -
-
-
- Select a Flight from the list to show or edit details.
-
-
- Qt::AlignCenter
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
- 284
- 410
- 200
- 16
-
-
-
-
- 200
- 0
-
-
-
-
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
- Edit Flight
-
-
-
-
- Delete Flight
-
-
-
-
- Edit_Sim
-
-
- Edit an existing Simulator Entry
-
-
-
-
-
-
diff --git a/src/gui/widgets/pilottableeditwidget.cpp b/src/gui/widgets/pilottableeditwidget.cpp
new file mode 100644
index 00000000..0bf9fa5e
--- /dev/null
+++ b/src/gui/widgets/pilottableeditwidget.cpp
@@ -0,0 +1,112 @@
+#include "pilottableeditwidget.h"
+#include "src/database/database.h"
+#include "src/gui/dialogues/entryeditdialog.h"
+#include "src/gui/dialogues/newpilotdialog.h"
+#include "src/opl.h"
+#include
+
+PilotTableEditWidget::PilotTableEditWidget(QWidget *parent)
+ : TableEditWidget(Horizontal, parent)
+{}
+
+void PilotTableEditWidget::setupModelAndView()
+{
+ m_model = new QSqlTableModel(this, DB->database());
+ m_model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Pilots));
+ m_model->select();
+ m_model->setHeaderData(COL_LASTNAME, Qt::Horizontal, tr("Last Name"));
+ m_model->setHeaderData(COL_FIRSTNAME, Qt::Horizontal, tr("First Name"));
+ m_model->setHeaderData(COL_COMPANY, Qt::Horizontal, tr("Company"));
+ m_model->setFilter(QStringLiteral("%1 > 1").arg(OPL::PilotEntry::ROWID)); // hide self
+
+ m_view->setModel(m_model);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+ m_view->resizeColumnsToContents();
+ m_view->verticalHeader()->hide();
+ m_view->setAlternatingRowColors(true);
+ for(const int i : COLS_TO_HIDE)
+ m_view->hideColumn(i);
+
+}
+
+void PilotTableEditWidget::setupUI()
+{
+ // the base class does most of the setup
+ TableEditWidget::setupUI();
+
+ // only need to set the table specific labels and combo box items
+ m_addNewEntryPushButton->setText(tr("Add New Pilot"));
+ m_deleteEntryPushButton->setText(tr("Delete Selected Pilot"));
+ m_filterSelectionComboBox->addItems(FILTER_COLUMNS);
+}
+
+EntryEditDialog *PilotTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+ return new NewPilotDialog(QString(), parent);
+}
+
+QString PilotTableEditWidget::deleteErrorString(int pilotId)
+{
+ const QList foreign_key_constraints = DB->getForeignKeyConstraints(pilotId,
+ OPL::DbTable::Pilots);
+ QList constrained_flights;
+ for (const auto &row_id : foreign_key_constraints) {
+ constrained_flights.append(DB->getFlightEntry(row_id));
+ }
+
+ // the error is a database error
+ if (constrained_flights.isEmpty()) {
+ return(tr("
Unable to delete.
The following error has ocurred:
%1"
+ ).arg(DB->lastError.text()));
+ } else {
+ // the error is a foreign key constraint
+ QString constrained_flights_string;
+ for (int i=0; i"));
+ if (i>10) {
+ constrained_flights_string.append("
[...]
");
+ break;
+ }
+ }
+ return(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));
+ }
+}
+
+QString PilotTableEditWidget::confirmDeleteString(int rowId)
+{
+ const auto entry = DB->getPilotEntry(rowId);
+ return tr("You are deleting the following pilot:
"
+ "%1, %2
Are you sure?").arg(entry.getLastName(), entry.getFirstName());
+}
+
+void PilotTableEditWidget::filterTextChanged(const QString &filterText)
+{
+ if(filterText.isEmpty()) {
+ m_model->setFilter(QStringLiteral("%1 > 1").arg(OPL::PilotEntry::ROWID)); // hide self
+ return;
+ }
+
+ int i = m_filterSelectionComboBox->currentIndex();
+ const QString filter =
+ QLatin1Char('\"')
+ + FILTER_COLUMN_NAMES.at(i)
+ + QLatin1String("\" LIKE '%")
+ + filterText
+ + QLatin1String("%' AND ")
+ + OPL::PilotEntry::ROWID
+ + QLatin1String(" > 1");
+ m_model->setFilter(filter);
+}
+
+
diff --git a/src/gui/widgets/pilottableeditwidget.h b/src/gui/widgets/pilottableeditwidget.h
new file mode 100644
index 00000000..e45fc4bd
--- /dev/null
+++ b/src/gui/widgets/pilottableeditwidget.h
@@ -0,0 +1,52 @@
+#ifndef PILOTTABLEEDITWIDGET_H
+#define PILOTTABLEEDITWIDGET_H
+
+#include "tableeditwidget.h"
+#include "src/database/pilotentry.h"
+
+class PilotTableEditWidget : public TableEditWidget
+{
+ Q_OBJECT
+public:
+ PilotTableEditWidget(QWidget *parent = nullptr);
+
+ virtual void setupModelAndView() override;
+ virtual void setupUI() override;
+ virtual EntryEditDialog *getEntryEditDialog(QWidget *parent = nullptr) override;
+
+
+private:
+ static constexpr int COL_ROWID = 0;
+ static constexpr int COL_LASTNAME = 1;
+ static constexpr int COL_FIRSTNAME = 2;
+ static constexpr int COL_COMPANY = 4;
+ static constexpr int COLS_TO_HIDE[5] = {0, 3, 5, 6, 7};
+
+ const QString COLUMN_1_NAME = tr("First Name");
+ const QString COLUMN_2_NAME = tr("Last Name");
+ const QString COLUMN_3_NAME = tr("Company");
+
+ const QStringList FILTER_COLUMNS = { COLUMN_1_NAME, COLUMN_2_NAME, COLUMN_3_NAME };
+ const static inline QStringList FILTER_COLUMN_NAMES = {
+ OPL::PilotEntry::FIRSTNAME,
+ OPL::PilotEntry::LASTNAME,
+ OPL::PilotEntry::COMPANY };
+
+ /*!
+ * \brief Informs the user that deleting a Pilot 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.
+ */
+ virtual QString deleteErrorString(int pilotId) override;
+
+ virtual QString confirmDeleteString(int rowId) override;
+
+private slots:
+ virtual void filterTextChanged(const QString &filterText) override;
+};
+
+#endif // PILOTTABLEEDITWIDGET_H
diff --git a/src/gui/widgets/settingswidget.cpp b/src/gui/widgets/settingswidget.cpp
index 45cf4a21..e65bfc61 100644
--- a/src/gui/widgets/settingswidget.cpp
+++ b/src/gui/widgets/settingswidget.cpp
@@ -23,7 +23,6 @@
#include "src/classes/settings.h"
#include "src/database/database.h"
#include "src/opl.h"
-#include "src/functions/datetime.h"
#include "src/gui/widgets/backupwidget.h"
SettingsWidget::SettingsWidget(QWidget *parent) :
@@ -36,7 +35,6 @@ SettingsWidget::SettingsWidget(QWidget *parent) :
loadBackupWidget();
loadPreviousExperienceWidget();
setupComboBoxes();
- setupDateEdits();
setupValidators();
readSettings();
}
@@ -62,41 +60,9 @@ void SettingsWidget::setupComboBoxes(){
OPL::GLOBALS->loadPilotFunctios(ui->functionComboBox);
OPL::GLOBALS->fillViewNamesComboBox(ui->logbookViewComboBox);
OPL::GLOBALS->fillLanguageComboBox(ui->languageComboBox);
- }
-}
-
-void SettingsWidget::setupDateEdits()
-{
- // Read Display Format Setting
- int date_format_index = Settings::read(Settings::Main::DateFormat).toInt();
- const QString date_format_string = OPL::DateTime::getFormatString(
- static_cast(date_format_index));
- const auto date_edits = this->findChildren();
- for (const auto &date_edit : date_edits) {
- date_edit->setDisplayFormat(date_format_string);
- }
- // Fill currencies
- const QList> currencies_list = {
- {OPL::CurrencyName::Licence, ui->currLicDateEdit},
- {OPL::CurrencyName::TypeRating, ui->currTrDateEdit},
- {OPL::CurrencyName::LineCheck, ui->currLckDateEdit},
- {OPL::CurrencyName::Medical, ui->currMedDateEdit},
- {OPL::CurrencyName::Custom1, ui->currCustom1DateEdit},
- {OPL::CurrencyName::Custom2, ui->currCustom2DateEdit},
- };
- for (const auto &pair : currencies_list) {
- const QSignalBlocker signal_blocker(pair.second);
- const auto entry = DB->getCurrencyEntry(static_cast(pair.first));
- if (entry.isValid()) { // set date
- const auto date = QDate::fromString(
- entry.getData().value(OPL::CurrencyEntry::EXPIRYDATE).toString(),
- Qt::ISODate);
- if(date.isValid())
- pair.second->setDate(date);
- } else { // set current date
- pair.second->setDate(QDate::currentDate());
- }
+ // Set up the currency warning threshold spin box
+ ui->currencyWarningDaysSpinBox->setValue(Settings::getCurrencyWarningThreshold());
}
}
@@ -135,29 +101,18 @@ void SettingsWidget::readSettings()
ui->emailLineEdit->setText(user_data.value(OPL::PilotEntry::EMAIL).toString());
// FLight Logging Tab
- ui->functionComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Function).toInt());
- ui->rulesComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::LogIFR).toInt());
- ui->approachComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Approach).toInt());
- ui->nightComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::NightLoggingEnabled).toInt());
- ui->prefixLineEdit->setText(Settings::read(Settings::FlightLogging::FlightNumberPrefix).toString());
-
- ui->logbookViewComboBox->setCurrentIndex(Settings::read(Settings::Main::LogbookView).toInt());
- ui->aliasComboBox->setCurrentIndex(Settings::read(Settings::UserData::DisplaySelfAs).toInt());
-
- // Currencies Tab
- ui->currToLdgCheckBox->setChecked(Settings::read(Settings::UserData::ShowToLgdCurrency).toBool());
- ui->currLicCheckBox->setChecked(Settings::read(Settings::UserData::ShowLicCurrency).toBool());
- ui->currTrCheckBox->setChecked(Settings::read(Settings::UserData::ShowTrCurrency).toBool());
- ui->currLckCheckBox->setChecked(Settings::read(Settings::UserData::ShowLckCurrency).toBool());
- ui->currMedCheckBox->setChecked(Settings::read(Settings::UserData::ShowMedCurrency).toBool());
- ui->currCustom1CheckBox->setChecked(Settings::read(Settings::UserData::ShowCustom1Currency).toBool());
- ui->currCustom2CheckBox->setChecked(Settings::read(Settings::UserData::ShowCustom2Currency).toBool());
- ui->currCustom1LineEdit->setText(Settings::read(Settings::UserData::Custom1CurrencyName).toString());
- ui->currCustom2LineEdit->setText(Settings::read(Settings::UserData::Custom2CurrencyName).toString());
+ ui->functionComboBox->setCurrentIndex(static_cast(Settings::getPilotFunction()));
+ ui->rulesComboBox->setCurrentIndex(Settings::getLogIfr());
+ ui->approachComboBox->setCurrentText(Settings::getApproachType());
+ ui->nightComboBox->setCurrentIndex(Settings::getNightLoggingEnabled());
+ ui->prefixLineEdit->setText(Settings::getFlightNumberPrefix());
+
+ ui->logbookViewComboBox->setCurrentIndex(static_cast(Settings::getLogbookView()));
+ ui->aliasComboBox->setCurrentIndex(Settings::getShowSelfAs());
// Misc Tab
- ui->acftSortComboBox->setCurrentIndex(Settings::read(Settings::UserData::TailSortColumn).toInt());
- ui->pilotSortComboBox->setCurrentIndex(Settings::read(Settings::UserData::PilotSortColumn).toInt());
+ ui->acftSortComboBox->setCurrentIndex(Settings::getTailSortColumn());
+ ui->pilotSortComboBox->setCurrentIndex(Settings::getPilotSortColumn());
// Don't emit signals for OPL::Style changes during setup
const QSignalBlocker style_blocker(ui->styleComboBox);
@@ -165,10 +120,10 @@ void SettingsWidget::readSettings()
const QSignalBlocker font_blocker_2(ui->fontComboBox);
const QSignalBlocker font_blocker_3(ui->fontCheckBox);
- ui->styleComboBox->setCurrentText(Settings::read(Settings::Main::Style).toString());
- ui->fontSpinBox->setValue(Settings::read(Settings::Main::FontSize).toUInt());
- ui->fontComboBox->setCurrentFont(QFont(Settings::read(Settings::Main::Font).toString()));
- bool use_system_font = Settings::read(Settings::Main::UseSystemFont).toBool();
+ ui->styleComboBox->setCurrentText(Settings::getApplicationStyle());
+ ui->fontSpinBox->setValue(Settings::getApplicationFontSize());
+ ui->fontComboBox->setCurrentFont(QFont(Settings::getApplicationFontName()));
+ bool use_system_font = Settings::getUseSystemFont();
ui->fontCheckBox->setChecked(use_system_font);
if (!use_system_font) {
ui->fontComboBox->setEnabled(true);
@@ -179,7 +134,6 @@ void SettingsWidget::readSettings()
void SettingsWidget::setupValidators()
{
ui->phoneLineEdit->setValidator(new QRegularExpressionValidator(OPL::RegEx::RX_PHONE_NUMBER, ui->phoneLineEdit));
- ui->emailLineEdit->setValidator(new QRegularExpressionValidator(OPL::RegEx::RX_EMAIL_ADDRESS, ui->emailLineEdit));
}
/*!
@@ -262,44 +216,43 @@ void SettingsWidget::on_phoneLineEdit_editingFinished()
void SettingsWidget::on_aliasComboBox_currentIndexChanged(int index)
{
- Settings::write(Settings::UserData::DisplaySelfAs, index);
+ Settings::setShowSelfAs(index);
updatePersonalDetails();
}
void SettingsWidget::on_functionComboBox_currentIndexChanged(int arg1)
{
- Settings::write(Settings::FlightLogging::Function, arg1);
+ Settings::setPilotFunction(OPL::PilotFunction(arg1));
}
void SettingsWidget::on_rulesComboBox_currentIndexChanged(int arg1)
{
- Settings::write(Settings::FlightLogging::LogIFR, arg1);
+ Settings::setLogIfr(arg1);
}
void SettingsWidget::on_approachComboBox_currentIndexChanged(int arg1)
{
- Settings::write(Settings::FlightLogging::Approach, arg1);
+ Settings::setApproachType(ui->approachComboBox->currentText());
}
void SettingsWidget::on_nightComboBox_currentIndexChanged(int index)
{
- Settings::write(Settings::FlightLogging::NightLoggingEnabled, index);
+ Settings::setNightLoggingEnabled(index);
switch (index) {
case 1:
- Settings::write(Settings::FlightLogging::NightAngle, -6);
+ Settings::setNightAngle(-6);
break;
case 2:
- Settings::write(Settings::FlightLogging::NightAngle, 0);
+ Settings::setNightAngle(0);
break;
default:
- Settings::write(Settings::FlightLogging::NightAngle, -6);
+ Settings::setNightAngle(-6);
}
}
void SettingsWidget::on_prefixLineEdit_textChanged(const QString &arg1)
{
- Settings::write(Settings::FlightLogging::FlightNumberPrefix, arg1);
-
+ Settings::setFlightNumberPrefix(arg1);
}
/*
@@ -308,18 +261,19 @@ void SettingsWidget::on_prefixLineEdit_textChanged(const QString &arg1)
void SettingsWidget::on_logbookViewComboBox_currentIndexChanged(int index)
{
- Settings::write(Settings::Main::LogbookView, index);
+// Settings::write(Settings::Main::LogbookView, index);
+ Settings::setLogbookView(OPL::LogbookView(index));
emit settingChanged(SettingSignal::LogbookWidget);
}
void SettingsWidget::on_pilotSortComboBox_currentIndexChanged(int index)
{
- Settings::write(Settings::UserData::PilotSortColumn, index);
+ Settings::setPilotSortColumn(index);
emit settingChanged(PilotsWidget);
}
void SettingsWidget::on_acftSortComboBox_currentIndexChanged(int index)
{
- Settings::write(Settings::UserData::TailSortColumn, index);
+ Settings::setTailSortColumn(index);
emit settingChanged(AircraftWidget);
}
@@ -404,14 +358,16 @@ void SettingsWidget::on_styleComboBox_currentTextChanged(const QString& new_styl
{
if (new_style_setting == QLatin1String("Dark-Palette")) {
OPL::Style::setStyle(OPL::Style::darkPalette());
- Settings::write(Settings::Main::Style, new_style_setting);
+// Settings::write(Settings::Main::Style, new_style_setting);
+ Settings::setApplicationStyle(new_style_setting);
emit settingChanged(MainWindow);
return;
}
for (const auto &style_name : OPL::Style::styles) {
if (new_style_setting == style_name) {
OPL::Style::setStyle(style_name);
- Settings::write(Settings::Main::Style, new_style_setting);
+// Settings::write(Settings::Main::Style, new_style_setting);
+ Settings::setApplicationStyle(style_name);
emit settingChanged(MainWindow);
return;
}
@@ -420,7 +376,8 @@ void SettingsWidget::on_styleComboBox_currentTextChanged(const QString& new_styl
for (const auto &style_sheet : OPL::Style::styleSheets) {
if (new_style_setting == style_sheet.styleSheetName) {
OPL::Style::setStyle(style_sheet);
- Settings::write(Settings::Main::Style, new_style_setting);
+// Settings::write(Settings::Main::Style, new_style_setting);
+ Settings::setApplicationStyle(new_style_setting);
emit settingChanged(MainWindow);
return;
}
@@ -430,7 +387,8 @@ void SettingsWidget::on_styleComboBox_currentTextChanged(const QString& new_styl
void SettingsWidget::on_fontComboBox_currentFontChanged(const QFont &f)
{
qApp->setFont(f);
- Settings::write(Settings::Main::Font, f.toString());
+// Settings::write(Settings::Main::Font, f.toString());
+ Settings::setApplicationFontName(f.toString());
DEB << "Setting Font:" << f.toString();
}
@@ -439,7 +397,8 @@ void SettingsWidget::on_fontSpinBox_valueChanged(int arg1)
QFont f = qApp->font();
f.setPointSize(arg1);
qApp->setFont(f);
- Settings::write(Settings::Main::FontSize, arg1);
+// Settings::write(Settings::Main::FontSize, arg1);
+ Settings::setApplicationFontSize(arg1);
DEB << "Setting Font:" << f.toString();
}
@@ -455,7 +414,7 @@ void SettingsWidget::on_fontCheckBox_stateChanged(int arg1)
{
ui->fontComboBox->setEnabled(true);
ui->fontSpinBox->setEnabled(true);
- Settings::write(Settings::Main::UseSystemFont, false);
+ Settings::setUseSystemFont(false);
QFont font(ui->fontComboBox->currentFont());
font.setPointSize(ui->fontSpinBox->value());
qApp->setFont(font);
@@ -466,7 +425,7 @@ void SettingsWidget::on_fontCheckBox_stateChanged(int arg1)
{
ui->fontComboBox->setEnabled(false);
ui->fontSpinBox->setEnabled(false);
- Settings::write(Settings::Main::UseSystemFont, true);
+ Settings::setUseSystemFont(true);
INFO(tr("The application will be restarted for this change to take effect."));
qApp->quit();
QProcess::startDetached(qApp->arguments()[0], qApp->arguments());
@@ -496,184 +455,6 @@ void SettingsWidget::on_resetStylePushButton_clicked()
ui->fontCheckBox->setChecked(true);
}
-void SettingsWidget::on_currLicDateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::Licence), row_data);
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currTrDateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::TypeRating), row_data);
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currLckDateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::LineCheck), row_data);
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currMedDateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::Medical), row_data);
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currCustom1DateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)},
- {OPL::CurrencyEntry::CURRENCYNAME, ui->currCustom1LineEdit->text()}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::Custom1), row_data);
- DEB << entry;
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currCustom2DateEdit_userDateChanged(const QDate &date)
-{
- const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)},
- {OPL::CurrencyEntry::CURRENCYNAME, ui->currCustom2LineEdit->text()}};
- const OPL::CurrencyEntry entry(static_cast(OPL::CurrencyName::Custom2), row_data);
- if (!DB->commit(entry))
- WARN(tr("Unable to update currency. The following error has ocurred:
%1").arg(DB->lastError.text()));
-
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currToLdgCheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowToLgdCurrency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowToLgdCurrency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currLicCheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowLicCurrency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowLicCurrency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currTrCheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowTrCurrency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowTrCurrency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currLckCheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowLckCurrency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowLckCurrency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currMedCheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowMedCurrency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowMedCurrency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currCustom1CheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowCustom1Currency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowCustom1Currency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currCustom2CheckBox_stateChanged(int arg1)
-{
- switch (arg1) {
- case Qt::CheckState::Checked:
- Settings::write(Settings::UserData::ShowCustom2Currency, true);
- break;
- case Qt::CheckState::Unchecked:
- Settings::write(Settings::UserData::ShowCustom2Currency, false);
- break;
- default:
- break;
- }
- emit settingChanged(HomeWidget);
-}
-
-void SettingsWidget::on_currCustom1LineEdit_editingFinished()
-{
- Settings::write(Settings::UserData::Custom1CurrencyName, ui->currCustom1LineEdit->text());
-}
-
-void SettingsWidget::on_currCustom2LineEdit_editingFinished()
-{
- Settings::write(Settings::UserData::Custom2CurrencyName, ui->currCustom2LineEdit->text());
-}
-
void SettingsWidget::on_languageComboBox_activated(int arg1)
{
if (arg1 != 0) {
@@ -684,10 +465,15 @@ void SettingsWidget::on_languageComboBox_activated(int arg1)
}
}
-
void SettingsWidget::on_exportPushButton_clicked()
{
auto exp = new ExportToCsvDialog(this);
exp->exec();
}
+
+void SettingsWidget::on_currencyWarningDaysSpinBox_valueChanged(int arg1)
+{
+ Settings::setCurrencyWarningThreshold(arg1);
+}
+
diff --git a/src/gui/widgets/settingswidget.h b/src/gui/widgets/settingswidget.h
index 594e4d8b..7024eb39 100644
--- a/src/gui/widgets/settingswidget.h
+++ b/src/gui/widgets/settingswidget.h
@@ -74,24 +74,11 @@ private slots:
void on_fontSpinBox_valueChanged(int arg1);
void on_fontCheckBox_stateChanged(int arg1);
void on_resetStylePushButton_clicked();
- void on_currLicDateEdit_userDateChanged(const QDate &date);
- void on_currTrDateEdit_userDateChanged(const QDate &date);
- void on_currLckDateEdit_userDateChanged(const QDate &date);
- void on_currMedDateEdit_userDateChanged(const QDate &date);
- void on_currCustom1DateEdit_userDateChanged(const QDate &date);
- void on_currCustom2DateEdit_userDateChanged(const QDate &date);
- void on_currToLdgCheckBox_stateChanged(int arg1);
- void on_currLicCheckBox_stateChanged(int arg1);
- void on_currTrCheckBox_stateChanged(int arg1);
- void on_currLckCheckBox_stateChanged(int arg1);
- void on_currMedCheckBox_stateChanged(int arg1);
- void on_currCustom1CheckBox_stateChanged(int arg1);
- void on_currCustom2CheckBox_stateChanged(int arg1);
- void on_currCustom1LineEdit_editingFinished();
- void on_currCustom2LineEdit_editingFinished();
void on_languageComboBox_activated(int arg1);
void on_exportPushButton_clicked();
+ void on_currencyWarningDaysSpinBox_valueChanged(int arg1);
+
private:
Ui::SettingsWidget *ui;
@@ -101,8 +88,6 @@ private slots:
void setupComboBoxes();
- void setupDateEdits();
-
void loadBackupWidget();
void loadPreviousExperienceWidget();
diff --git a/src/gui/widgets/settingswidget.ui b/src/gui/widgets/settingswidget.ui
index e7c1807d..9c5d5a2a 100644
--- a/src/gui/widgets/settingswidget.ui
+++ b/src/gui/widgets/settingswidget.ui
@@ -17,8 +17,261 @@
-
- 2
+ 0
+
+
+ General
+
+
+
-
+
+
+ Setting this value to 0 disables warnings.
+
+
+ Warn about expiring currencies
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Style
+
+
+
+ -
+
+
+ Reset to Default
+
+
+
+ -
+
+
+ -
+
+
+ Font
+
+
+
+ -
+
+
+ Use System Font
+
+
+ true
+
+
+
+ -
+
+
+ false
+
+
+
+ -
+
+
+ false
+
+
+
+ 80
+ 16777215
+
+
+
+ 8
+
+
+ 18
+
+
+ 10
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
+
+
+ Sort Pilots by
+
+
+
+ -
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
+
+
-
+
+ Last Name
+
+
+ -
+
+ First Name
+
+
+ -
+
+ Company
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
+
+
+ Sort Aircraft by
+
+
+
+ -
+
+
+ <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
+
+
-
+
+ Registration
+
+
+ -
+
+ Type
+
+
+ -
+
+ Company
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
+
+
+ <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
+
+
+ Logbook Display
+
+
+
+ -
+
+
+ <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
+
+
+
+ -
+
+
+ <html><head/><body><p>How your own name is displayed in your logbook</p></body></html>
+
+
+ Show own name as
+
+
+
+ -
+
+
-
+
+ self
+
+
+ -
+
+ SELF
+
+
+ -
+
+ Lastname, Firstname
+
+
+
+
+ -
+
+
+ Language
+
+
+
+ -
+
+
+ -
+
+
+ Setting this value to 0 disables warnings.
+
+
+ 30
+
+
+
+ -
+
+
+ Setting this value to 0 disables warnings.
+
+
+ days before expiry
+
+
+
+
+
Personal
@@ -320,668 +573,6 @@
-
-
- Currencies
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
-
-
-
- custom currency
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- Take-off / Landing (days)
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 168
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
- <html><head/><body><p>Number of days for TO/LDG currency. Default 90</p></body></html>
-
-
- 90
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- Medical
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- custom currency
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- Line Check
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- Type Rating
-
-
-
- -
-
-
-
- 280
- 0
-
-
-
- Licence
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 167
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- QDateTimeEdit::MonthSection
-
-
- MM/dd/yyyy
-
-
- true
-
-
- Qt::UTC
-
-
-
- 2020
- 1
- 1
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Qt::LeftToRight
-
-
-
-
-
-
- -
-
-
-
- 140
- 0
-
-
-
- Show on Home Page
-
-
- Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft
-
-
-
-
-
-
-
- Appearance
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Style
-
-
-
- -
-
-
- Reset to Default
-
-
-
- -
-
-
- -
-
-
- Font
-
-
-
- -
-
-
- Use System Font
-
-
- true
-
-
-
- -
-
-
- false
-
-
-
- -
-
-
- false
-
-
-
- 80
- 16777215
-
-
-
- 8
-
-
- 18
-
-
- 10
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
-
-
- <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
-
-
- Sort Pilots by
-
-
-
- -
-
-
- <html><head/><body><p>Determines by which column to sort the display of Pilots in the Pilots Tab.</p></body></html>
-
-
-
-
- Last Name
-
-
- -
-
- First Name
-
-
- -
-
- Company
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
-
-
- <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
-
-
- Sort Aircraft by
-
-
-
- -
-
-
- <html><head/><body><p>Determines by which column to sort the display of Aircaft in the Aircraft Tab.</p></body></html>
-
-
-
-
- Registration
-
-
- -
-
- Type
-
-
- -
-
- Company
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
-
-
- <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
-
-
- Logbook Dispay
-
-
-
- -
-
-
- <html><head/><body><p>Determines how your logbook is displayed in the logbook tab. This has no influence on what details are logged, just on what is displayed by default.</p></body></html>
-
-
-
- -
-
-
- <html><head/><body><p>How your own name is displayed in your logbook</p></body></html>
-
-
- Show own name as
-
-
-
- -
-
-
-
-
- self
-
-
- -
-
- SELF
-
-
- -
-
- Lastname, Firstname
-
-
-
-
- -
-
-
- Language
-
-
-
- -
-
-
-
-
Backups
diff --git a/src/gui/widgets/tableeditwidget.cpp b/src/gui/widgets/tableeditwidget.cpp
new file mode 100644
index 00000000..7e48fd73
--- /dev/null
+++ b/src/gui/widgets/tableeditwidget.cpp
@@ -0,0 +1,231 @@
+#include "tableeditwidget.h"
+#include "src/database/database.h"
+#include "src/opl.h"
+#include
+#include
+
+TableEditWidget::TableEditWidget(Orientation orientation, QWidget *parent)
+ : QWidget{parent}, m_orientation(orientation)
+{}
+
+void TableEditWidget::init()
+{
+ setupUI();
+ setupSignalsAndSlots();
+}
+
+void TableEditWidget::setupUI()
+{
+ // Setting up the model and view is done in the derived class
+ setupModelAndView();
+ m_entryEditDialog = getEntryEditDialog(this);
+ m_stackedWidget->addWidget(m_entryEditDialog);
+
+ // set up the UI
+ switch (m_orientation) {
+ case Horizontal:
+ setupHorizontalUI();
+ break;
+ case Vertical:
+ setupVerticalUI();
+ default:
+ break;
+ }
+
+}
+
+void TableEditWidget::setupHorizontalUI()
+{
+ // In the horizontal view, the editing widget is hidden on the right hand side
+ m_stackedWidget->hide();
+
+ // create a 2-column grid layout and fill the cells
+ int colL = 0; // left column
+ int colR = 1; // right column
+ int row = 0;
+ int allRowSpan = 4; // adjust as needed for stackedWidget to span all rows
+
+ auto gridLayout = new QGridLayout(this);
+
+ gridLayout->addWidget(m_view, row, colL);
+ gridLayout->addWidget(m_stackedWidget, row, colR, allRowSpan, 1);
+ row++;
+
+ setupButtonWidget();
+ gridLayout->addWidget(m_buttonWidget);
+ row++;
+
+ setupFilterWidget();
+ gridLayout->addWidget(m_filterWidget, row, colL);
+}
+
+void TableEditWidget::setupVerticalUI()
+{
+ // create a single column grid layout and fill the cells
+ int col = 0;
+ int row = 0;
+ auto gridLayout = new QGridLayout(this);
+
+ gridLayout->addWidget(m_view, row, col);
+ row++;
+
+ gridLayout->addWidget(m_stackedWidget, row, col);
+ row++;
+
+ setupButtonWidget();
+ gridLayout->addWidget(m_buttonWidget);
+ row++;
+
+ setupFilterWidget();
+ m_stackedWidget->addWidget(m_filterWidget);
+ m_stackedWidget->setCurrentWidget(m_filterWidget);
+ gridLayout->addWidget(m_stackedWidget);
+}
+
+void TableEditWidget::setupFilterWidget()
+{
+ // place the filter items in a grid layout so they occupy one cell in parent layout
+ QWidget *widget = new QWidget(this);
+ QGridLayout *layout = new QGridLayout(widget);
+
+ // one row, three columns
+ layout->addWidget(new QLabel(tr("Filter"), this), 0, 0);
+ layout->addWidget(m_filterLineEdit, 0, 1);
+ layout->addWidget(m_filterSelectionComboBox, 0, 2);
+
+ m_filterWidget = widget;
+}
+
+void TableEditWidget::setupButtonWidget()
+{
+ auto buttonWidget = new QWidget(this);
+ auto buttonGridLayout = new QGridLayout(buttonWidget);
+
+ switch (m_orientation) {
+ case Horizontal:
+ buttonGridLayout->addWidget(m_addNewEntryPushButton, 0, 0);
+ buttonGridLayout->addWidget(m_deleteEntryPushButton, 1, 0);
+ break;
+ case Vertical:
+ buttonGridLayout->addWidget(m_addNewEntryPushButton, 0, 0);
+ buttonGridLayout->addWidget(m_deleteEntryPushButton, 0, 1);
+ default:
+ break;
+ }
+
+ m_buttonWidget = buttonWidget;
+}
+
+void TableEditWidget::setupSignalsAndSlots()
+{
+ // refresh the view when the database is updated
+ QObject::connect(DB, &OPL::Database::dataBaseUpdated,
+ this, &TableEditWidget::databaseContentChanged);
+ // filter the view
+ QObject::connect(m_filterLineEdit, &QLineEdit::textChanged,
+ this, &TableEditWidget::filterTextChanged);
+ // sort the view by column
+ QObject::connect(m_view->horizontalHeader(),&QHeaderView::sectionClicked,
+ this, &TableEditWidget::sortColumnChanged);
+ // Edit an entry
+ QObject::connect(m_view, &QTableView::clicked,
+ this, &TableEditWidget::editEntryRequested);
+ // Add a new entry
+ QObject::connect(m_addNewEntryPushButton, &QPushButton::clicked,
+ this, &TableEditWidget::addEntryRequested);
+ // Delete a selected entry
+ QObject::connect(m_deleteEntryPushButton, &QPushButton::clicked,
+ this, &TableEditWidget::deleteEntryRequested);
+}
+
+void TableEditWidget::addEntryRequested()
+{
+ cleanUpOldEditDialog();
+
+ m_entryEditDialog = getEntryEditDialog(this);
+ m_stackedWidget->addWidget(m_entryEditDialog);
+ m_stackedWidget->setCurrentWidget(m_entryEditDialog);
+
+ showEditWidget();
+ m_entryEditDialog->exec();
+ hideEditWidget();
+}
+
+void TableEditWidget::editEntryRequested(const QModelIndex &selectedIndex)
+{
+ int rowIdToEdit = m_model->index(selectedIndex.row(), 0).data().toInt();
+
+ cleanUpOldEditDialog();
+
+ m_entryEditDialog = getEntryEditDialog(this);
+ m_entryEditDialog->loadEntry(rowIdToEdit);
+ m_stackedWidget->addWidget(m_entryEditDialog);
+ m_stackedWidget->setCurrentWidget(m_entryEditDialog);
+
+ showEditWidget();
+ m_entryEditDialog->exec();
+ hideEditWidget();
+}
+
+void TableEditWidget::deleteEntryRequested()
+{
+ const QModelIndex selectedIndex = m_view->selectionModel()->currentIndex();
+ if(!selectedIndex.isValid()) {
+ WARN(tr("No entry selected."));
+ return;
+ }
+ m_stackedWidget->hide();
+
+ int rowId = m_model->index(selectedIndex.row(), 0).data().toInt();
+ m_view->selectionModel()->reset();
+
+ // get user confirmation
+ QMessageBox confirm(this);
+ confirm.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ confirm.setDefaultButton(QMessageBox::No);
+ confirm.setIcon(QMessageBox::Question);
+ confirm.setWindowTitle(tr("Confirm Deletion"));
+
+ confirm.setText(confirmDeleteString(rowId));
+ if (confirm.exec() == QMessageBox::Yes) {
+ auto editDialog = getEntryEditDialog(this);
+ if(!editDialog->deleteEntry(rowId))
+ WARN(deleteErrorString(rowId));
+ }
+
+ // re-set stackedWidget for Vertical Layout
+ if(m_orientation == Vertical) {
+ m_stackedWidget->setCurrentWidget(m_filterWidget);
+ m_stackedWidget->show();
+ }
+}
+
+void TableEditWidget::sortColumnChanged(int newSortColumn)
+{
+ m_view->sortByColumn(newSortColumn, Qt::AscendingOrder);
+}
+
+void TableEditWidget::databaseContentChanged()
+{
+ m_model->select();
+ m_view->resizeColumnsToContents();
+}
+
+void TableEditWidget::showEditWidget()
+{
+ m_buttonWidget->hide();
+ m_stackedWidget->show();
+}
+
+void TableEditWidget::hideEditWidget()
+{
+ m_stackedWidget->hide();
+ m_buttonWidget->show();
+}
+
+void TableEditWidget::cleanUpOldEditDialog()
+{
+ if(m_stackedWidget->indexOf(m_entryEditDialog) != -1) {
+ delete m_entryEditDialog;
+ }
+}
diff --git a/src/gui/widgets/tableeditwidget.h b/src/gui/widgets/tableeditwidget.h
new file mode 100644
index 00000000..25af31d8
--- /dev/null
+++ b/src/gui/widgets/tableeditwidget.h
@@ -0,0 +1,154 @@
+#ifndef TABLEEDITWIDGET_H
+#define TABLEEDITWIDGET_H
+
+#include "src/gui/dialogues/entryeditdialog.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*!
+ * \brief The TableEditWidget class is a base class for widgets which enable
+ * editing certain tables in the datbase.
+ * \details The TableEditWidget consists of a QTableView which displays the data
+ * from a given table. The data is held in a QSqlTableModel. The views edit triggers
+ * are disabled. Whenever a row is selected in the view, the selected entry is displayed
+ * for editing in a suitable EntryEditDialog which is responsible for the verification of
+ * the user input as well as reading and writing to and from the database.
+ *
+ * The TableEditWidget has two Orientation options: Horizontal and Vertical
+ *
+ * In the Horizontal layout, the table view is split horizontally to make space
+ * for the TableEditWidget on the right hand side, whereas on the Vertical layout
+ * it is split vertically with the TableEditWidget occupying the lower half of the screen.
+ *
+ * When implementing the TableEditWidget it is important to set up the model and call the
+ * Base Class implementation of setupUI before performing any specialisations. Before the
+ * TableEditWidget is shown, the init method must be run.
+ */
+class TableEditWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ /*!
+ * \brief Determines how the layout is created
+ * \details
+ * - Horizontal: The edit widget is shown besides the table
+ * - Vertical: The edit widget is shown below the table
+ *
+ */
+ enum Orientation {Horizontal, Vertical};
+
+ /*!
+ * \brief Create a new TableEditWidget
+ */
+ explicit TableEditWidget(Orientation orientation = Horizontal, QWidget *parent = nullptr);
+
+ /*!
+ * \brief Initialises the dialog by calling its virtual setup functions.
+ * \attention Call this functian before showing the dialog.
+ */
+ void init();
+
+ /*!
+ * \brief Set up the model and view of the widget
+ * \details Implement this function to initialise the protected members of this class.
+ * This includes setting the QSqlTableModel and QTableView */
+ virtual void setupModelAndView() = 0;
+
+ /*!
+ * \brief Set up the UI of the widget
+ * \details Implement this function to set appropriate labels to the protected members of this
+ * class. This includes setting appropriate labels on the Push Buttons as well as
+ * appropriate filter options in the filter Combo Box. Make sure to call the base class
+ * implementation first when overriding this method.
+ */
+ virtual void setupUI();
+
+ /*!
+ * \brief create an error String when deleting a database entry has been unsuccessful
+ * \param rowId - the row id of the entry to be deleted
+ * \details When deleting an entry from a database fails, this can have different reasons
+ * depending on the table. This function returns an implementation-specific error string
+ * to inform the user about the failure and give hints on how to fix it
+ */
+ virtual QString deleteErrorString(int rowId) = 0;
+
+ /*!
+ * \brief return a String asking the user to confirm deletion of a given entry
+ * \param rowId - the row id of the entry to be deleted
+ * \brief The message string is displayed in a QMessageBox
+ */
+ virtual QString confirmDeleteString(int rowId) = 0;
+
+ /*!
+ * \brief get an apropriate Edit Dialog for the implementation
+ * \details The Edit Dialogs for different tables differ in the data they display
+ * and how they verify the user inputs. This method returns an apropriate
+ * EntryEditDialog for the selected table.
+ */
+ virtual EntryEditDialog *getEntryEditDialog(QWidget *parent = nullptr) = 0;
+
+protected:
+ Orientation m_orientation;
+ QSqlTableModel *m_model = nullptr;
+ QTableView *m_view = new QTableView(this);
+ QWidget *m_filterWidget = nullptr;
+ QWidget *m_buttonWidget = nullptr;
+ EntryEditDialog* m_entryEditDialog = nullptr;
+
+ QPushButton *m_addNewEntryPushButton = new QPushButton(this);
+ QPushButton *m_deleteEntryPushButton = new QPushButton(this);
+
+ QStackedWidget *m_stackedWidget = new QStackedWidget(this);
+ QLineEdit *m_filterLineEdit = new QLineEdit(this);
+ QComboBox *m_filterSelectionComboBox = new QComboBox(this);
+
+ virtual void showEditWidget();
+ virtual void hideEditWidget();
+ /*!
+ * \brief makes sure heap allocated widgets are destroyed when a user requests another add or edit before completing
+ * a proviously opened one.
+ */
+ void cleanUpOldEditDialog();
+
+private:
+ void setupHorizontalUI();
+ void setupVerticalUI();
+ void setupSignalsAndSlots();
+
+ /*!
+ * \brief Place the filter items in a widget to facilitate easier placement in parent layout
+ */
+ void setupFilterWidget();
+
+ /*!
+ * \brief Place the new and edit buttons in a widget to facilitate easier placement in parent layout
+ */
+ void setupButtonWidget();
+
+public slots:
+ virtual void addEntryRequested();
+ virtual void editEntryRequested(const QModelIndex &selectedIndex);
+ virtual void deleteEntryRequested();
+ virtual void sortColumnChanged(int newSortColumn);
+
+ /*!
+ * \brief Set a filter on the model
+ */
+ virtual void filterTextChanged(const QString &filterString) = 0;
+
+public slots:
+ /*!
+ * \brief refresh the view after a Database change
+ */
+ void databaseContentChanged();
+
+};
+
+#endif // TABLEEDITWIDGET_H
diff --git a/src/gui/widgets/tailtableeditwidget.cpp b/src/gui/widgets/tailtableeditwidget.cpp
new file mode 100644
index 00000000..84d0e332
--- /dev/null
+++ b/src/gui/widgets/tailtableeditwidget.cpp
@@ -0,0 +1,111 @@
+#include "tailtableeditwidget.h"
+#include "src/database/database.h"
+#include "src/gui/dialogues/newtaildialog.h"
+
+TailTableEditWidget::TailTableEditWidget(QWidget *parent)
+ : TableEditWidget(Horizontal, parent)
+{}
+
+void TailTableEditWidget::setupModelAndView()
+{
+ m_model = new QSqlTableModel(this, DB->database());
+ m_model->setTable(OPL::GLOBALS->getDbTableName(OPL::DbTable::Tails));
+ m_model->select();
+ m_model->setHeaderData(COL_REGISTRATION, Qt::Horizontal, COLUMN_NAME_REGISTRATION);
+ m_model->setHeaderData(COL_TYPE, Qt::Horizontal, COLUMN_NAME_TYPE);
+ m_model->setHeaderData(COL_COMPANY, Qt::Horizontal, COLUMN_NAME_COMPANY);
+
+ m_view->setModel(m_model);
+ m_view->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_view->setSelectionBehavior(QAbstractItemView::SelectRows);
+ m_view->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ m_view->horizontalHeader()->setStretchLastSection(QHeaderView::Stretch);
+ m_view->resizeColumnsToContents();
+ m_view->verticalHeader()->hide();
+ m_view->setAlternatingRowColors(true);
+ for(const int i : COLS_TO_HIDE)
+ m_view->hideColumn(i);
+}
+
+void TailTableEditWidget::setupUI()
+{
+ // the base class does most of the setup
+ TableEditWidget::setupUI();
+
+ // only need to set the table specific labels and combo box items
+ m_addNewEntryPushButton->setText(tr("Add New Tail"));
+ m_deleteEntryPushButton->setText(tr("Delete Selected Tail"));
+ m_filterSelectionComboBox->addItems(FILTER_COLUMNS);
+}
+
+QString TailTableEditWidget::deleteErrorString(int rowId)
+{
+ QList foreign_key_constraints = DB->getForeignKeyConstraints(rowId,
+ OPL::DbTable::Tails);
+ QList constrained_flights;
+ for (const auto &row_id : qAsConst(foreign_key_constraints)) {
+ constrained_flights.append(DB->getFlightEntry(row_id));
+ }
+
+ QMessageBox message_box(this);
+ if (constrained_flights.isEmpty()) {
+ // error is a database error
+ return tr("
Unable to delete.
The following error has ocurred: %1"
+ ).arg(DB->lastError.text());
+ } else {
+ QString constrained_flights_string;
+ for (int i=0; i"));
+ if (i>10) {
+ constrained_flights_string.append(QLatin1String("
[...]
"));
+ break;
+ }
+ }
+ return (tr("Unable to delete.
"
+ "This is most likely the case because a flight exists with the aircraft "
+ "you are trying to delete.
"
+ "%1 flight(s) with this aircraft have been found:
"
+ "%2"
+ "
You have to change or remove the conflicting flight(s) "
+ "before removing this aircraft from the database.
"
+ ).arg(
+ QString::number(constrained_flights.length()),
+ constrained_flights_string)
+ );
+ }
+}
+
+QString TailTableEditWidget::confirmDeleteString(int rowId)
+{
+ const auto entry = DB->getTailEntry(rowId);
+ return tr("You are deleting the following aircraft:
"
+ "%1 (%2)
Are you sure?"
+ ).arg(
+ entry.getData().value(OPL::TailEntry::REGISTRATION).toString(),
+ entry.type()
+ );
+}
+
+EntryEditDialog *TailTableEditWidget::getEntryEditDialog(QWidget *parent)
+{
+ QString empty;
+ return new NewTailDialog(empty, parent);
+}
+
+void TailTableEditWidget::filterTextChanged(const QString &filterString)
+{
+ if(filterString.isEmpty()) {
+ m_model->setFilter(QString());
+ return;
+ }
+
+ int i = m_filterSelectionComboBox->currentIndex();
+ const QString filter =
+ QLatin1Char('\"')
+ + FILTER_COLUMN_NAMES.at(i)
+ + QLatin1String("\" LIKE '%")
+ + filterString
+ + QLatin1String("%'");
+ m_model->setFilter(filter);
+}
diff --git a/src/gui/widgets/tailtableeditwidget.h b/src/gui/widgets/tailtableeditwidget.h
new file mode 100644
index 00000000..30583839
--- /dev/null
+++ b/src/gui/widgets/tailtableeditwidget.h
@@ -0,0 +1,50 @@
+#ifndef TAILTABLEEDITWIDGET_H
+#define TAILTABLEEDITWIDGET_H
+
+#include "tableeditwidget.h"
+#include "src/database/tailentry.h"
+
+class TailTableEditWidget : public TableEditWidget
+{
+ Q_OBJECT
+public:
+ TailTableEditWidget() = delete;
+ explicit TailTableEditWidget(QWidget *parent = nullptr);
+
+
+ virtual void setupModelAndView() override;
+ virtual void setupUI() override;
+ virtual QString deleteErrorString(int rowId) override;
+ virtual QString confirmDeleteString(int rowId) override;
+ virtual EntryEditDialog *getEntryEditDialog(QWidget *parent) override;
+
+private:
+ const int COL_ROWID = 0;
+ const int COL_REGISTRATION = 1;
+ const int COL_TYPE = 10;
+ const int COL_COMPANY = 2;
+
+ const int COLS_TO_HIDE[8] = {0, 3, 4, 5, 6, 7, 8, 9};
+
+ const QString COLUMN_NAME_REGISTRATION = tr("Registration");
+ const QString COLUMN_NAME_TYPE = tr("Type");
+ const QString COLUMN_NAME_COMPANY = tr("Company");
+
+ const QStringList FILTER_COLUMNS = {
+ COLUMN_NAME_REGISTRATION,
+ COLUMN_NAME_TYPE,
+ COLUMN_NAME_COMPANY,
+ };
+
+ const static inline QStringList FILTER_COLUMN_NAMES = {
+ OPL::TailEntry::REGISTRATION,
+ OPL::TailEntry::TYPE_STRING,
+ OPL::TailEntry::COMPANY
+ };
+
+private slots:
+
+ virtual void filterTextChanged(const QString &filterString) override;
+};
+
+#endif // TAILTABLEEDITWIDGET_H
diff --git a/src/gui/widgets/totalswidget.cpp b/src/gui/widgets/totalswidget.cpp
index 3b43cad3..403ef1b5 100644
--- a/src/gui/widgets/totalswidget.cpp
+++ b/src/gui/widgets/totalswidget.cpp
@@ -22,6 +22,7 @@
#include "src/opl.h"
#include "src/classes/time.h"
#include "ui_totalswidget.h"
+#include "src/classes/settings.h"
TotalsWidget::TotalsWidget(WidgetType widgetType, QWidget *parent) :
QWidget(parent),
@@ -43,6 +44,7 @@ TotalsWidget::~TotalsWidget()
*/
void TotalsWidget::setup(const WidgetType widgetType)
{
+ m_format = Settings::getDisplayFormat();
const QList lineEdits = this->findChildren();
switch (widgetType) {
@@ -90,6 +92,7 @@ void TotalsWidget::fillTotals(const WidgetType widgetType)
break;
case PreviousExperienceWidget:
time_data = DB->getRowData(OPL::DbTable::PreviousExperience, ROW_ID);
+ break;
}
// fill the line edits with the data obtained
@@ -106,7 +109,7 @@ void TotalsWidget::fillTotals(const WidgetType widgetType)
line_edit->setText(field.toString());
} else {
// line edits for total time
- OPL::Time time = OPL::Time(field.toInt());// = Time(field.toInt());
+ OPL::Time time = OPL::Time(field.toInt(), m_format);
line_edit->setText(time.toString());
}
}
@@ -171,7 +174,7 @@ void TotalsWidget::timeLineEditEditingFinished()
// write the updated value to the database
const QString db_field = line_edit->objectName().remove(QLatin1String("LineEdit"));
- const QVariant value = OPL::Time::fromString(line_edit->text()).toMinutes();
+ const QVariant value = OPL::Time::fromString(line_edit->text(), m_format).toMinutes();
m_rowData.insert(db_field, value);
LOG << "Added row data: " + db_field + ": " + value.toString();
@@ -181,7 +184,7 @@ void TotalsWidget::timeLineEditEditingFinished()
// Read back the value and set the line edit to confirm input is correct and provide user feedback
m_rowData = DB->getRowData(OPL::DbTable::PreviousExperience, ROW_ID);
- OPL::Time new_time = OPL::Time(m_rowData.value(db_field).toInt());
+ OPL::Time new_time = OPL::Time(m_rowData.value(db_field).toInt(), m_format);
line_edit->setText(new_time.toString());
}
diff --git a/src/gui/widgets/totalswidget.h b/src/gui/widgets/totalswidget.h
index d36d0376..98bd345b 100644
--- a/src/gui/widgets/totalswidget.h
+++ b/src/gui/widgets/totalswidget.h
@@ -28,6 +28,18 @@ namespace Ui {
class TotalsWidget;
}
+/*!
+ * \brief The TotalsWidget is used to display or edit total time values.
+ * \details This widget has two different purposes.
+ *
+ * - It displays the cumulative total time in the logbook
+ * - It is used to enter and edit the total time accumulated in previous logbooks
+ *
+ *
+ * In its total time form, the Widget functions purely as a display widget, whereas when used
+ * for previous experience, its fields are editable.
+ *
+ */
class TotalsWidget : public QWidget
{
Q_OBJECT
@@ -48,6 +60,8 @@ class TotalsWidget : public QWidget
/*!
* \brief ROW_ID the row ID for previous experience entries (1)
*/
+
+ OPL::DateTimeFormat m_format;
const static int ROW_ID = 1;
void fillTotals(const WidgetType widgetType);
void setup(const WidgetType widgetType);
diff --git a/src/gui/widgets/totalswidget.ui b/src/gui/widgets/totalswidget.ui
index 284b1518..4295c7ab 100644
--- a/src/gui/widgets/totalswidget.ui
+++ b/src/gui/widgets/totalswidget.ui
@@ -15,535 +15,531 @@
-
-
-
-
-
-
-
- 120
- 16777215
-
-
-
- Night
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- LDG Night
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
- 0
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- SP ME
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
- 0
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- DUAL
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- TO Night
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
- 0
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- PIC
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- PICus
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- IFR
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- Multi Pilot
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
- 0
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- LDG Day
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- Simulator
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- Total
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- SP SE
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- SIC
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- FI
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 100
- 0
-
-
-
-
- 120
- 16777215
-
-
-
- Qt::TabFocus
-
-
-
- -
-
-
-
- 120
- 16777215
-
-
-
- TO Day
-
-
-
-
+
+
+
+ 120
+ 16777215
+
+
+
+ Total
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ PICus
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ SP SE
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ IFR
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ SP ME
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ Night
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ Multi Pilot
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ Simulator
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ PIC
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ TO Day
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+ 0
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ SIC
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ TO Night
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+ 0
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ DUAL
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ LDG Day
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+ 0
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ FI
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+
+ -
+
+
+
+ 120
+ 16777215
+
+
+
+ LDG Night
+
+
+
+ -
+
+
+
+ 100
+ 0
+
+
+
+
+ 120
+ 16777215
+
+
+
+ Qt::TabFocus
+
+
+ 0
+
+
diff --git a/src/opl.h b/src/opl.h
index 3a09669d..357f551d 100644
--- a/src/opl.h
+++ b/src/opl.h
@@ -70,16 +70,22 @@ namespace OPL {
/**
* @brief Defines the row ID for non-user entries in the database;
*/
-const static int STUB_ROW_ID = -1;
+constexpr static int STUB_ROW_ID = -1;
/**
* @brief Defines a four-letter code for a non-extistent (dummy) airport: "XXXX"
*/
-const static char* STUB_AIRPORT_CODE = "XXXX";
+constexpr static auto STUB_AIRPORT_CODE = QLatin1String("XXXX");
/**
* @brief Defines a registration for a non-existent (dummy) aircraft: "XX-XXX"
*/
-const static char* STUB_AIRCRAFT_REG = "XX-XXX";
+constexpr static auto STUB_AIRCRAFT_REG = QLatin1String("XX-XXX");
+
+/*!
+ * \brief The decimal seperator used internally
+ */
+constexpr static char DECIMAL_SEPERATOR = '.';
+
/*!
* \brief The ANotificationHandler class handles displaying of user-directed messages. It displays
@@ -118,6 +124,63 @@ struct ToLdgCount_T {
: toDay(toDay), toNight(toNight), ldgDay(ldgDay), ldgNight(ldgNight) {}
};
+/*!
+ * \brief The DateFormat struct encapsulates how date and time values are displayed.
+ * \details Stores how the user wishes to display and enter Date and Time Entries.
+ * These are stored numerically in the database and thus need to be converted to
+ * human-readably form.
+ */
+struct DateTimeFormat {
+ /*!
+ * \brief Enumerates how dates can be formatted to a localised format.
+ * \value Default - The Application standard, Equivalent to Qt::ISODate
+ * \value SystemLocale - The current system locale date format
+ */
+ enum class DateFormat { Default, SystemLocale, Custom };
+
+ /*!
+ * \brief Enumerates how time values can be formatted
+ * \value Default - The application default is 'hh:mm'
+ * \value Decimal - Time as Decmial hours (01:30 == 1.5)
+ * \value Custom - A user-provided custom format string
+ */
+ enum class TimeFormat { Default, Decimal, Custom };
+
+ /*!
+ * \brief Initialise a DateTimeFormat instance with default values
+ */
+ DateTimeFormat()
+ : m_dateFormat(DateFormat::Default),
+ m_dateFormatString(QStringLiteral("yyyy-MM-dd")),
+ m_timeFormat(TimeFormat::Default),
+ m_timeFormatString(QStringLiteral("hh:mm"))
+ {}
+
+ DateTimeFormat(DateFormat dateFormat_,
+ const QString &dateFormatString_,
+ TimeFormat timeFormat_,
+ const QString &timeFormatString_)
+ :
+ m_dateFormat(dateFormat_),
+ m_dateFormatString(dateFormatString_),
+ m_timeFormat(timeFormat_),
+ m_timeFormatString(timeFormatString_)
+ {}
+
+
+public:
+ DateFormat dateFormat() const { return m_dateFormat; }
+ TimeFormat timeFormat() const { return m_timeFormat; }
+ const QString &dateFormatString() const { return m_dateFormatString; }
+ const QString &timeFormatString() const { return m_timeFormatString; }
+
+private:
+ DateFormat m_dateFormat;
+ TimeFormat m_timeFormat;
+ QString m_dateFormatString;
+ QString m_timeFormatString;
+};
+
/*!
* \brief ADateFormats enumerates the accepted date formats for QDateEdits
* \todo At the moment, only ISODate is accepet as a valid date format.
@@ -126,7 +189,7 @@ enum class DateFormat {ISODate, DE, EN };
enum class FlightTimeFormat {Default, Decimal};
-enum class DateTimeFormat {Default, Backup};
+enum class DateTimeFormat_deprecated {Default, Backup};
/*!
* \brief PilotFunction
@@ -142,7 +205,7 @@ enum class Translation {English, German, Spanish};
/*!
* \brief Enumerates the available SQL views in the database
*/
-enum class DbViewName {Default, DefaultWithSim, Easa, EasaWithSim, SimulatorOnly};
+enum class LogbookView {Default, DefaultWithSim, Easa, EasaWithSim, SimulatorOnly};
/*!
* \brief Enumerates the Simulator Types: Flight and Navigation Procedures Trainer 1/2, Flight Simulation Training Device
@@ -176,7 +239,7 @@ class OplGlobals : public QObject {
inline const QStringList &getApproachTypes() const {return APPROACH_TYPES;}
inline const QString getLanguageFilePath(Translation language) const {return L10N_FilePaths.value(language);}
- inline const QString getViewIdentifier(DbViewName view_name) const {return DATABASE_VIEWS.value(view_name);}
+ inline const QString getViewIdentifier(LogbookView view_name) const {return DATABASE_VIEWS.value(view_name);}
inline const QString getDbTableName(DbTable table_name) const {return DB_TABLES.value(table_name);}
private:
@@ -191,19 +254,19 @@ class OplGlobals : public QObject {
{Translation::German, QStringLiteral("Deutsch")},
{Translation::Spanish, QStringLiteral("Español")},
};
- const static inline QMap DATABASE_VIEWS = {
- {DbViewName::Default, QStringLiteral("viewDefault")},
- {DbViewName::DefaultWithSim, QStringLiteral("viewDefaultSim")},
- {DbViewName::Easa, QStringLiteral("viewEasa")},
- {DbViewName::EasaWithSim, QStringLiteral("viewEasaSim")},
- {DbViewName::SimulatorOnly, QStringLiteral("viewSimulators")},
+ const static inline QMap DATABASE_VIEWS = {
+ {LogbookView::Default, QStringLiteral("viewDefault")},
+ {LogbookView::DefaultWithSim, QStringLiteral("viewDefaultSim")},
+ {LogbookView::Easa, QStringLiteral("viewEasa")},
+ {LogbookView::EasaWithSim, QStringLiteral("viewEasaSim")},
+ {LogbookView::SimulatorOnly, QStringLiteral("viewSimulators")},
};
- const QMap DATABASE_VIEW_DISPLAY_NAMES = {
- {DbViewName::Default, tr("Default")},
- {DbViewName::DefaultWithSim, tr("Default with Simulator")},
- {DbViewName::Easa, tr("EASA-FCL")},
- {DbViewName::EasaWithSim, tr("EASA-FCL with Simulator")},
- {DbViewName::SimulatorOnly, tr("Simulator Sessions Only")},
+ const QMap DATABASE_VIEW_DISPLAY_NAMES = {
+ {LogbookView::Default, tr("Default")},
+ {LogbookView::DefaultWithSim, tr("Default with Simulator")},
+ {LogbookView::Easa, tr("EASA-FCL")},
+ {LogbookView::EasaWithSim, tr("EASA-FCL with Simulator")},
+ {LogbookView::SimulatorOnly, tr("Simulator Sessions Only")},
};
const static inline QMap PILOT_FUNCTIONS = {
{PilotFunction::PIC, QStringLiteral("PIC")},
@@ -265,7 +328,6 @@ const inline auto DATABASE_SCHEMA = QStringLiteral(":/database/da
const inline auto DATABASE_TEMPLATE_AIRCRAFT = QStringLiteral(":/database/templates/aircraft.json");
const inline auto DATABASE_TEMPLATE_AIRPORT = QStringLiteral(":/database/templates/airports.json");
const inline auto DATABASE_TEMPLATE_CHANGELOG = QStringLiteral(":/database/templates/changelog.json");
-const inline auto DATABASE_TEMPLATE_CURRENCIES = QStringLiteral(":/database/templates/currencies.json");
const inline auto LOGO = QStringLiteral(":/icons/opl-icons/logos/logo_text.png");
const inline auto ICON_MAIN = QStringLiteral(":/icons/opl-icons/app/icon_main.png");
@@ -300,17 +362,16 @@ namespace CssStyles {
const inline auto RED_BORDER = QStringLiteral("border: 1px solid red");
} // namespace Styles
-namespace Format {
+//namespace Format {
-const inline auto TIME_FORMAT = QStringLiteral("hh:mm");
+//const inline auto TIME_FORMAT = QStringLiteral("hh:mm");
-} // namespace Format
+//} // namespace Format
namespace RegEx {
const inline auto RX_PHONE_NUMBER = QRegularExpression(QStringLiteral("^[+]{0,1}[0-9\\-\\s]+"));
-const inline auto RX_EMAIL_ADDRESS = QRegularExpression(QStringLiteral("\\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@"));
-const inline auto RX_TIME_ENTRY = QRegularExpression(QStringLiteral("([01]?[0-9]|2[0-3]):?[0-5][0-9]?"));
+const inline auto RX_TIME_ENTRY = QRegularExpression(QStringLiteral("^(?:(?:([01]?\\d|2[0-3])(?::?)([0-5]\\d))|(?:([01]?\\d|2[0-3])([0-5]\\d))|(?:([1-9]|[1-9]\\d)\\:([0-5]\\d)?)|(?:([01]?\\d|2[0-3])\\.([0-5]?\\d)))$"));
const inline auto RX_AIRPORT_CODE = QRegularExpression(QStringLiteral("[a-zA-Z0-9]{1,4}"));
} // namespace RegEx
diff --git a/src/testing/importCrewlounge/processflights.cpp b/src/testing/importCrewlounge/processflights.cpp
index d1fe2c2b..4d760b77 100644
--- a/src/testing/importCrewlounge/processflights.cpp
+++ b/src/testing/importCrewlounge/processflights.cpp
@@ -54,14 +54,14 @@ void ProcessFlights::processParsedData()
auto time_off = QTime::fromString(row[4], QStringLiteral("hh:mm"));
if (!time_off.isValid())
time_off = QTime::fromString(row[4], QStringLiteral("h:mm"));
- int tofb = OPL::Time::fromString(time_off.toString()).toMinutes();
+ int tofb = OPL::Time::fromString(time_off.toString(), OPL::DateTimeFormat()).toMinutes();
new_flight_data.insert(OPL::FlightEntry::TOFB, tofb);
auto time_on = QTime::fromString(row[5], QStringLiteral("hh:mm"));
if (!time_on.isValid())
time_on = QTime::fromString(row[5], QStringLiteral("h:mm"));
- int tonb = OPL::Time::fromString(time_on.toString()).toMinutes();
+ int tonb = OPL::Time::fromString(time_on.toString(), OPL::DateTimeFormat()).toMinutes();
new_flight_data.insert(OPL::FlightEntry::TONB, tonb);
// map pilots
diff --git a/src/testing/randomgenerator.cpp b/src/testing/randomgenerator.cpp
index fbba29ac..fd47a349 100644
--- a/src/testing/randomgenerator.cpp
+++ b/src/testing/randomgenerator.cpp
@@ -19,8 +19,8 @@ const FlightEntry RandomGenerator::randomFlight()
const QDateTime dest_dt = dept_dt.addSecs(QRandomGenerator::global()->bounded(900, 50000));
const QString doft = dept_dt.date().toString(Qt::ISODate);
- OPL::Time tofb = OPL::Time::fromString(dept_dt.time().toString());
- OPL::Time tonb = OPL::Time::fromString(dest_dt.time().toString());
+ OPL::Time tofb = OPL::Time::fromString(dept_dt.time().toString(Qt::ISODate), OPL::DateTimeFormat());
+ OPL::Time tonb = OPL::Time::fromString(dest_dt.time().toString(Qt::ISODate), OPL::DateTimeFormat());
int pic = randomPilot();
int acft = randomTail();