ソースを参照

Merge pull request #103 from fiffty-50/develop-previous-experience

Develop previous experience
Felix Turowsky 1 年間 前
コミット
d71d01cd94
97 ファイル変更3602 行追加2456 行削除
  1. 3 0
      .gitignore
  2. 26 2
      CMakeLists.txt
  3. 207 188
      assets/database/database_schema.sql
  4. 18 12
      main.cpp
  5. 14 8
      mainwindow.cpp
  6. 1 1
      mainwindow.h
  7. 1 1
      src/classes/downloadhelper.cpp
  8. 1 1
      src/classes/downloadhelper.h
  9. 1 1
      src/classes/jsonhelper.cpp
  10. 1 1
      src/classes/jsonhelper.h
  11. 1 1
      src/classes/md5sum.cpp
  12. 1 1
      src/classes/md5sum.h
  13. 1 1
      src/classes/runguard.cpp
  14. 1 1
      src/classes/runguard.h
  15. 1 1
      src/classes/settings.cpp
  16. 1 1
      src/classes/settings.h
  17. 1 1
      src/classes/style.cpp
  18. 1 1
      src/classes/style.h
  19. 64 0
      src/classes/time.cpp
  20. 60 0
      src/classes/time.h
  21. 39 0
      src/database/aircraftentry.cpp
  22. 105 0
      src/database/aircraftentry.h
  23. 49 0
      src/database/airportentry.cpp
  24. 89 0
      src/database/airportentry.h
  25. 39 0
      src/database/currencyentry.cpp
  26. 53 0
      src/database/currencyentry.h
  27. 104 19
      src/database/database.cpp
  28. 39 1
      src/database/database.h
  29. 17 0
      src/database/databasecache.cpp
  30. 17 0
      src/database/databasecache.h
  31. 4 1
      src/database/dbsummary.cpp
  32. 2 3
      src/database/dbsummary.h
  33. 39 0
      src/database/flightentry.cpp
  34. 70 0
      src/database/flightentry.h
  35. 49 0
      src/database/pilotentry.cpp
  36. 80 0
      src/database/pilotentry.h
  37. 39 0
      src/database/previousexperienceentry.cpp
  38. 57 0
      src/database/previousexperienceentry.h
  39. 16 92
      src/database/row.cpp
  40. 50 92
      src/database/row.h
  41. 39 0
      src/database/simulatorentry.cpp
  42. 69 0
      src/database/simulatorentry.h
  43. 48 0
      src/database/tailentry.cpp
  44. 109 0
      src/database/tailentry.h
  45. 21 21
      src/functions/calc.cpp
  46. 8 7
      src/functions/calc.h
  47. 1 1
      src/functions/log.cpp
  48. 1 1
      src/functions/log.h
  49. 1 2
      src/functions/readcsv.h
  50. 2 2
      src/functions/statistics.cpp
  51. 1 1
      src/functions/statistics.h
  52. 0 218
      src/functions/time.h
  53. 1 0
      src/gui/dialogues/exporttocsvdialog.cpp
  54. 31 15
      src/gui/dialogues/firstrundialog.cpp
  55. 6 1
      src/gui/dialogues/firstrundialog.h
  56. 15 15
      src/gui/dialogues/newairportdialog.cpp
  57. 93 119
      src/gui/dialogues/newflightdialog.cpp
  58. 2 3
      src/gui/dialogues/newflightdialog.h
  59. 480 563
      src/gui/dialogues/newflightdialog.ui
  60. 1 1
      src/gui/dialogues/newpilotdialog.cpp
  61. 2 2
      src/gui/dialogues/newpilotdialog.h
  62. 20 19
      src/gui/dialogues/newsimdialog.cpp
  63. 1 1
      src/gui/dialogues/newsimdialog.h
  64. 10 9
      src/gui/dialogues/newtaildialog.cpp
  65. 2 4
      src/gui/dialogues/newtaildialog.h
  66. 2 2
      src/gui/verification/timeinput.cpp
  67. 1 1
      src/gui/widgets/airportwidget.cpp
  68. 2 2
      src/gui/widgets/backupwidget.cpp
  69. 1 2
      src/gui/widgets/backupwidget.h
  70. 11 5
      src/gui/widgets/debugwidget.cpp
  71. 3 1
      src/gui/widgets/debugwidget.h
  72. 66 59
      src/gui/widgets/debugwidget.ui
  73. 26 15
      src/gui/widgets/homewidget.cpp
  74. 2 4
      src/gui/widgets/homewidget.h
  75. 96 633
      src/gui/widgets/homewidget.ui
  76. 7 9
      src/gui/widgets/logbookwidget.cpp
  77. 2 3
      src/gui/widgets/logbookwidget.h
  78. 9 10
      src/gui/widgets/pilotswidget.cpp
  79. 4 3
      src/gui/widgets/pilotswidget.h
  80. 48 55
      src/gui/widgets/settingswidget.cpp
  81. 5 1
      src/gui/widgets/settingswidget.h
  82. 15 2
      src/gui/widgets/settingswidget.ui
  83. 14 14
      src/gui/widgets/tailswidget.cpp
  84. 2 2
      src/gui/widgets/tailswidget.h
  85. 208 0
      src/gui/widgets/totalswidget.cpp
  86. 64 0
      src/gui/widgets/totalswidget.h
  87. 570 0
      src/gui/widgets/totalswidget.ui
  88. 37 115
      src/opl.h
  89. 1 1
      src/testing/atimer.cpp
  90. 1 2
      src/testing/atimer.h
  91. 2 3
      src/testing/importCrewlounge/importcrewlounge.cpp
  92. 14 13
      src/testing/importCrewlounge/processaircraft.cpp
  93. 0 1
      src/testing/importCrewlounge/processaircraft.h
  94. 29 28
      src/testing/importCrewlounge/processflights.cpp
  95. 7 6
      src/testing/importCrewlounge/processpilots.cpp
  96. 21 22
      src/testing/randomgenerator.cpp
  97. 6 6
      src/testing/randomgenerator.h

+ 3 - 0
.gitignore

@@ -83,6 +83,9 @@ openPilotLog.vcxproj.filters
 
 openPilotLog.vcxproj.user
 
+.vscode/
+build/
+
 # Disable localization updates
 l10n/
 # DS files

+ 26 - 2
CMakeLists.txt

@@ -75,9 +75,12 @@ set(PROJECT_SOURCES
     src/gui/widgets/pilotswidget.h
     src/gui/widgets/pilotswidget.cpp
     src/gui/widgets/pilotswidget.ui
-    src/gui/widgets/settingswidget.cpp
     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
     # Verification
     src/gui/verification/validationstate.h
     src/gui/verification/userinput.h
@@ -111,6 +114,27 @@ set(PROJECT_SOURCES
     src/classes/jsonhelper.cpp
     src/classes/md5sum.h
     src/classes/md5sum.cpp
+    src/classes/time.h
+    src/classes/time.cpp
+
+    # Database Entries
+    src/database/flightentry.h
+    src/database/flightentry.cpp
+    src/database/aircraftentry.h
+    src/database/aircraftentry.cpp
+    src/database/tailentry.h
+    src/database/tailentry.cpp
+    src/database/airportentry.h
+    src/database/airportentry.cpp
+    src/database/pilotentry.h
+    src/database/pilotentry.cpp
+    src/database/simulatorentry.h
+    src/database/simulatorentry.cpp
+    src/database/currencyentry.h
+    src/database/currencyentry.cpp
+
+    src/database/previousexperienceentry.h
+    src/database/previousexperienceentry.cpp
 
     # Namespaces
     src/functions/calc.h
@@ -122,7 +146,7 @@ set(PROJECT_SOURCES
     src/functions/statistics.cpp
     src/functions/datetime.h
     src/functions/datetime.cpp
-    src/functions/time.h
+
 
     # Database
     src/database/database.h

+ 207 - 188
assets/database/database_schema.sql

@@ -3,11 +3,11 @@ CREATE TABLE IF NOT EXISTS 'pilots' (
 	'pilot_id'	INTEGER NOT NULL,
 	'lastname'	TEXT NOT NULL,
 	'firstname'	TEXT,
-	'alias'	TEXT,
+        'alias'		TEXT,
 	'company'	TEXT,
 	'employeeid'	TEXT,
-	'phone'	TEXT,
-	'email'	TEXT,
+        'phone'		TEXT,
+        'email'		TEXT,
 	PRIMARY KEY('pilot_id' AUTOINCREMENT)
 );
 DROP TABLE IF EXISTS 'tails';
@@ -15,8 +15,8 @@ CREATE TABLE IF NOT EXISTS 'tails' (
 	'tail_id'	INTEGER NOT NULL,
 	'registration'	TEXT NOT NULL,
 	'company'	TEXT,
-	'make'	TEXT,
-	'model'	TEXT,
+        'make'		TEXT,
+        'model'		TEXT,
 	'variant'	TEXT,
 	'multipilot'	INTEGER,
 	'multiengine'	INTEGER,
@@ -27,27 +27,27 @@ CREATE TABLE IF NOT EXISTS 'tails' (
 DROP TABLE IF EXISTS 'flights';
 CREATE TABLE IF NOT EXISTS 'flights' (
 	'flight_id'	INTEGER NOT NULL,
-	'doft'	NUMERIC NOT NULL,
-	'dept'	TEXT NOT NULL,
-	'dest'	TEXT NOT NULL,
-	'tofb'	INTEGER NOT NULL,
-	'tonb'	INTEGER NOT NULL,
-	'pic'	INTEGER NOT NULL,
-	'acft'	INTEGER NOT NULL,
-	'tblk'	INTEGER NOT NULL,
-	'tSPSE'	INTEGER,
-	'tSPME'	INTEGER,
-	'tMP'	INTEGER,
+        'doft'		NUMERIC NOT NULL,
+        'dept'		TEXT NOT NULL,
+        'dest'		TEXT NOT NULL,
+        'tofb'		INTEGER NOT NULL,
+        'tonb'		INTEGER NOT NULL,
+        'pic'		INTEGER NOT NULL,
+        'acft'		INTEGER NOT NULL,
+        'tblk'		INTEGER NOT NULL,
+        'tSPSE'		INTEGER,
+        'tSPME'		INTEGER,
+        'tMP'		INTEGER,
 	'tNIGHT'	INTEGER,
-	'tIFR'	INTEGER,
-	'tPIC'	INTEGER,
+        'tIFR'		INTEGER,
+        'tPIC'		INTEGER,
 	'tPICUS'	INTEGER,
-	'tSIC'	INTEGER,
-	'tDUAL'	INTEGER,
-	'tFI'	INTEGER,
-	'tSIM'	INTEGER,
+        'tSIC'		INTEGER,
+        'tDUAL'		INTEGER,
+        'tFI'		INTEGER,
+        'tSIM'		INTEGER,
 	'pilotFlying'	INTEGER,
-	'toDay'	INTEGER,
+        'toDay'		INTEGER,
 	'toNight'	INTEGER,
 	'ldgDay'	INTEGER,
 	'ldgNight'	INTEGER,
@@ -64,12 +64,12 @@ CREATE TABLE IF NOT EXISTS 'flights' (
 DROP TABLE IF EXISTS 'aircraft';
 CREATE TABLE IF NOT EXISTS 'aircraft' (
 	'aircraft_id'	INTEGER NOT NULL,
-	'make'	TEXT,
-	'model'	TEXT,
+        'make'		TEXT,
+        'model'		TEXT,
 	'variant'	TEXT,
-	'name'	TEXT,
-	'iata'	TEXT,
-	'icao'	TEXT,
+        'name'		TEXT,
+        'iata'		TEXT,
+        'icao'		TEXT,
 	'multipilot'	INTEGER,
 	'multiengine'	INTEGER,
 	'engineType'	INTEGER,
@@ -79,11 +79,11 @@ CREATE TABLE IF NOT EXISTS 'aircraft' (
 DROP TABLE IF EXISTS 'airports';
 CREATE TABLE IF NOT EXISTS 'airports' (
 	'airport_id'	INTEGER NOT NULL,
-	'icao'	TEXT NOT NULL,
-	'iata'	TEXT,
-	'name'	TEXT,
-	'lat'	REAL,
-	'long'	REAL,
+        'icao'		TEXT NOT NULL,
+        'iata'		TEXT,
+        'name'		TEXT,
+        'lat'		REAL,
+        'long'		REAL,
 	'country'	TEXT,
 	'tzolson'	TEXT,
 	PRIMARY KEY('airport_id' AUTOINCREMENT)
@@ -99,13 +99,13 @@ DROP TABLE IF EXISTS 'changelog';
 CREATE TABLE IF NOT EXISTS 'changelog' (
 	'revision'	INTEGER NOT NULL,
 	'comment'	TEXT,
-	'date'	NUMERIC,
+        'date'		NUMERIC,
 	PRIMARY KEY('revision' AUTOINCREMENT)
 );
 DROP TABLE IF EXISTS 'simulators';
 CREATE TABLE IF NOT EXISTS 'simulators' (
 	'session_id'	INTEGER NOT NULL,
-	'date'	NUMERIC NOT NULL,
+        'date'		NUMERIC NOT NULL,
 	'totalTime'	INTEGER NOT NULL,
 	'deviceType'	TEXT NOT NULL,
 	'aircraftType'	TEXT,
@@ -113,219 +113,238 @@ CREATE TABLE IF NOT EXISTS 'simulators' (
 	'remarks'	TEXT,
 	PRIMARY KEY('session_id' AUTOINCREMENT)
 );
-
+DROP TABLE IF EXISTS 'previousExperience';
+CREATE TABLE 'previousExperience' (
+        'tblk'		INTEGER,
+        'tSPSE'		INTEGER,
+        'tSPME'		INTEGER,
+        'tMP'		INTEGER,
+        'tNIGHT'	INTEGER,
+        'tIFR'		INTEGER,
+        'tPIC'		INTEGER,
+        'tPICUS'	INTEGER,
+        'tSIC'		INTEGER,
+        'tDUAL'		INTEGER,
+        'tFI'		INTEGER,
+        'tSIM'		INTEGER,
+        'toDay'		INTEGER,
+        'toNight'	INTEGER,
+        'ldgDay'	INTEGER,
+        'ldgNight'	INTEGER,
+        'autoland'	INTEGER
+);
 DROP VIEW IF EXISTS 'viewDefault';
 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' 
+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  
-INNER JOIN pilots on flights.pic = pilots.pilot_id  
-INNER JOIN tails on flights.acft = tails.tail_id  
+INNER JOIN pilots on flights.pic = pilots.pilot_id
+INNER JOIN tails on flights.acft = tails.tail_id
 ORDER BY date 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' 
+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)), 
-remarks 
+        SELECT (session_id * -1),
+        date,
+        null, null, null, null,
+        'SIM',
+        null,
+        aircraftType,
+        registration,
+        deviceType,
+        printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)),
+        remarks
 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'  
+        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;
 
 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'    
+        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),  
-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)),  
-remarks  
+        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)),
+        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'  
+        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;
 
 DROP VIEW IF EXISTS 'viewTails';
 CREATE VIEW viewTails AS  
 SELECT  tail_id AS 'ID',  
-registration AS 'Registration',  
-make||' '||model AS 'Type',  
-company AS 'Company'  
+        registration AS 'Registration',
+        make||' '||model AS 'Type',
+        company AS 'Company'
 FROM tails WHERE model IS NOT NULL AND variant IS NULL  
 UNION  
 SELECT  tail_id AS 'ID',  
-registration AS 'Registration',  
-make||' '||model||'-'||variant AS 'Type',  
-company AS 'Company'  
+        registration AS 'Registration',
+        make||' '||model||'-'||variant AS 'Type',
+        company AS 'Company'
 FROM tails WHERE variant IS NOT NULL;
 
 DROP VIEW IF EXISTS 'viewPilots';
 CREATE VIEW viewPilots AS  
 SELECT  pilot_id AS 'ID',  
-lastname AS 'Last Name',  
-firstname AS 'First Name',  
-company AS 'Company'  
+        lastname AS 'Last Name',
+        firstname AS 'First Name',
+        company AS 'Company'
 FROM pilots;
 
 DROP VIEW IF EXISTS 'viewTotals';
 CREATE VIEW viewTotals AS  
 SELECT  printf('%02d',CAST(SUM(tblk) AS INT)/60)||':'||printf('%02d',CAST(SUM(tblk) AS INT)%60) AS 'TOTAL',  
-printf('%02d',CAST(SUM(tSPSE) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPSE) AS INT)%60) AS 'SP SE',  
-printf('%02d',CAST(SUM(tSPME) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPME) AS INT)%60) AS 'SP ME',  
-printf('%02d',CAST(SUM(tNIGHT) AS INT)/60)||':'||printf('%02d',CAST(SUM(tNIGHT) AS INT)%60) AS 'NIGHT',  
-printf('%02d',CAST(SUM(tIFR) AS INT)/60)||':'||printf('%02d',CAST(SUM(tIFR) AS INT)%60) AS 'IFR',  
-printf('%02d',CAST(SUM(tPIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPIC) AS INT)%60) AS 'PIC',  
-printf('%02d',CAST(SUM(tPICUS) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPICUS) AS INT)%60) AS 'PICUS',  
-printf('%02d',CAST(SUM(tSIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIC) AS INT)%60) AS 'SIC',  
-printf('%02d',CAST(SUM(tDual) AS INT)/60)||':'||printf('%02d',CAST(SUM(tDual) AS INT)%60) AS 'DUAL',  
-printf('%02d',CAST(SUM(tFI) AS INT)/60)||':'||printf('%02d',CAST(SUM(tFI) AS INT)%60) AS 'INSTRUCTOR',  
-printf('%02d',CAST(SUM(tSIM) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIM) AS INT)%60) AS 'SIMULATOR',  
-printf('%02d',CAST(SUM(tMP) AS INT)/60)||':'||printf('%02d',CAST(SUM(tMP) AS INT)%60) AS 'MultPilot',  
-CAST(SUM(toDay) AS INT) AS 'TO Day', 
-CAST(SUM(toNight) AS INT) AS 'TO Night',  
-CAST(SUM(ldgDay) AS INT) AS 'LDG Day', 
-CAST(SUM(ldgNight) AS INT) AS 'LDG Night'  
+        printf('%02d',CAST(SUM(tSPSE) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPSE) AS INT)%60) AS 'SP SE',
+        printf('%02d',CAST(SUM(tSPME) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSPME) AS INT)%60) AS 'SP ME',
+        printf('%02d',CAST(SUM(tNIGHT) AS INT)/60)||':'||printf('%02d',CAST(SUM(tNIGHT) AS INT)%60) AS 'NIGHT',
+        printf('%02d',CAST(SUM(tIFR) AS INT)/60)||':'||printf('%02d',CAST(SUM(tIFR) AS INT)%60) AS 'IFR',
+        printf('%02d',CAST(SUM(tPIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPIC) AS INT)%60) AS 'PIC',
+        printf('%02d',CAST(SUM(tPICUS) AS INT)/60)||':'||printf('%02d',CAST(SUM(tPICUS) AS INT)%60) AS 'PICUS',
+        printf('%02d',CAST(SUM(tSIC) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIC) AS INT)%60) AS 'SIC',
+        printf('%02d',CAST(SUM(tDual) AS INT)/60)||':'||printf('%02d',CAST(SUM(tDual) AS INT)%60) AS 'DUAL',
+        printf('%02d',CAST(SUM(tFI) AS INT)/60)||':'||printf('%02d',CAST(SUM(tFI) AS INT)%60) AS 'INSTRUCTOR',
+        printf('%02d',CAST(SUM(tSIM) AS INT)/60)||':'||printf('%02d',CAST(SUM(tSIM) AS INT)%60) AS 'SIMULATOR',
+        printf('%02d',CAST(SUM(tMP) AS INT)/60)||':'||printf('%02d',CAST(SUM(tMP) AS INT)%60) AS 'MultPilot',
+        CAST(SUM(toDay) AS INT) AS 'TO Day',
+        CAST(SUM(toNight) AS INT) AS 'TO Night',
+        CAST(SUM(ldgDay) AS INT) AS 'LDG Day',
+        CAST(SUM(ldgNight) AS INT) AS 'LDG Night'
 FROM flights;
 
 DROP VIEW IF EXISTS 'viewExport';
 CREATE VIEW viewExport AS
 SELECT  flight_id,
-doft as 'Date',
-dept AS 'Dept',
-printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time Out',
-dest AS 'Dest',
-printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time In ',
-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',
-toDay AS 'Take-Off Day',
-ldgDay AS 'Landings Day',
-toNight AS 'Take-Off Night',
-ldgNight AS 'Landings Night',
-(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'
+        doft as 'Date',
+        dept AS 'Dept',
+        printf('%02d',(tofb/60))||':'||printf('%02d',(tofb%60)) AS 'Time Out',
+        dest AS 'Dest',
+        printf('%02d',(tonb/60))||':'||printf('%02d',(tonb%60)) AS 'Time In ',
+        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',
+        toDay AS 'Take-Off Day',
+        ldgDay AS 'Landings Day',
+        toNight AS 'Take-Off Night',
+        ldgNight AS 'Landings Night',
+        (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),
-date,
-null,  null,  null,  null,
-aircraftType,
-registration,
-null,  null,  null,
-'SIM',
-null,  null,  null,  null,  null,  null,  null,  null,  null,  null, null,
-deviceType,  printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)),
-remarks
+        date,
+        null,  null,  null,  null,
+        aircraftType,
+        registration,
+        null,  null,  null,
+        'SIM',
+        null,  null,  null,  null,  null,  null,  null,  null,  null,  null, null,
+        deviceType,  printf('%02d',(totalTime/60))||':'||printf('%02d',(totalTime%60)),
+        remarks
 FROM simulators
 ORDER BY date DESC;

+ 18 - 12
main.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -34,10 +34,9 @@
 #include <QTranslator>
 
 /*!
- *  Helper functions that prepare and set up the application
+ * \brief init - Sets up the logging facilities, loads the user settings and sets
+ * up the application style before the MainWindow is instantiated
  */
-namespace Main {
-
 void init()
 {
     LOG << "Setting up / verifying Application Directories...";
@@ -61,17 +60,24 @@ void init()
     //ATranslator::installTranslator(OPL::Translations::English);
 }
 
-bool firstRun()
+/*!
+ * \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 false;
+        return 1;
     }
+
     Settings::write(Settings::Main::SetupComplete, true);
     LOG << "Initial Setup Completed successfully";
-    return true;
+    QMessageBox mb;
+    mb.setText("Initial set-up has been completed successfully.<br><br>Please re-start the application.");
+    mb.exec();
+    return 0;
 }
-} // namespace Main
 
 int main(int argc, char *argv[])
 {
@@ -80,7 +86,8 @@ int main(int argc, char *argv[])
     QCoreApplication::setOrganizationDomain(ORGDOMAIN);
     QCoreApplication::setApplicationName(APPNAME);
 
-    // Check for another instance already running
+    // 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.";
@@ -88,12 +95,11 @@ int main(int argc, char *argv[])
     }
 
     // Set Up the Application
-    Main::init();
+    init();
 
     // Check for First Run and launch Setup Wizard
     if (!Settings::read(Settings::Main::SetupComplete).toBool())
-        if(!Main::firstRun())
-            return 0;
+        return firstRun();
 
     // Create Main Window and set Window Icon acc. to Platform
     MainWindow w;

+ 14 - 8
mainwindow.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -25,16 +25,22 @@
 #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
-#include "src/testing/randomgenerator.h"
 void MainWindow::doDebugStuff()
 {
-    auto generator = OPL::RandomGenerator();
-    OPL::FlightEntry entry = generator.randomFlight();
-    DB->commit(entry);
-
-    auto nfd = NewFlightDialog(DB->getLastEntry(OPL::DbTable::Flights));
-    nfd.exec();
+    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();
 }
 
 MainWindow::MainWindow(QWidget *parent)

+ 1 - 1
mainwindow.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/downloadhelper.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/downloadhelper.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/jsonhelper.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/jsonhelper.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/md5sum.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/md5sum.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/runguard.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/runguard.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/settings.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/settings.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/style.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/classes/style.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 64 - 0
src/classes/time.cpp

@@ -0,0 +1,64 @@
+#include "time.h"
+
+namespace OPL {
+
+Time::Time()
+{
+}
+
+bool Time::isValidTimeOfDay() const
+{
+    return m_minutes <= MINUTES_PER_DAY;
+}
+
+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');
+}
+
+int32_t Time::toMinutes() const
+{
+    return m_minutes;
+}
+
+Time Time::fromString(const QString &timeString)
+{
+    const QStringList parts = timeString.split(QChar(':'));
+    if(parts.size() < 2)
+        return {};
+
+
+    int32_t hours = parts[0].toInt();
+    int32_t minutes = parts[1].toInt();
+
+    if(hours < 0 || minutes < 0)
+        return{};
+
+    return Time(hours * 60 + minutes);
+}
+
+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 {};
+
+    // 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);
+    } else {
+        // landing the day after take off
+        int minutesToMidnight = MINUTES_PER_DAY - offBlocks.m_minutes;
+        return Time(minutesToMidnight + onBlocks.m_minutes);
+    }
+}
+
+int32_t Time::blockMinutes(const Time &offBlocks, const Time &onBlocks)
+{
+    return blockTime(offBlocks, onBlocks).toMinutes();
+}
+
+} // namespace OPL

+ 60 - 0
src/classes/time.h

@@ -0,0 +1,60 @@
+#ifndef TIME_H
+#define TIME_H
+
+#include <QtCore>
+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).
+ */
+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) {};
+
+    /**
+     * @brief isValidTimeOfDay - determines whether the instance can be converted to a time hh:mm
+     * @return true if the total amount of minutes does not exceed one day.
+     */
+    bool isValidTimeOfDay() const;
+
+    /**
+     * @brief toString returns the time as hh:mm
+     */
+    const QString toString() const;
+
+    /**
+     * @brief toMinutes - returns the number of minutes in the time Object
+     */
+    int32_t toMinutes() const;
+
+    /**
+     * @brief fromString create a Time Object from a String formatted as hh:mm
+     * @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);
+
+    /**
+     * @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
+     */
+    int32_t timeElapsed(const Time &other);
+
+    static Time blockTime(const Time &offBlocks, const Time& onBlocks);
+    static int32_t blockMinutes(const Time &offBlocks, const Time& onBlocks);
+};
+
+}// namespace OPL
+
+#endif // TIME_H

+ 39 - 0
src/database/aircraftentry.cpp

@@ -0,0 +1,39 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "aircraftentry.h"
+
+namespace OPL {
+
+AircraftEntry::AircraftEntry()
+    : Row(DbTable::Aircraft, 0)
+{}
+
+AircraftEntry::AircraftEntry(const RowData_T &row_data)
+    : Row(DbTable::Aircraft, 0, row_data)
+{}
+
+AircraftEntry::AircraftEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Aircraft, row_id, row_data)
+{}
+
+const QString AircraftEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+} // namespace OPL

+ 105 - 0
src/database/aircraftentry.h

@@ -0,0 +1,105 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef AIRCRAFTENTRY_H
+#define AIRCRAFTENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing an Aircraft entry.
+ * \details
+ * In this context an aircraft refers to the aircraft TYPE (Boeing 737, Airbus A320,...) and
+ * could be seen as an analogy for a class. The aircraft 'instances' are called TAILS and are
+ * stored in the tails database (A Boeing 737 with registration (tail) LN-ENL for example).
+ *
+ * Aircraft = All aircraft with a common type that share its traits
+ * Tail - A specific aircraft of that type
+ *
+ * The aircraft table in the database contains templates of various aircraft types
+ * and is used to provide auto-completion when the user adds a new tail to the logbook.
+ */
+class AircraftEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("aircraft");
+public:
+    AircraftEntry();
+    AircraftEntry(const RowData_T &row_data);
+    AircraftEntry(int row_id, const RowData_T &row_data);
+    const QString getTableName() const override;
+
+    /*!
+     * \brief The aircrafts manufacturer (Airbus, Boeing,...)
+     */
+    static const inline QString MAKE = QStringLiteral("make");
+    /*!
+     * \brief The aircraft model (A320, B737,...)
+     */
+    static const inline QString MODEL = QStringLiteral("model");
+    /*!
+     * \brief The aircraft variant( A320-<b>200<\b>, B737-<b>800<\b>)
+     */
+    static const inline QString VARIANT = QStringLiteral("variant");
+    /*!
+     * \brief (optional) The aircraft common name ("Beluga",...)
+     */
+    static const inline QString NAME = QStringLiteral("name");
+    /*!
+     * \brief The aircraft types iata code
+     */
+    static const inline QString IATA = QStringLiteral("iata");
+    /*!
+     * \brief The aircraft types icao code
+     */
+    static const inline QString ICAO = QStringLiteral("icao");
+    /*!
+     * \brief Wether the aircraft requires more than one pilot (stored in the database as boolean)
+     */
+    static const inline QString MULTI_PILOT = QStringLiteral("multipilot");
+    /*!
+     * \brief Wether the aircraft has more than one engine (stored in the database as a boolean)
+     */
+    static const inline QString MULTI_ENGINE = QStringLiteral("multiengine");
+    /*!
+     * \brief The aircrafts engine type. Stored in the database as an integer
+     * \details
+     * <ul>
+     * <li> 0 - Single Engine Piston <\li>
+     * <li> 1 - Multi Engine Piston <\li>
+     * <li> 2 - Turboprop <\li>
+     * <li> 3 - Jet <\li>
+     * <\ul>
+     */
+    static const inline QString ENGINE_TYPE = QStringLiteral("engineType");
+    /*!
+     * \brief The aircrafts weight class. Stored in the database as an integer
+     * \details
+     * <ul>
+     * <li> 0 - Light <\li>
+     * <li> 1 - Medium <\li>
+     * <li> 2 - Heavy <\li>
+     * <li> 3 - Super Heavy <\li>
+     * <\ul>
+     */
+    static const inline QString WEIGHT_CLASS = QStringLiteral("weightClass");
+};
+
+} // namespace OPL
+
+
+#endif // AIRCRAFTENTRY_H

+ 49 - 0
src/database/airportentry.cpp

@@ -0,0 +1,49 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "airportentry.h"
+
+namespace OPL {
+
+AirportEntry::AirportEntry()
+    : Row(DbTable::Airports, 0)
+{}
+
+AirportEntry::AirportEntry(const RowData_T &row_data)
+    : Row(DbTable::Airports, 0, row_data)
+{}
+
+AirportEntry::AirportEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Airports, row_id, row_data)
+{}
+
+const QString AirportEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+const QString AirportEntry::getIataCode() const
+{
+    return getData().value(IATA).toString();
+}
+
+const QString AirportEntry::getIcaoCode() const
+{
+    return getData().value(ICAO).toString();
+}
+
+} // namespace OPL

+ 89 - 0
src/database/airportentry.h

@@ -0,0 +1,89 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef AIRPORTENTRY_H
+#define AIRPORTENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing an Airport entry. See Row class for details.
+ */
+class AirportEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("airports");
+public:
+    AirportEntry();
+    AirportEntry(const RowData_T &row_data);
+    AirportEntry(int row_id, const RowData_T &row_data);
+    const QString getTableName() const override;
+
+    /*!
+     * \brief return the airports IATA code (3-letter)
+     */
+    const QString getIataCode() const;
+
+    /*!
+     * \brief return the airports ICAO code (4-letter)
+     */
+    const QString getIcaoCode() const;
+
+    /*!
+     * \brief The ICAO code is a 4-letter alphanumeric identifier for airports
+     */
+    const static inline QString ICAO           = QStringLiteral("icao");
+    /*!
+     * \brief The IATA code is a 3-letter alphanumeric identifier for airports
+     */
+    const static inline QString IATA           = QStringLiteral("iata");
+    /*!
+     * \brief The airports common name
+     */
+    const static inline QString NAME           = QStringLiteral("name");
+    /*!
+     * \brief The airports latitude. Stored as a double
+     */
+    const static inline QString LAT            = QStringLiteral("lat");
+
+    /*!
+     * \brief The airports longitude. Stored as a double
+     */
+    const static inline QString LON            = QStringLiteral("long");
+
+    /*!
+     * \brief The country the airport is located in
+     */
+    const static inline QString COUNTRY        = QStringLiteral("country");
+    /*!
+     * \brief The altitude aboe mea sea level the airport is located at.
+     */
+    const static inline QString ALTITIDUE      = QStringLiteral("alt");
+
+    /*!
+     * \brief The airports timezone Offset from UTC
+     */
+    const static inline QString UTC_OFFSET     = QStringLiteral("utcoffset");
+    /*!
+     * \brief The timezone (Olson classification) the airport is situated in
+     */
+    const static inline QString TZ_OLSON       = QStringLiteral("tzolson");
+};
+
+} // namespace OPL
+
+#endif // AIRPORTENTRY_H

+ 39 - 0
src/database/currencyentry.cpp

@@ -0,0 +1,39 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "currencyentry.h"
+
+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)
+{}
+
+const QString CurrencyEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+} // namespace OPL

+ 53 - 0
src/database/currencyentry.h

@@ -0,0 +1,53 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef CURRENCYENTRY_H
+#define CURRENCYENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing a Currency entry. See Row class for details.
+ * \details An Entry in the currencies table represents an item with an expiry date
+ * and is used to track those. Typical example would be medical licenses, type rating
+ * validations or route certifications.
+ */
+class CurrencyEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("currencies");
+public:
+    CurrencyEntry();
+    CurrencyEntry(const RowData_T &row_data);
+    CurrencyEntry(int row_id, const RowData_T &row_data);
+
+    const QString getTableName() const override;
+
+
+    /*!
+    * \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");
+};
+
+} // namespace OPL
+
+#endif // CURRENCYENTRY_H

+ 104 - 19
src/database/database.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -41,7 +41,7 @@ bool Database::connect()
     }
 
 
-    LOG << "Database connection established.";
+    LOG << "Database connection established: " + databaseFile.absoluteFilePath();
     // Enable foreign key restrictions
     QSqlQuery query;
     query.prepare(QStringLiteral("PRAGMA foreign_keys = ON;"));
@@ -386,6 +386,7 @@ bool Database::insert(const OPL::Row &new_row)
     } else {
         DEB << "Unable to commit.";
         DEB << "Query: " << statement;
+        DEB << "Bound Values: " << query.boundValues();
         DEB << "Query Error: " << query.lastError().text();
         lastError = query.lastError();
         return false;
@@ -469,6 +470,105 @@ int Database::getLastEntry(OPL::DbTable table)
     }
 }
 
+const RowData_T Database::getTotals(bool includePreviousExperience)
+{
+    QString statement = "SELECT"
+        " SUM(tblk) AS tblk,"
+        " SUM(tSPSE) AS tSPSE,"
+        " SUM(tSPME) AS tSPME,"
+        " SUM(tMP) AS tMP,"
+        " SUM(tPIC) AS tPIC,"
+        " SUM(tSIC) AS tSIC,"
+        " SUM(tDUAL) AS tDUAL,"
+        " SUM(tFI) AS tFI,"
+        " SUM(tPICUS) AS tPICUS,"
+        " SUM(tNIGHT) AS tNIGHT,"
+        " SUM(tIFR) AS tIFR,"
+        " SUM(tSIM) AS tSIM,"
+        " SUM(toDay) AS toDay,"
+        " SUM(toNight) AS toNight,"
+        " SUM(ldgDay) AS ldgDay,"
+        " SUM(ldgNight) AS ldgNight"
+        " FROM flights";
+
+    QSqlQuery query;
+    query.prepare(statement);
+    if (!query.exec()) {
+        DEB << "SQL error: " << query.lastError().text();
+        DEB << "Statement: " << query.lastQuery();
+        lastError = query.lastError();
+        return {}; // return invalid Row
+    }
+
+    RowData_T entry_data;
+    if(query.next()) {
+        auto r = query.record(); // retreive record
+        if (r.count() == 0)  // row is empty
+            return {};
+
+        for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
+            if(!r.value(i).isNull()) {
+                entry_data.insert(r.fieldName(i), r.value(i));
+            }
+        }
+    }
+
+    if(!includePreviousExperience) {
+        return entry_data;
+    }
+
+    statement = "SELECT"
+                " SUM(tblk) AS tblk,"
+                " SUM(tSPSE) AS tSPSE,"
+                " SUM(tSPME) AS tSPME,"
+                " SUM(tMP) AS tMP,"
+                " SUM(tPIC) AS tPIC,"
+                " SUM(tSIC) AS tSIC,"
+                " SUM(tDUAL) AS tDUAL,"
+                " SUM(tFI) AS tFI,"
+                " SUM(tPICUS) AS tPICUS,"
+                " SUM(tNIGHT) AS tNIGHT,"
+                " SUM(tIFR) AS tIFR,"
+                " SUM(tSIM) AS tSIM,"
+                " SUM(toDay) AS toDay,"
+                " SUM(toNight) AS toNight,"
+                " SUM(ldgDay) AS ldgDay,"
+                " SUM(ldgNight) AS ldgNight"
+                " FROM previousExperience";
+    query.prepare(statement);
+
+    if (!query.exec()) {
+        DEB << "SQL error: " << query.lastError().text();
+        DEB << "Statement: " << query.lastQuery();
+        lastError = query.lastError();
+        return {}; // return invalid Row
+    }
+
+    RowData_T prev_exp_data;
+    if(query.next()) {
+        auto r = query.record(); // retreive record
+        if (r.count() == 0)  // row is empty
+            return {};
+
+        for (int i = 0; i < r.count(); i++){ // iterate through fields to get key:value map
+            if(!r.value(i).isNull()) {
+                prev_exp_data.insert(r.fieldName(i), r.value(i));
+            }
+        }
+    }
+
+    // add up the two query results
+    for(auto it = prev_exp_data.begin(); it != prev_exp_data.end(); it++) {
+        int prevXpValue = it.value().toInt();
+        int entryValue = entry_data.value(it.key()).toInt();
+
+        const QVariant sum = prevXpValue + entryValue;
+        it.value() = sum;
+    }
+
+    return prev_exp_data;
+}
+
 QList<int> Database::getForeignKeyConstraints(int foreign_row_id, OPL::DbTable table)
 {
     QString statement = QLatin1String("SELECT ROWID FROM flights WHERE ");
@@ -536,22 +636,7 @@ QVector<QVariant> Database::customQuery(QString statement, int return_values)
 
 QVector<RowData_T> Database::getTable(OPL::DbTable table)
 {
-    auto query_str = QStringLiteral("SELECT * FROM ");
-    switch (table) {
-    case OPL::DbTable::Pilots:
-        query_str.append(OPL::Db::TABLE_PILOTS);
-        break;
-    case OPL::DbTable::Tails:
-        query_str.append(OPL::Db::TABLE_TAILS);
-        break;
-    case OPL::DbTable::Flights:
-        query_str.append(OPL::Db::TABLE_FLIGHTS);
-        break;
-    case OPL::DbTable::Currencies:
-        query_str.append(OPL::Db::TABLE_CURRENCIES);
-    default:
-        break;
-    }
+    const QString query_str = QStringLiteral("SELECT * FROM ") + GLOBALS->getDbTableName(table);
 
     QSqlQuery q;
     q.prepare(query_str);
@@ -709,7 +794,7 @@ bool Database::resetUserData()
     for (const auto& table : DB->getUserTables()) {
         query.prepare(QLatin1String("DELETE FROM ") + OPL::GLOBALS->getDbTableName(table));
         if (!query.exec()) {
-            DEB << "Error: " << query.lastError().text();
+            lastError = query.lastError();
             return false;
         }
     }

+ 39 - 1
src/database/database.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -32,6 +32,13 @@
 #include <QSqlField>
 
 #include "src/classes/paths.h"
+#include "src/database/aircraftentry.h"
+#include "src/database/airportentry.h"
+#include "src/database/currencyentry.h"
+#include "src/database/flightentry.h"
+#include "src/database/pilotentry.h"
+#include "src/database/simulatorentry.h"
+#include "src/database/tailentry.h"
 #include "src/opl.h"
 #include "src/database/row.h"
 
@@ -207,6 +214,30 @@ public:
         return OPL::PilotEntry(row_id, data);
     }
 
+    /*!
+     * \brief get the database entry for the logbook owner (self)
+     */
+    inline OPL::PilotEntry getLogbookOwner()
+    {
+        auto data = getRowData(OPL::DbTable::Pilots, 1);
+        data.insert(OPL::PilotEntry::ROWID, 1);
+        return OPL::PilotEntry(1, data);
+    }
+
+    /*!
+     * \brief Set the database entry for the logbook owner (self)
+     */
+    inline bool setLogbookOwner(RowData_T &ownerData)
+    {
+        if(ownerData.value(OPL::PilotEntry::LASTNAME).isNull()) {
+            lastError = QSqlError("Logbook owners last name is mandatory.");
+            return false;
+        }
+
+        ownerData.insert(OPL::PilotEntry::ROWID, 1);
+        return commit(OPL::PilotEntry(1, ownerData));
+    }
+
     /*!
      * \brief retreives a TailEntry from the database. See row class for details.
      */
@@ -327,6 +358,13 @@ public:
 
 
 
+    /*!
+     * @brief Retreive the total time of all flight entries in the databas
+     * @param includePreviousExperience determines whether experience from previous logbooks
+     * is included.
+     * @return The sum of all entries in the flights table
+     */
+    const RowData_T getTotals(bool includePreviousExperience);
 signals:
     /*!
      * \brief updated is emitted whenever the database contents have been updated.

+ 17 - 0
src/database/databasecache.cpp

@@ -1,3 +1,20 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
 #include "databasecache.h"
 #include "src/database/database.h"
 #include "src/opl.h"

+ 17 - 0
src/database/databasecache.h

@@ -1,3 +1,20 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
 #ifndef DATABASECACHE_H
 #define DATABASECACHE_H
 #include "src/opl.h"

+ 4 - 1
src/database/dbsummary.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,6 +16,9 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "dbsummary.h"
+#include "QtCore/qstringliteral.h"
+#include "QtSql/qsqldatabase.h"
+#include "QtSql/qsqlquery.h"
 
 namespace OPL {
 

+ 2 - 3
src/database/dbsummary.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -17,8 +17,7 @@
  */
 #ifndef DBSUMMARY_H
 #define DBSUMMARY_H
-
-#include "src/database/database.h"
+#include <QtCore>
 
 namespace OPL {
 

+ 39 - 0
src/database/flightentry.cpp

@@ -0,0 +1,39 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "flightentry.h"
+
+namespace OPL {
+
+FlightEntry::FlightEntry()
+    : Row(DbTable::Flights, 0)
+{}
+
+FlightEntry::FlightEntry(const RowData_T &row_data)
+    : Row(DbTable::Flights, 0, row_data)
+{}
+
+FlightEntry::FlightEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Flights, row_id, row_data)
+{}
+
+const QString FlightEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+} // namespace OPL

+ 70 - 0
src/database/flightentry.h

@@ -0,0 +1,70 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef FLIGHTENTRY_H
+#define FLIGHTENTRY_H
+#include "src/database/row.h"
+
+
+namespace OPL {
+/*!
+ * \brief A Row representing a Flight entry. See Row class for details.
+ */
+class FlightEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("flights");
+public:
+    FlightEntry();
+    FlightEntry(const RowData_T &row_data);
+    FlightEntry(int row_id, const RowData_T &row_data);
+
+    const QString getTableName() const override;
+
+    const static inline QString ROWID          = QStringLiteral("flight_id");
+    const static inline QString DOFT           = QStringLiteral("doft");
+    const static inline QString DEPT           = QStringLiteral("dept");
+    const static inline QString DEST           = QStringLiteral("dest");
+    const static inline QString TOFB           = QStringLiteral("tofb");
+    const static inline QString TONB           = QStringLiteral("tonb");
+    const static inline QString PIC            = QStringLiteral("pic");
+    const static inline QString ACFT           = QStringLiteral("acft");
+    const static inline QString TBLK           = QStringLiteral("tblk");
+    const static inline QString TSPSE          = QStringLiteral("tSPSE");
+    const static inline QString TSPME          = QStringLiteral("tSPME");
+    const static inline QString TMP            = QStringLiteral("tMP");
+    const static inline QString TNIGHT         = QStringLiteral("tNIGHT");
+    const static inline QString TIFR           = QStringLiteral("tIFR");
+    const static inline QString TPIC           = QStringLiteral("tPIC");
+    const static inline QString TPICUS         = QStringLiteral("tPICUS");
+    const static inline QString TSIC           = QStringLiteral("tSIC");
+    const static inline QString TDUAL          = QStringLiteral("tDUAL");
+    const static inline QString TFI            = QStringLiteral("tFI");
+    const static inline QString TSIM           = QStringLiteral("tSIM");
+    const static inline QString PILOTFLYING    = QStringLiteral("pilotFlying");
+    const static inline QString TODAY          = QStringLiteral("toDay");
+    const static inline QString TONIGHT        = QStringLiteral("toNight");
+    const static inline QString LDGDAY         = QStringLiteral("ldgDay");
+    const static inline QString LDGNIGHT       = QStringLiteral("ldgNight");
+    const static inline QString AUTOLAND       = QStringLiteral("autoland");
+    const static inline QString SECONDPILOT    = QStringLiteral("secondPilot");
+    const static inline QString THIRDPILOT     = QStringLiteral("thirdPilot");
+    const static inline QString APPROACHTYPE   = QStringLiteral("approachType");
+    const static inline QString FLIGHTNUMBER   = QStringLiteral("flightNumber");
+    const static inline QString REMARKS        = QStringLiteral("remarks");
+};
+} // namespace OPL
+#endif // FLIGHTENTRY_H

+ 49 - 0
src/database/pilotentry.cpp

@@ -0,0 +1,49 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "pilotentry.h"
+
+namespace OPL {
+
+PilotEntry::PilotEntry()
+    : Row(DbTable::Pilots, 0)
+{}
+
+PilotEntry::PilotEntry(const RowData_T &row_data)
+    : Row(DbTable::Pilots, 0, row_data)
+{}
+
+PilotEntry::PilotEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Pilots, row_id, row_data)
+{}
+
+const QString PilotEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+const QString PilotEntry::getLastName() const
+{
+    return getData().value(LASTNAME).toString();
+}
+
+const QString PilotEntry::getFirstName() const
+{
+    return getData().value(FIRSTNAME).toString();
+}
+
+} // namespace OPL

+ 80 - 0
src/database/pilotentry.h

@@ -0,0 +1,80 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef PILOTENTRY_H
+#define PILOTENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing a Pilot entry. See Row class for details.
+ */
+class PilotEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("pilots");
+public:
+    PilotEntry();
+    PilotEntry(const RowData_T &row_data);
+    PilotEntry(int row_id, const RowData_T &row_data);
+    const QString getTableName() const override;
+
+    /*!
+     * \brief Return the pilots last name
+     */
+    const QString getLastName()  const;
+
+    /*!
+     * \brief Return the pilots first name
+     */
+    const QString getFirstName() const;
+
+    const static inline QString ROWID           = QStringLiteral("pilot_id");
+    /*!
+     * \brief The sql column name for the pilots last name
+     */
+    const static inline QString LASTNAME        = QStringLiteral("lastname");
+    /*!
+     * \brief The sql column name for the pilots first name
+     */
+    const static inline QString FIRSTNAME       = QStringLiteral("firstname");
+
+    /*!
+     * \brief The sql column name for an alias for the pilot
+     */
+    const static inline QString ALIAS           = QStringLiteral("alias");
+    /*!
+     * \brief The company the pilots works for
+     */
+    const static inline QString COMPANY         = QStringLiteral("company");
+    /*!
+     * \brief The sql column name for the pilots employee number
+     */
+    const static inline QString EMPLOYEEID      = QStringLiteral("employeeid");
+    /*!
+     * \brief The sql column name for a pilots phone number
+     */
+    const static inline QString PHONE           = QStringLiteral("phone");
+    /*!
+     * \brief the sql column name for a pilots email address
+     */
+    const static inline QString EMAIL           = QStringLiteral("email");
+};
+
+} // namespace OPL
+
+#endif // PILOTENTRY_H

+ 39 - 0
src/database/previousexperienceentry.cpp

@@ -0,0 +1,39 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "previousexperienceentry.h"
+
+namespace OPL {
+
+PreviousExperienceEntry::PreviousExperienceEntry()
+    : Row(DbTable::PreviousExperience, 0)
+{}
+
+PreviousExperienceEntry::PreviousExperienceEntry(const RowData_T &row_data)
+    : Row(DbTable::PreviousExperience, 0, row_data)
+{}
+
+PreviousExperienceEntry::PreviousExperienceEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::PreviousExperience, row_id, row_data)
+{}
+
+const QString PreviousExperienceEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+} // namespace OPL

+ 57 - 0
src/database/previousexperienceentry.h

@@ -0,0 +1,57 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef PREVIOUSEXPERIENCEENTRY_H
+#define PREVIOUSEXPERIENCEENTRY_H
+#include "src/database/flightentry.h"
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing an Airport entry. See Row class for details.
+ */
+class PreviousExperienceEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("previousExperience");
+public:
+    PreviousExperienceEntry();
+    PreviousExperienceEntry(const RowData_T &row_data);
+    PreviousExperienceEntry(int row_id, const RowData_T &row_data);
+    const QString getTableName() const override;
+
+    // these literals already exist in the FlightEntry class, so we can just copy them
+    const static inline QString TBLK           = OPL::FlightEntry::TBLK;
+    const static inline QString TSPSE          = OPL::FlightEntry::TSPSE;
+    const static inline QString TSPME          = OPL::FlightEntry::TSPME;
+    const static inline QString TMP            = OPL::FlightEntry::TMP;
+    const static inline QString TNIGHT         = OPL::FlightEntry::TNIGHT;
+    const static inline QString TIFR           = OPL::FlightEntry::TIFR;
+    const static inline QString TPIC           = OPL::FlightEntry::TPIC;
+    const static inline QString TPICUS         = OPL::FlightEntry::TPICUS;
+    const static inline QString TSIC           = OPL::FlightEntry::TSIC;
+    const static inline QString TDUAL          = OPL::FlightEntry::TDUAL;
+    const static inline QString TFI            = OPL::FlightEntry::TFI;
+    const static inline QString TSIM           = OPL::FlightEntry::TSIM;
+    const static inline QString TODAY          = OPL::FlightEntry::TODAY;
+    const static inline QString TONIGHT        = OPL::FlightEntry::TONIGHT;
+    const static inline QString LDGDAY         = OPL::FlightEntry::LDGDAY;
+    const static inline QString LDGNIGHT       = OPL::FlightEntry::LDGNIGHT;
+};
+
+} // namespace OPL
+#endif // PREVIOUSEXPERIENCEENTRY_H

+ 16 - 92
src/database/row.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -32,6 +32,11 @@ Row::Row(DbTable table_name)
     rowId = 0; // new entry
 };
 
+Row::Row()
+{
+    valid = false;
+}
+
 Row::Row(OPL::DbTable table_name, int row_id, const RowData_T &row_data)
     : table(table_name), rowId(row_id), rowData(row_data)
 {
@@ -64,18 +69,22 @@ OPL::DbTable Row::getTable() const
     return table;
 }
 
+const QString Row::getPosition() const
+{
+    return QString("Table: %1 / RowID: %2").arg(OPL::GLOBALS->getDbTableName(table), QString::number(rowId));
+}
+
 const QString Row::getTableName() const
 {
-    return OPL::GLOBALS->getDbTableName(table);
+    return {};
 }
 
-//TODO: Remove when tweaking for performance. Used for debugging
-const QString Row::getPosition() const
+bool Row::isValid() const
 {
-    return QString("Table: %1 / RowID: %2").arg(OPL::GLOBALS->getDbTableName(table), QString::number(rowId));
+    return hasData && valid;
 }
 
-//TODO: Remove when tweaking for performance. Used for debugging
+//Used for debugging
 OPL::Row::operator QString() const
 {
     if (!isValid()) {
@@ -122,90 +131,5 @@ OPL::Row::operator QString() const
     return QString();
 }
 
-AircraftEntry::AircraftEntry()
-    : Row(DbTable::Aircraft, 0)
-{}
-
-AircraftEntry::AircraftEntry(const RowData_T &row_data)
-    : Row(DbTable::Aircraft, 0, row_data)
-{}
-
-AircraftEntry::AircraftEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Aircraft, row_id, row_data)
-{}
-
-
-TailEntry::TailEntry()
-    : Row(DbTable::Tails, 0)
-{}
-
-TailEntry::TailEntry(const RowData_T &row_data)
-    : Row(DbTable::Tails, 0, row_data)
-{}
-
-TailEntry::TailEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Tails, row_id, row_data)
-{}
-
-PilotEntry::PilotEntry()
-    : Row(DbTable::Pilots, 0)
-{}
-
-PilotEntry::PilotEntry(const RowData_T &row_data)
-    : Row(DbTable::Pilots, 0, row_data)
-{}
-
-PilotEntry::PilotEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Pilots, row_id, row_data)
-{}
-
-
-SimulatorEntry::SimulatorEntry()
-    : Row(DbTable::Simulators, 0)
-{}
-
-SimulatorEntry::SimulatorEntry(const RowData_T &row_data)
-    : Row(DbTable::Simulators, 0, row_data)
-{}
-
-SimulatorEntry::SimulatorEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Simulators, row_id, row_data)
-{}
-
-FlightEntry::FlightEntry()
-    : Row(DbTable::Flights, 0)
-{}
-
-FlightEntry::FlightEntry(const RowData_T &row_data)
-    : Row(DbTable::Flights, 0, row_data)
-{}
-
-FlightEntry::FlightEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Flights, row_id, row_data)
-{}
-
-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)
-{}
-
-AirportEntry::AirportEntry()
-    : Row(DbTable::Airports, 0)
-{}
-
-AirportEntry::AirportEntry(const RowData_T &row_data)
-    : Row(DbTable::Airports, 0, row_data)
-{}
-
-AirportEntry::AirportEntry(int row_id, const RowData_T &row_data)
-    : Row(DbTable::Airports, row_id, row_data)
-{}
-
 } // namespace OPL
+

+ 50 - 92
src/database/row.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -40,28 +40,73 @@ namespace OPL {
  * The Identifying information can be accessed with getRowId and getTable() / getTableName().
  *
  * For convenience and readabilty, subclasses exist that have the table property pre-set. These rows are then
- * referred to as entries. See AircraftEntry, FlightEntry etc.
+ * referred to as entries. See AircraftEntry, FlightEntry etc. These subclasses have public static members which
+ * hold the column names used in the sql database. These can be used to access the data held in the row by column.
  */
 class Row
 {
 public:
-    Row() { valid = false;} // Require specifying position
+
+    /*!
+     * \brief Create a new empty row entry
+     */
+    Row();
+    /*!
+     * \brief Create a row entry specifying its table, row id and row data.
+     */
     Row(OPL::DbTable table_name, int row_id, const RowData_T &row_data);
+    /*!
+     * \brief Create a row entry specifying its table and row id.
+     */
     Row(OPL::DbTable table_name, int row_id);
+
+    /*!
+     * \brief Create a row entry specifying its table name.
+     * \param table_name
+     */
     Row(OPL::DbTable table_name);
 
     Row(const Row&) = default;
     Row& operator=(const Row&) = default;
 
+    /*!
+     * \brief get the Row Data contained in the Row
+     * \details The row data is a Map where the sql column name is the key and its value is the value.
+     */
     const RowData_T& getData() const;
+
     void setData(const RowData_T &value);
+
+    /*!
+     * \brief Get the entries row id in the database
+     */
     int getRowId() const;
+
+    /*!
+     * \brief Set the entries row id in the database
+     */
     void setRowId(int value);
+
     OPL::DbTable getTable() const;
-    const QString getTableName() const;
+
+    /*!
+     * \brief returns a string representation of the entries position in the database (Table and Row ID)
+     */
     const QString getPosition() const;
 
-    bool isValid() const {return hasData && valid;}
+    /*!
+     * \brief get the name of the table in the sql database.
+     * \details This method has to be overwritten in any subclass to return the table name, this should be
+     * a purely virtual function but in order to be able to use row class instances this function is implemented
+     * to return an empty strring in the base class.
+     * \return The name of the table in the database containing a valid row, or an empty String
+     */
+    virtual const QString getTableName() const;
+
+    /*!
+     * \brief A Row entry is valid if its table and row are specified and if it contains row data.
+     */
+    bool isValid() const;
 
     /*!
      * \brief operator QString can be used for printing debug information to stdout
@@ -78,92 +123,5 @@ protected:
     bool valid = true;
 };
 
-/*!
- * \brief A Row representing an Aircraft entry. See Row class for details.
- */
-class AircraftEntry : public Row
-{
-public:
-    AircraftEntry();
-    AircraftEntry(const RowData_T &row_data);
-    AircraftEntry(int row_id, const RowData_T &row_data);
-};
-
-/*!
- * \brief A Row representing a Tail (Registration) entry. See Row class for details.
- */
-class TailEntry : public Row
-{
-public:
-    TailEntry();
-    TailEntry(const RowData_T &row_data);
-    TailEntry(int row_id, const RowData_T &row_data);
-
-    const QString registration() const { return getData().value(OPL::Db::TAILS_REGISTRATION).toString(); }
-    const QString type()         const { return getData().value(OPL::Db::TAILS_MAKE).toString(); } //TODO - Create String for make-model-variant
-};
-
-/*!
- * \brief A Row representing a Pilot entry. See Row class for details.
- */
-class PilotEntry : public Row
-{
-public:
-    PilotEntry();
-    PilotEntry(const RowData_T &row_data);
-    PilotEntry(int row_id, const RowData_T &row_data);
-
-    const QString lastName()  const { return getData().value(OPL::Db::PILOTS_LASTNAME).toString(); }
-    const QString firstName() const { return getData().value(OPL::Db::PILOTS_FIRSTNAME).toString(); }
-
-};
-
-/*!
- * \brief A Row representing a Simulator entry. See Row class for details.
- */
-class SimulatorEntry : public Row
-{
-public:
-    SimulatorEntry();
-    SimulatorEntry(const RowData_T &row_data);
-    SimulatorEntry(int row_id, const RowData_T &row_data);
-};
-
-/*!
- * \brief A Row representing a Flight entry. See Row class for details.
- */
-class FlightEntry : public Row
-{
-public:
-    FlightEntry();
-    FlightEntry(const RowData_T &row_data);
-    FlightEntry(int row_id, const RowData_T &row_data);
-};
-
-/*!
- * \brief A Row representing a Currency entry. See Row class for details.
- */
-class CurrencyEntry : public Row
-{
-public:
-    CurrencyEntry();
-    CurrencyEntry(const RowData_T &row_data);
-    CurrencyEntry(int row_id, const RowData_T &row_data);
-};
-
-/*!
- * \brief A Row representing an Airport entry. See Row class for details.
- */
-class AirportEntry : public Row
-{
-public:
-    AirportEntry();
-    AirportEntry(const RowData_T &row_data);
-    AirportEntry(int row_id, const RowData_T &row_data);
-
-    const QString iata() const { return getData().value(OPL::Db::AIRPORTS_IATA).toString(); }
-    const QString icao() const { return getData().value(OPL::Db::AIRPORTS_ICAO).toString(); }
-};
-
 } // namespace OPL
 #endif // ROW_H

+ 39 - 0
src/database/simulatorentry.cpp

@@ -0,0 +1,39 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "simulatorentry.h"
+
+namespace OPL {
+
+SimulatorEntry::SimulatorEntry()
+    : Row(DbTable::Simulators, 0)
+{}
+
+SimulatorEntry::SimulatorEntry(const RowData_T &row_data)
+    : Row(DbTable::Simulators, 0, row_data)
+{}
+
+SimulatorEntry::SimulatorEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Simulators, row_id, row_data)
+{}
+
+const QString SimulatorEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+} // namespace OPL

+ 69 - 0
src/database/simulatorentry.h

@@ -0,0 +1,69 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef SIMULATORENTRY_H
+#define SIMULATORENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing a Simulator entry. See Row class for details.
+ */
+class SimulatorEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("simulators");
+public:
+    SimulatorEntry();
+    SimulatorEntry(const RowData_T &row_data);
+    SimulatorEntry(int row_id, const RowData_T &row_data);
+
+    const QString getTableName() const override;
+
+    /*!
+     * \brief The sql column name for the row id
+     */
+    const static inline QString  ROWID       = QStringLiteral("session_id");
+    /*!
+     * \brief The sql column name for the date
+     */
+    const static inline QString  DATE        = QStringLiteral("date");
+    /*!
+     * \brief The sql column name for the total time
+     */
+    const static inline QString  TIME        = QStringLiteral("totalTime");
+    /*!
+     * \brief The sql column name for the simulator type (FNPT/FFS)
+     */
+    const static inline QString  TYPE        = QStringLiteral("deviceType");
+    /*!
+     * \brief The sql column name for the simulators aircraft type
+     */
+    const static inline QString  ACFT        = QStringLiteral("aircraftType");
+    /*!
+     * \brief The sql column name for the simulators registration
+     */
+    const static inline QString  REG         = QStringLiteral("registration");
+    /*!
+     * \brief The sql column name for remarks
+     */
+    const static inline QString  REMARKS     = QStringLiteral("remarks");
+};
+
+} // namespace OPL
+
+#endif // SIMULATORENTRY_H

+ 48 - 0
src/database/tailentry.cpp

@@ -0,0 +1,48 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "tailentry.h"
+
+namespace OPL {
+
+TailEntry::TailEntry()
+    : Row(DbTable::Tails, 0)
+{}
+
+TailEntry::TailEntry(const RowData_T &row_data)
+    : Row(DbTable::Tails, 0, row_data)
+{}
+
+TailEntry::TailEntry(int row_id, const RowData_T &row_data)
+    : Row(DbTable::Tails, row_id, row_data)
+{}
+
+const QString TailEntry::getTableName() const
+{
+    return TABLE_NAME;
+}
+
+const QString TailEntry::registration() const
+{
+    return getData().value(REGISTRATION).toString();
+}
+
+const QString TailEntry::type() const {
+    return getData().value(MAKE).toString();
+}
+
+} // namespace OPL

+ 109 - 0
src/database/tailentry.h

@@ -0,0 +1,109 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef TAILENTRY_H
+#define TAILENTRY_H
+#include "src/database/row.h"
+
+namespace OPL {
+
+/*!
+ * \brief A Row representing a Tail (Registration) entry.
+ * \details
+ * The tails table holds the various tails the user has added to his logbook.
+ * Within the program the term aircraft refers to an aircraft type and is stored
+ * in the aircraft database and is used as a template. A tail is a specific instance
+ * of an aircraft which is identified by its registration (tail).
+ */
+class TailEntry : public Row
+{
+    const static inline QString TABLE_NAME = QStringLiteral("tails");
+public:
+    TailEntry();
+    TailEntry(const RowData_T &row_data);
+    TailEntry(int row_id, const RowData_T &row_data);
+    const QString getTableName() const override;
+
+    /*!
+     * \brief Return the aircrafts registration
+     * \return
+     */
+    const QString registration() const;
+    /*!
+     * \brief Return the aircraft type
+     */
+    const QString type()         const; //TODO - Create String for make-model-variant
+
+    /*!
+     * \brief The entries row id in the database
+     */
+    const static inline QString ROWID            = QStringLiteral("tail_id");
+    /*!
+     * \brief The aircrafts registration ("LN-ENL", "D-ABCD")
+     */
+    const static inline QString REGISTRATION     = QStringLiteral("registration");
+    /*!
+     * \brief The company the aircraft is operated by
+     */
+    const static inline QString COMPANY          = QStringLiteral("company");
+    /*!
+     * \brief The aircrafts manufacturer
+     */
+    const static inline QString MAKE             = QStringLiteral("make");
+    /*!
+     * \brief The aircraft model
+     */
+    const static inline QString MODEL            = QStringLiteral("model");
+    /*!
+     * \brief The aircraft model variant
+     */
+    const static inline QString VARIANT          = QStringLiteral("variant");
+    /*!
+     * \brief Wether the aircraft requires more than one pilot (stored in the database as boolean)
+     */
+    static const inline QString MULTI_PILOT = QStringLiteral("multipilot");
+    /*!
+     * \brief Wether the aircraft has more than one engine (stored in the database as a boolean)
+     */
+    static const inline QString MULTI_ENGINE = QStringLiteral("multiengine");
+    /*!
+     * \brief The aircrafts engine type. Stored in the database as an integer
+     * \details
+     * <ul>
+     * <li> 0 - Single Engine Piston <\li>
+     * <li> 1 - Multi Engine Piston <\li>
+     * <li> 2 - Turboprop <\li>
+     * <li> 3 - Jet <\li>
+     * <\ul>
+     */
+    static const inline QString ENGINE_TYPE = QStringLiteral("engineType");
+    /*!
+     * \brief The aircrafts weight class. Stored in the database as an integer
+     * \details
+     * <ul>
+     * <li> 0 - Light <\li>
+     * <li> 1 - Medium <\li>
+     * <li> 2 - Heavy <\li>
+     * <li> 3 - Super Heavy <\li>
+     * <\ul>
+     */
+    static const inline QString WEIGHT_CLASS = QStringLiteral("weightClass");
+};
+
+} // namespace OPL
+
+#endif // TAILENTRY_H

+ 21 - 21
src/functions/calc.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -315,23 +315,23 @@ void OPL::Calc::updateAutoTimes(int acft_id)
         auto flight = DB->getFlightEntry(item.toInt());
         auto flight_data = flight.getData();
 
-        if(acft_data.value(OPL::Db::TAILS_MULTIPILOT).toInt() == 0
-                && acft_data.value(OPL::Db::TAILS_MULTIENGINE) == 0) {
+        if(acft_data.value(OPL::TailEntry::MULTI_PILOT).toInt() == 0
+            && acft_data.value(OPL::TailEntry::MULTI_ENGINE) == 0) {
             DEB << "SPSE";
-            flight_data.insert(OPL::Db::FLIGHTS_TSPSE, flight_data.value(OPL::Db::FLIGHTS_TBLK));
-            flight_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
-            flight_data.insert(OPL::Db::FLIGHTS_TMP, QString());
-        } else if ((acft_data.value(OPL::Db::TAILS_MULTIPILOT) == 0
-                    && acft.getData().value(OPL::Db::TAILS_MULTIENGINE) == 1)) {
+            flight_data.insert(OPL::FlightEntry::TSPSE, flight_data.value(OPL::FlightEntry::TBLK));
+            flight_data.insert(OPL::FlightEntry::TSPME, QString());
+            flight_data.insert(OPL::FlightEntry::TMP, QString());
+        } else if ((acft_data.value(OPL::TailEntry::MULTI_PILOT) == 0
+                    && acft.getData().value(OPL::TailEntry::MULTI_ENGINE) == 1)) {
             DEB << "SPME";
-            flight_data.insert(OPL::Db::FLIGHTS_TSPME, flight_data.value(OPL::Db::FLIGHTS_TBLK));
-            flight_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
-            flight_data.insert(OPL::Db::FLIGHTS_TMP, QString());
-        } else if ((acft_data.value(OPL::Db::TAILS_MULTIPILOT) == 1)) {
+            flight_data.insert(OPL::FlightEntry::TSPME, flight_data.value(OPL::FlightEntry::TBLK));
+            flight_data.insert(OPL::FlightEntry::TSPSE, QString());
+            flight_data.insert(OPL::FlightEntry::TMP, QString());
+        } else if ((acft_data.value(OPL::TailEntry::MULTI_PILOT) == 1)) {
             DEB << "MPME";
-            flight_data.insert(OPL::Db::FLIGHTS_TMP, flight_data.value(OPL::Db::FLIGHTS_TBLK));
-            flight_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
-            flight_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
+            flight_data.insert(OPL::FlightEntry::TMP, flight_data.value(OPL::FlightEntry::TBLK));
+            flight_data.insert(OPL::FlightEntry::TSPSE, QString());
+            flight_data.insert(OPL::FlightEntry::TSPME, QString());
         }
         flight.setData(flight_data);
         DB->commit(flight);
@@ -359,14 +359,14 @@ void OPL::Calc::updateNightTimes()
 
         auto flt = DB->getFlightEntry(item.toInt());
         auto data = flt.getData();
-        auto dateTime = QDateTime(QDate::fromString(data.value(OPL::Db::FLIGHTS_DOFT).toString(), Qt::ISODate),
-                                  QTime().addSecs(data.value(OPL::Db::FLIGHTS_TOFB).toInt() * 60),
+        auto dateTime = QDateTime(QDate::fromString(data.value(OPL::FlightEntry::DOFT).toString(), Qt::ISODate),
+                                  QTime().addSecs(data.value(OPL::FlightEntry::TOFB).toInt() * 60),
                                   Qt::UTC);
-        data.insert(OPL::Db::FLIGHTS_TNIGHT,
-                    calculateNightTime(data.value(OPL::Db::FLIGHTS_DEPT).toString(),
-                                       data.value(OPL::Db::FLIGHTS_DEST).toString(),
+        data.insert(OPL::FlightEntry::TNIGHT,
+                    calculateNightTime(data.value(OPL::FlightEntry::DEPT).toString(),
+                                       data.value(OPL::FlightEntry::DEST).toString(),
                                        dateTime,
-                                       data.value(OPL::Db::FLIGHTS_TBLK).toInt(),
+                                       data.value(OPL::FlightEntry::TBLK).toInt(),
                                        night_angle));
         flt.setData(data);
         DB->commit(flt);

+ 8 - 7
src/functions/calc.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -24,7 +24,7 @@
 #include <cmath>
 #include <QDateTime>
 #include <QDebug>
-#include "src/functions/time.h"
+#include "src/classes/time.h"
 /*!
  * \brief The ACalc namespace provides various functions for calculations that are performed
  * outside of the database. This includes tasks like converting different units and formats,
@@ -144,8 +144,8 @@ struct NightTimeValues{
     {
         nightMinutes = calculateNightTime(dept, dest, departure_time, block_minutes, night_angle);
 
-        nightTime = OPL::Time::qTimefromMinutes(nightMinutes);
-        totalTime = OPL::Time::qTimefromMinutes(block_minutes);
+        nightTime = OPL::Time(nightMinutes);
+        totalTime = OPL::Time(block_minutes);
 
         if (nightMinutes == 0) { // all day
             takeOffNight = false;
@@ -166,13 +166,14 @@ struct NightTimeValues{
         }
 
     };
-    NightTimeValues(bool to_night, bool ldg_night, int night_minutes, QTime night_time, QTime 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;
-    QTime nightTime;
-    QTime totalTime;
+    OPL::Time nightTime;
+    OPL::Time totalTime;
 
     inline bool isAllDay()      {return (!takeOffNight  && !landingNight);}
     inline bool isAllNight()    {return ( takeOffNight  &&  landingNight);}

+ 1 - 1
src/functions/log.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 1
src/functions/log.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 2
src/functions/readcsv.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -18,7 +18,6 @@
 #ifndef READCSV_H
 #define READCSV_H
 
-#include "src/opl.h"
 #include<QtCore>
 
 namespace CSV {

+ 2 - 2
src/functions/statistics.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -132,7 +132,6 @@ QVector<QPair<QString, QString>> OPL::Statistics::totals()
     }
     return output;
 }
-
 /*!
  * \brief Calculates the date of expiry for the take-off and landing currency.
  *
@@ -166,3 +165,4 @@ QDate OPL::Statistics::currencyTakeOffLandingExpiry(int expiration_days)
 
     return expiration_date.addDays(expiration_days);;
 }
+

+ 1 - 1
src/functions/statistics.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 0 - 218
src/functions/time.h

@@ -1,218 +0,0 @@
-/*
- *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 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 <https://www.gnu.org/licenses/>.
- */
-#ifndef TIME_H
-#define TIME_H
-
-#include <QtCore>
-#include <QTime>
-#include "src/opl.h"
-
-namespace OPL::Time {
-
-/*!
- * \brief Converts a QTime to a String to be used in the UI
- */
-inline const QString toString(const QTime &time, OPL::FlightTimeFormat format = OPL::FlightTimeFormat::Default)
-{
-    switch (format) {
-    case OPL::FlightTimeFormat::Default:
-        return time.toString(QStringLiteral("hh:mm"));
-        break;
-    case OPL::FlightTimeFormat::Decimal:
-        return QString::number(((time.hour() * 60 + time.minute() )/60.0), 'f', 2);
-        break;
-    default:
-        return QString();
-    }
-}
-
-/*!
- * \brief Converts an integer of minutes as received from the Datbase to a String
- */
-inline const QString toString(int minutes_in, OPL::FlightTimeFormat format = OPL::FlightTimeFormat::Default)
-{
-    switch (format) {
-    case OPL::FlightTimeFormat::Default:
-    {
-        QString hour = QString::number(minutes_in / 60);
-        if (hour.size() < 2) {
-            hour.prepend(QStringLiteral("0"));
-        }
-        QString minute = QString::number(minutes_in % 60);
-        if (minute.size() < 2) {
-            minute.prepend(QStringLiteral("0"));
-        }
-        return hour + ':' + minute;
-    }
-    case OPL::FlightTimeFormat::Decimal:
-    {
-        int hour = minutes_in / 60;
-        double minute = (minutes_in % 60) / 60.0;
-        return QString::number((hour + minute), 'f', 2);
-    }
-    default:
-        return QString();
-    }
-
-}
-
-inline double toDecimalHours(const QTime &time){
-    return (time.hour() * 60 + time.minute()) / 60.0;
-}
-
-inline QTime qTimefromMinutes(int total_minutes)
-{
-    int minute = total_minutes % 60;
-    int hour = total_minutes / 60;
-
-    return QTime(hour, minute, 0);
-}
-
-inline const QTime fromString(QString time_string, OPL::FlightTimeFormat format = OPL::FlightTimeFormat::Default)
-{
-    switch (format) {
-    case OPL::FlightTimeFormat::Default:
-        return QTime::fromString(time_string, QStringLiteral("hh:mm"));
-        break;
-    case OPL::FlightTimeFormat::Decimal:
-    {
-        double decimal_time = time_string.toDouble();
-        int hour = decimal_time;
-        int minute = round((decimal_time - hour) * 60);
-        return QTime(hour, minute, 0);
-        break;
-    }
-    default:
-        return QTime();
-    }
-}
-
-inline const QTime fromString(const char* time_string, OPL::FlightTimeFormat format = OPL::FlightTimeFormat::Default)
-{
-    switch (format) {
-    case OPL::FlightTimeFormat::Default:
-        return QTime::fromString(time_string, QStringLiteral("hh:mm"));
-        break;
-    case OPL::FlightTimeFormat::Decimal:
-    {
-        double decimal_time = QString(time_string).toDouble();
-        int hour = decimal_time;
-        int minute = round((decimal_time - hour) * 60);
-        return QTime(hour, minute, 0);
-        break;
-    }
-    default:
-        return QTime();
-    }
-}
-
-inline int toMinutes(const QTime &time) {return time.hour() * 60 + time.minute();}
-inline int toMinutes(const QString &time_string) {return toMinutes(fromString(time_string));}
-
-inline QTime blocktime(const QTime &tofb, const QTime &tonb)
-{
-    QTime blocktime_out(0, 0); // initialise return value at midnight
-
-    if (tonb > tofb) { // landing same day
-        int block_seconds = tofb.secsTo(tonb);
-        blocktime_out = blocktime_out.addSecs(block_seconds);
-    } else { // landing next day
-        QTime midnight(0, 0);
-        int seconds = tofb.secsTo(midnight);
-        blocktime_out = blocktime_out.addSecs(seconds);
-        seconds = midnight.secsTo(tonb);
-        blocktime_out = blocktime_out.addSecs(seconds);
-    }
-    return blocktime_out;
-}
-
-inline QTime blocktime(const QString& tofb, const QString& tonb)
-{
-    QTime t_tofb = OPL::Time::fromString(tofb);
-    QTime t_tonb = OPL::Time::fromString(tonb);
-    return blocktime(t_tofb, t_tonb);
-}
-
-/*!
- * \brief blockMinutes calculates the total amount of minutes elapsed between
- * tofb and tonb
- */
-inline int blockMinutes(const QString& tofb, const QString& tonb)
-{
-    const QTime t_tofb = OPL::Time::fromString(tofb);
-    const QTime t_tonb = OPL::Time::fromString(tonb);
-    if (t_tofb.isValid() && t_tonb.isValid()) {
-        const auto tblk = OPL::Time::blocktime(t_tofb, t_tonb);
-        return OPL::Time::toMinutes(tblk);
-    } else
-        return 0;
-}
-
-/*!
- * \brief blockMinutes calculates the total amount of minutes elapsed between
- * tofb and tonb
- */
-inline int blockMinutes(const QTime& tofb, const QTime& tonb)
-{
-    if (tofb.isValid() && tonb.isValid()) {
-        const auto tblk = OPL::Time::blocktime(tofb, tonb);
-        return OPL::Time::toMinutes(tblk);
-    } else
-        return 0;
-}
-
-/*!
- * \brief verifies user input and formats to hh:mm
- * if the output is not a valid time, an empty string is returned. Accepts
- * input as hh:mm, h:mm, hhmm or hmm.
- * \param userinput from a QLineEdit
- * \return formatted QString "hh:mm" or Empty String
- */
-QT_DEPRECATED
-inline const QString formatTimeInput(QString user_input)
-{
-    LOG << "DEPRECATED";
-    QTime temp_time; //empty time object is invalid by default
-
-    bool contains_seperator = user_input.contains(':');
-    if (user_input.length() == 4 && !contains_seperator) {
-        temp_time = QTime::fromString(user_input, QStringLiteral("hhmm"));
-    } else if (user_input.length() == 3 && !contains_seperator) {
-        if (user_input.toInt() < 240) { //Qtime is invalid if time is between 000 and 240 for this case
-            QString tempstring = user_input.prepend(QStringLiteral("0"));
-            temp_time = QTime::fromString(tempstring, QStringLiteral("hhmm"));
-        } else {
-            temp_time = QTime::fromString(user_input, QStringLiteral("Hmm"));
-        }
-    } else if (user_input.length() == 4 && contains_seperator) {
-        temp_time = QTime::fromString(user_input, QStringLiteral("h:mm"));
-    } else if (user_input.length() == 5 && contains_seperator) {
-        temp_time = QTime::fromString(user_input, QStringLiteral("hh:mm"));
-    }
-
-    auto output = temp_time.toString(QStringLiteral("hh:mm"));
-
-    if (output.isEmpty()) {
-        DEB << "Time input is invalid.";
-    }
-    return output;
-}
-
-} // namespace OPL::Time
-
-#endif // TIME_H

+ 1 - 0
src/gui/dialogues/exporttocsvdialog.cpp

@@ -3,6 +3,7 @@
 #include "QtSql/qsqlrecord.h"
 #include "QtSql/qsqltablemodel.h"
 #include "QtWidgets/qfiledialog.h"
+#include "src/opl.h"
 #include "ui_exporttocsvdialog.h"
 #include "src/functions/readcsv.h"
 

+ 31 - 15
src/gui/dialogues/firstrundialog.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,6 +16,7 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "firstrundialog.h"
+#include "src/database/previousexperienceentry.h"
 #include "ui_firstrundialog.h"
 #include "src/opl.h"
 #include "src/database/database.h"
@@ -177,6 +178,15 @@ bool FirstRunDialog::finishSetup()
         return false;
     }
 
+    if (!setupPreviousExperienceEntry()) {
+        QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
+                                tr("Unable to execute database query<br>"
+                                   "The following error has occured:<br>%1"
+                                   ).arg(DB->lastError.text()));
+        message_box.exec();
+        return false;
+    }
+
     if (!writeCurrencies()) {
         QMessageBox message_box(QMessageBox::Critical, tr("Database setup failed"),
                                 tr("Unable to execute database query<br>"
@@ -291,7 +301,7 @@ bool FirstRunDialog::setupDatabase()
                                               "Would you like to download the latest database information?"
                                               "<br>(Recommended, Internet connection required)"),
                                QMessageBox::Yes | QMessageBox::No, this);
-    confirm.setDefaultButton(QMessageBox::No);
+    confirm.setDefaultButton(QMessageBox::Yes);
 
     if (confirm.exec() == QMessageBox::Yes) {
         useRessourceData = false;
@@ -321,17 +331,23 @@ bool FirstRunDialog::setupDatabase()
 
 bool FirstRunDialog::createUserEntry()
 {
-    QHash<QString, QVariant> data;
-    data.insert(OPL::Db::PILOTS_LASTNAME,   ui->lastnameLineEdit->text());
-    data.insert(OPL::Db::PILOTS_FIRSTNAME,  ui->firstnameLineEdit->text());
-    data.insert(OPL::Db::PILOTS_ALIAS,      QStringLiteral("self"));
-    data.insert(OPL::Db::PILOTS_EMPLOYEEID, ui->employeeidLineEdit->text());
-    data.insert(OPL::Db::PILOTS_PHONE,      ui->phoneLineEdit->text());
-    data.insert(OPL::Db::PILOTS_EMAIL,      ui->emailLineEdit->text());
-
-    auto pilot = OPL::PilotEntry(1, data);
+    OPL::RowData_T data;
+    data.insert(OPL::PilotEntry::LASTNAME,   ui->lastnameLineEdit->text());
+    data.insert(OPL::PilotEntry::FIRSTNAME,  ui->firstnameLineEdit->text());
+    data.insert(OPL::PilotEntry::ALIAS,      QStringLiteral("self"));
+    data.insert(OPL::PilotEntry::EMPLOYEEID, ui->employeeidLineEdit->text());
+    data.insert(OPL::PilotEntry::PHONE,      ui->phoneLineEdit->text());
+    data.insert(OPL::PilotEntry::EMAIL,      ui->emailLineEdit->text());
+
+    return DB->setLogbookOwner(data);
+}
 
-    return DB->commit(pilot);
+bool FirstRunDialog::setupPreviousExperienceEntry()
+{
+    OPL::RowData_T prevData;
+    prevData.insert(OPL::PreviousExperienceEntry::TBLK, 0);
+    auto pXpEntry = OPL::PreviousExperienceEntry(1, prevData);
+    return DB->commit(pXpEntry);
 }
 
 bool FirstRunDialog::writeCurrencies()
@@ -358,11 +374,11 @@ bool FirstRunDialog::writeCurrencies()
         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::Db::CURRENCIES_EXPIRYDATE, date_edit->date().toString(Qt::ISODate)}};
+            OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date_edit->date().toString(Qt::ISODate)}};
             if (enum_value == OPL::CurrencyName::Custom1)
-                row_data.insert(OPL::Db::CURRENCIES_CURRENCYNAME, ui->currCustom1LineEdit->text());
+                row_data.insert(OPL::CurrencyEntry::CURRENCYNAME, ui->currCustom1LineEdit->text());
             else if(enum_value == OPL::CurrencyName::Custom2)
-                row_data.insert(OPL::Db::CURRENCIES_CURRENCYNAME, ui->currCustom2LineEdit->text());
+                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<int>(enum_value), row_data);

+ 6 - 1
src/gui/dialogues/firstrundialog.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -117,6 +117,11 @@ private:
      */
     bool createUserEntry();
 
+    /*!
+     * \brief setupPreviousExperienceEntry - set up a stub database entry for previous experience
+     */
+    bool setupPreviousExperienceEntry();
+
     /*!
      * \brief writeCurrencies - submits the user input to the currencies table in the database
      */

+ 15 - 15
src/gui/dialogues/newairportdialog.cpp

@@ -51,14 +51,14 @@ void NewAirportDialog::loadAirportData(int row_id)
     //const auto airport_data = airport.getData();
     DEB << "Filling Airport Data: " << airport_data;
 
-    ui->nameLineEdit->setText(airport_data.value(OPL::Db::AIRPORTS_NAME).toString());
-    ui->icaoLineEdit->setText(airport_data.value(OPL::Db::AIRPORTS_ICAO).toString());
-    ui->iataLineEdit->setText(airport_data.value(OPL::Db::AIRPORTS_IATA).toString());
-    ui->latDoubleSpinBox->setValue(airport_data.value(OPL::Db::AIRPORTS_LAT).toDouble());
-    ui->lonDoubleSpinBox->setValue(airport_data.value(OPL::Db::AIRPORTS_LON).toDouble());
-    ui->countryLineEdit->setText(airport_data.value(OPL::Db::AIRPORTS_COUNTRY).toString());
-
-    const QString timezone = airport_data.value(OPL::Db::AIRPORTS_TZ_OLSON).toString();
+    ui->nameLineEdit->setText(airport_data.value(OPL::AirportEntry::NAME).toString());
+    ui->icaoLineEdit->setText(airport_data.value(OPL::AirportEntry::ICAO).toString());
+    ui->iataLineEdit->setText(airport_data.value(OPL::AirportEntry::IATA).toString());
+    ui->latDoubleSpinBox->setValue(airport_data.value(OPL::AirportEntry::LAT).toDouble());
+    ui->lonDoubleSpinBox->setValue(airport_data.value(OPL::AirportEntry::LON).toDouble());
+    ui->countryLineEdit->setText(airport_data.value(OPL::AirportEntry::COUNTRY).toString());
+
+    const QString timezone = airport_data.value(OPL::AirportEntry::TZ_OLSON).toString();
     DEB << "Timezone: " << timezone;
     if (timezone.isNull())
         WARN(tr("Unable to read timezone data for this airport. Please verify."));
@@ -109,13 +109,13 @@ void NewAirportDialog::on_buttonBox_accepted()
         return;
     // create Entry object
     OPL::RowData_T airport_data = {
-        {OPL::Db::AIRPORTS_NAME,     ui->nameLineEdit->text()},
-        {OPL::Db::AIRPORTS_ICAO,     ui->icaoLineEdit->text()},
-        {OPL::Db::AIRPORTS_IATA,     ui->iataLineEdit->text()},
-        {OPL::Db::AIRPORTS_LAT,      ui->latDoubleSpinBox->value()},
-        {OPL::Db::AIRPORTS_LON,      ui->lonDoubleSpinBox->value()},
-        {OPL::Db::AIRPORTS_TZ_OLSON, ui->timeZoneComboBox->currentText()},
-        {OPL::Db::AIRPORTS_COUNTRY,  ui->countryLineEdit->text()},
+        {OPL::AirportEntry::NAME,     ui->nameLineEdit->text()},
+        {OPL::AirportEntry::ICAO,     ui->icaoLineEdit->text()},
+        {OPL::AirportEntry::IATA,     ui->iataLineEdit->text()},
+        {OPL::AirportEntry::LAT,      ui->latDoubleSpinBox->value()},
+        {OPL::AirportEntry::LON,      ui->lonDoubleSpinBox->value()},
+        {OPL::AirportEntry::TZ_OLSON, ui->timeZoneComboBox->currentText()},
+        {OPL::AirportEntry::COUNTRY,  ui->countryLineEdit->text()},
     };
 
     OPL::AirportEntry entry(rowId, airport_data);

+ 93 - 119
src/gui/dialogues/newflightdialog.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,6 +16,8 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "newflightdialog.h"
+#include "src/classes/time.h"
+#include "src/database/database.h"
 #include "src/database/databasecache.h"
 #include "src/gui/verification/airportinput.h"
 #include "src/gui/verification/completerprovider.h"
@@ -104,12 +106,12 @@ void NewFlightDialog::setupRawInputValidation()
 {
     // Time Line Edits
     for (const auto& line_edit : *timeLineEdits) {
-        auto validator = new QRegularExpressionValidator(QRegularExpression("([01]?[0-9]|2[0-3]):?[0-5][0-9]?"), line_edit);
+        const auto validator = new QRegularExpressionValidator(OPL::RegEx::RX_TIME_ENTRY, line_edit);
         line_edit->setValidator(validator);
     }
     // Location Line Edits
     for (const auto& line_edit : *locationLineEdits) {
-        auto validator = new QRegularExpressionValidator(QRegularExpression("[a-zA-Z0-9]{1,4}"), line_edit);
+        const auto validator = new QRegularExpressionValidator(OPL::RegEx::RX_AIRPORT_CODE, line_edit);
         line_edit->setValidator(validator);
         line_edit->setCompleter(QCompleterProvider.getCompleter(CompleterProvider::Airports));
     }
@@ -167,8 +169,7 @@ void NewFlightDialog::readSettings()
 {
     ui->functionComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Function).toInt());
     ui->approachComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Approach).toInt());
-    ui->pilotFlyingCheckBox->setChecked(Settings::read(Settings::FlightLogging::PilotFlying).toBool());
-    ui->ifrCheckBox->setChecked(Settings::read(Settings::FlightLogging::LogIFR).toBool());
+    ui->flightRulesComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::LogIFR).toInt());
     ui->flightNumberLineEdit->setText(Settings::read(Settings::FlightLogging::FlightNumberPrefix).toString());
 }
 
@@ -184,52 +185,50 @@ void NewFlightDialog::fillWithEntryData()
     const auto &flight_data = flightEntry.getData();
 
     // Date of Flight
-    ui->doftLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DOFT).toString());
+    ui->doftLineEdit->setText(flight_data.value(OPL::FlightEntry::DOFT).toString());
     // Location
-    ui->deptLocationLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DEPT).toString());
-    ui->destLocationLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_DEST).toString());
+    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::toString(flight_data.value(OPL::Db::FLIGHTS_TOFB).toInt()));
-    ui->tonbTimeLineEdit->setText(OPL::Time::toString(flight_data.value(OPL::Db::FLIGHTS_TONB).toInt()));
-    ui->acftLineEdit->setText(DBCache->getTailsMap().value(flight_data.value(OPL::Db::FLIGHTS_ACFT).toInt()));
-    ui->picNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_PIC).toInt()));
-    ui->sicNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_SECONDPILOT).toInt()));
-    ui->thirdPilotNameLineEdit->setText(DBCache->getPilotNamesMap().value(flight_data.value(OPL::Db::FLIGHTS_THIRDPILOT).toInt()));
+    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->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<int, QString> functions = {
-        {0, OPL::Db::FLIGHTS_TPIC},
-        {1, OPL::Db::FLIGHTS_TPICUS},
-        {2, OPL::Db::FLIGHTS_TSIC},
-        {3, OPL::Db::FLIGHTS_TDUAL},
-        {4, OPL::Db::FLIGHTS_TFI},
+        {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)
             ui->functionComboBox->setCurrentIndex(i);
     }
     // Approach ComboBox
-    const QString& app = flight_data.value(OPL::Db::FLIGHTS_APPROACHTYPE).toString();
+    const QString& app = flight_data.value(OPL::FlightEntry::APPROACHTYPE).toString();
     if(app != QString()){
         ui->approachComboBox->setCurrentText(app);
     }
-    // Task
-    bool PF = flight_data.value(OPL::Db::FLIGHTS_PILOTFLYING).toBool();
-    ui->pilotFlyingCheckBox->setChecked(PF);
     // Flight Rules
-    bool time_ifr = flight_data.value(OPL::Db::FLIGHTS_TIFR).toBool();
-    ui->ifrCheckBox->setChecked(time_ifr);
+    bool time_ifr = flight_data.value(OPL::FlightEntry::TIFR).toBool();
+    int rulesIndex = time_ifr ? 1 : 0;
+    ui->flightRulesComboBox->setCurrentIndex(rulesIndex);
     // Take-Off and Landing
-    int TO =  flight_data.value(OPL::Db::FLIGHTS_TODAY).toInt()
-            + flight_data.value(OPL::Db::FLIGHTS_TONIGHT).toInt();
-    int LDG = flight_data.value(OPL::Db::FLIGHTS_LDGDAY).toInt()
-            + flight_data.value(OPL::Db::FLIGHTS_LDGNIGHT).toInt();
-    ui->takeOffSpinBox->setValue(TO);
-    ui->landingSpinBox->setValue(LDG);
+    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->remarksLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_REMARKS).toString());
+    ui->remarksLineEdit->setText(flight_data.value(OPL::FlightEntry::REMARKS).toString());
     // Flight Number
-    ui->flightNumberLineEdit->setText(flight_data.value(OPL::Db::FLIGHTS_FLIGHTNUMBER).toString());
+    ui->flightNumberLineEdit->setText(flight_data.value(OPL::FlightEntry::FLIGHTNUMBER).toString());
 
     for(const auto &line_edit : *mandatoryLineEdits)
         emit line_edit->editingFinished();
@@ -264,15 +263,13 @@ void NewFlightDialog::onGoodInputReceived(QLineEdit *line_edit)
 
     if (validationState.timesValid()) {
         updateBlockTimeLabel();
-        if (validationState.nightDataValid())
-            updateNightCheckBoxes();
     }
 }
 
 void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
 {
     DEB << line_edit->objectName() << " - Bad input received - " << line_edit->text();
-    line_edit->setStyleSheet(OPL::Styles::RED_BORDER);
+    line_edit->setStyleSheet(OPL::CssStyles::RED_BORDER);
     line_edit->setText(QString());
 
     if (mandatoryLineEdits->contains(line_edit))
@@ -283,8 +280,11 @@ void NewFlightDialog::onBadInputReceived(QLineEdit *line_edit)
 
 void NewFlightDialog::updateBlockTimeLabel()
 {
-    QTime tblk = OPL::Time::blocktime(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
-    ui->tblkDisplayLabel->setText(OPL::Time::toString(tblk));
+    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());
 }
 
 /*!
@@ -365,58 +365,63 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
     if(!validationState.allValid())
         return {};
 
+    // prepare the entry data
     OPL::RowData_T new_data;
+
     // Calculate Block and Night Time
-    const int block_minutes = OPL::Time::blockMinutes(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
+    const OPL::Time tofb = OPL::Time::fromString(ui->tofbTimeLineEdit->text());
+    const OPL::Time tonb = OPL::Time::fromString(ui->tonbTimeLineEdit->text());
+    const int block_minutes = OPL::Time::blockMinutes(tofb, tonb);
+
     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());
     // Mandatory data
-    new_data.insert(OPL::Db::FLIGHTS_DOFT, ui->doftLineEdit->text());
-    new_data.insert(OPL::Db::FLIGHTS_DEPT, ui->deptLocationLineEdit->text());
-    new_data.insert(OPL::Db::FLIGHTS_TOFB, OPL::Time::toMinutes(ui->tofbTimeLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_DEST, ui->destLocationLineEdit->text());
-    new_data.insert(OPL::Db::FLIGHTS_TONB, OPL::Time::toMinutes(ui->tonbTimeLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_TBLK, block_minutes);
+    new_data.insert(OPL::FlightEntry::DOFT, ui->doftLineEdit->text());
+    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());
+    new_data.insert(OPL::FlightEntry::TONB, tonb.toMinutes());
+    new_data.insert(OPL::FlightEntry::TBLK, block_minutes);
     // Night
-    new_data.insert(OPL::Db::FLIGHTS_TNIGHT, night_time_data.nightMinutes);
+    new_data.insert(OPL::FlightEntry::TNIGHT, night_time_data.nightMinutes);
     // Aircraft
     int acft_id = DBCache->getTailsMap().key(ui->acftLineEdit->text());
-    new_data.insert(OPL::Db::FLIGHTS_ACFT, acft_id);
+    new_data.insert(OPL::FlightEntry::ACFT, acft_id);
     const OPL::TailEntry acft_data = DB->getTailEntry(acft_id);
-    bool multi_pilot = acft_data.getData().value(OPL::Db::TAILS_MULTIPILOT).toBool();
-    bool multi_engine = acft_data.getData().value(OPL::Db::TAILS_MULTIENGINE).toBool();
+    bool multi_pilot = acft_data.getData().value(OPL::TailEntry::MULTI_PILOT).toBool();
+    bool multi_engine = acft_data.getData().value(OPL::TailEntry::MULTI_ENGINE).toBool();
 
     if (multi_pilot) {
-        new_data.insert(OPL::Db::FLIGHTS_TMP, block_minutes);
-        new_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
-        new_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
+        new_data.insert(OPL::FlightEntry::TMP, block_minutes);
+        new_data.insert(OPL::FlightEntry::TSPSE, QString());
+        new_data.insert(OPL::FlightEntry::TSPME, QString());
     } else if (!multi_pilot && !multi_engine) {
-        new_data.insert(OPL::Db::FLIGHTS_TMP, QString());
-        new_data.insert(OPL::Db::FLIGHTS_TSPSE, block_minutes);
-        new_data.insert(OPL::Db::FLIGHTS_TSPME, QString());
+        new_data.insert(OPL::FlightEntry::TMP, QString());
+        new_data.insert(OPL::FlightEntry::TSPSE, block_minutes);
+        new_data.insert(OPL::FlightEntry::TSPME, QString());
     } else if (!multi_pilot && multi_engine) {
-        new_data.insert(OPL::Db::FLIGHTS_TMP, QString());
-        new_data.insert(OPL::Db::FLIGHTS_TSPSE, QString());
-        new_data.insert(OPL::Db::FLIGHTS_TSPME, block_minutes);
+        new_data.insert(OPL::FlightEntry::TMP, QString());
+        new_data.insert(OPL::FlightEntry::TSPSE, QString());
+        new_data.insert(OPL::FlightEntry::TSPME, block_minutes);
     }
     // Pilots
-    new_data.insert(OPL::Db::FLIGHTS_PIC, DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()));
-    new_data.insert(OPL::Db::FLIGHTS_THIRDPILOT, DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text()));
+    new_data.insert(OPL::FlightEntry::PIC, DBCache->getPilotNamesMap().key(ui->picNameLineEdit->text()));
+    new_data.insert(OPL::FlightEntry::SECONDPILOT, DBCache->getPilotNamesMap().key(ui->sicNameLineEdit->text()));
+    new_data.insert(OPL::FlightEntry::THIRDPILOT, DBCache->getPilotNamesMap().key(ui->thirdPilotNameLineEdit->text()));
     // IFR time
-    if (ui->ifrCheckBox->isChecked()) {
-        new_data.insert(OPL::Db::FLIGHTS_TIFR, block_minutes);
+    if (ui->flightRulesComboBox->currentIndex() > 0) {
+        new_data.insert(OPL::FlightEntry::TIFR, block_minutes);
     } else {
-        new_data.insert(OPL::Db::FLIGHTS_TIFR, QString());
+        new_data.insert(OPL::FlightEntry::TIFR, QString());
     }
     // Function Times
     QStringList function_times = {
-        OPL::Db::FLIGHTS_TPIC,
-        OPL::Db::FLIGHTS_TPICUS,
-        OPL::Db::FLIGHTS_TSIC,
-        OPL::Db::FLIGHTS_TDUAL,
-        OPL::Db::FLIGHTS_TFI,
+        OPL::FlightEntry::TPIC,
+        OPL::FlightEntry::TPICUS,
+        OPL::FlightEntry::TSIC,
+        OPL::FlightEntry::TDUAL,
+        OPL::FlightEntry::TFI,
     };
 
     // Determine function times, zero out all values except one (use QString() iso 0 for correct handling of NULL in DB
@@ -441,63 +446,31 @@ OPL::RowData_T NewFlightDialog::prepareFlightEntryData()
         }
         break;
     }
-    // Pilot flying / Pilot monitoring
-    new_data.insert(OPL::Db::FLIGHTS_PILOTFLYING, ui->pilotFlyingCheckBox->isChecked());
+
     // Take-Off and Landing
-    if (ui->toNightCheckBox->isChecked()) {
-        new_data.insert(OPL::Db::FLIGHTS_TONIGHT, ui->takeOffSpinBox->value());
-        new_data.insert(OPL::Db::FLIGHTS_TODAY, 0);
-    } else {
-        new_data.insert(OPL::Db::FLIGHTS_TONIGHT, 0);
-        new_data.insert(OPL::Db::FLIGHTS_TODAY, ui->takeOffSpinBox->value());
-    }
-    if (ui->ldgNightCheckBox->isChecked()) {
-        new_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, ui->landingSpinBox->value());
-        new_data.insert(OPL::Db::FLIGHTS_LDGDAY, 0);
-    } else {
-        new_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, 0);
-        new_data.insert(OPL::Db::FLIGHTS_LDGDAY, ui->landingSpinBox->value());
-    }
+    int toDay    = night_time_data.takeOffNight ? 0 : ui->takeOffSpinBox->value();
+    int toNight  = night_time_data.takeOffNight ? ui->takeOffSpinBox->value() : 0;
+    int ldgDay   = night_time_data.landingNight ? 0 : ui->landingSpinBox->value();
+    int ldgNight = night_time_data.landingNight ? ui->landingSpinBox->value() : 0;
+
+    new_data.insert(OPL::FlightEntry::TODAY, toDay);
+    new_data.insert(OPL::FlightEntry::TONIGHT, toNight);
+    new_data.insert(OPL::FlightEntry::LDGDAY, ldgDay);
+    new_data.insert(OPL::FlightEntry::LDGNIGHT, ldgNight);
     if (ui->approachComboBox->currentText() == CAT_3) // ILS CAT III
-        new_data.insert(OPL::Db::FLIGHTS_AUTOLAND, ui->landingSpinBox->value());
+        new_data.insert(OPL::FlightEntry::AUTOLAND, ui->landingSpinBox->value());
+
+    // Pilot flying / Pilot monitoring
+    bool isPilotFlying = toDay + toNight + ldgDay + ldgNight > 0;
+    new_data.insert(OPL::FlightEntry::PILOTFLYING, isPilotFlying);
 
     // Additional Data
-    new_data.insert(OPL::Db::FLIGHTS_APPROACHTYPE, ui->approachComboBox->currentText());
-    new_data.insert(OPL::Db::FLIGHTS_FLIGHTNUMBER, ui->flightNumberLineEdit->text());
-    new_data.insert(OPL::Db::FLIGHTS_REMARKS, ui->remarksLineEdit->text());
+    new_data.insert(OPL::FlightEntry::APPROACHTYPE, ui->approachComboBox->currentText());
+    new_data.insert(OPL::FlightEntry::FLIGHTNUMBER, ui->flightNumberLineEdit->text());
+    new_data.insert(OPL::FlightEntry::REMARKS, ui->remarksLineEdit->text());
     return new_data;
 }
 
-/*!
- * \brief NewFlightDialog::updateNightCheckBoxes updates the check boxes for take-off and landing
- * at night. Returns the number of minutes of night time.
- * \return
- */
-void NewFlightDialog::updateNightCheckBoxes()
-{
-    // Calculate Night Time
-    const QString dept_date = (ui->doftLineEdit->text() + ui->tofbTimeLineEdit->text());
-    const auto dept_date_time = OPL::DateTime::fromString(dept_date);
-    const int block_minutes = OPL::Time::blockMinutes(ui->tofbTimeLineEdit->text(), ui->tonbTimeLineEdit->text());
-    const int night_angle = Settings::read(Settings::FlightLogging::NightAngle).toInt();
-    const auto night_values = OPL::Calc::NightTimeValues(
-                ui->deptLocationLineEdit->text(),
-                ui->destLocationLineEdit->text(),
-                dept_date_time,
-                block_minutes,
-                night_angle);
-    // set check boxes
-    if (night_values.takeOffNight)
-        ui->toNightCheckBox->setCheckState(Qt::Checked);
-    else
-        ui->toNightCheckBox->setCheckState(Qt::Unchecked);
-
-    if (night_values.landingNight)
-        ui->ldgNightCheckBox->setCheckState(Qt::Checked);
-    else
-        ui->ldgNightCheckBox->setCheckState(Qt::Unchecked);
-}
-
 /*!
  * \brief NewFlightDialog::toUpper - changes inserted text to upper case for IATA/ICAO airport codes and registrations.
  */
@@ -708,3 +681,4 @@ void NewFlightDialog::on_buttonBox_accepted()
         QDialog::accept();
     }
 }
+

+ 2 - 3
src/gui/dialogues/newflightdialog.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -24,9 +24,9 @@
 #include <QList>
 #include <QBitArray>
 
+#include "src/database/flightentry.h"
 #include "src/gui/verification/userinput.h"
 #include "src/opl.h"
-#include "src/database/row.h"
 #include "src/gui/verification/validationstate.h"
 
 namespace Ui {
@@ -125,7 +125,6 @@ private:
     void onBadInputReceived(QLineEdit *line_edit);
 
     void updateBlockTimeLabel();
-    void updateNightCheckBoxes();
     void setNightCheckboxes();
 
     bool addNewTail(QLineEdit& parent_line_edit);

+ 480 - 563
src/gui/dialogues/newflightdialog.ui

@@ -6,579 +6,182 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>1022</width>
-    <height>262</height>
+    <width>767</width>
+    <height>362</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Add New Flight</string>
   </property>
-  <layout class="QGridLayout" name="gridLayout_4">
-   <item row="0" column="0">
-    <spacer name="leftSpacer">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="5" column="5">
+    <widget class="QLineEdit" name="flightNumberLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
      </property>
-     <property name="sizeHint" stdset="0">
-      <size>
-       <width>23</width>
-       <height>203</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="0" column="1" colspan="3">
-    <layout class="QGridLayout" name="gridLayout_3">
-     <item row="0" column="0">
-      <layout class="QGridLayout" name="gridLayout">
-       <item row="0" column="0">
-        <widget class="QLabel" name="doftLabel">
-         <property name="text">
-          <string>Date of flight</string>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="3">
-        <widget class="QLabel" name="flightNumberLabel">
-         <property name="text">
-          <string>Flight Number</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="3">
-        <widget class="QLabel" name="sicLabel">
-         <property name="text">
-          <string>SIC</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="0">
-        <widget class="QLabel" name="tonbLabel">
-         <property name="text">
-          <string>On Blocks</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="4">
-        <widget class="QLineEdit" name="acftLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="3">
-        <widget class="QLabel" name="acftLabel">
-         <property name="text">
-          <string>Aircraft</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="3">
-        <widget class="QLabel" name="picLabel">
-         <property name="text">
-          <string>PIC</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="5" column="0">
-        <widget class="QLabel" name="tblkLabel">
-         <property name="text">
-          <string>Total Time</string>
-         </property>
-        </widget>
-       </item>
-       <item row="5" column="3">
-        <widget class="QLabel" name="remarksLabel">
-         <property name="text">
-          <string>Remarks</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="4">
-        <widget class="QLineEdit" name="flightNumberLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="deptLabel">
-         <property name="text">
-          <string>Departure</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QLineEdit" name="doftLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="placeholderText">
-          <string>YYYY-MM-DD</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QLabel" name="destLabel">
-         <property name="text">
-          <string>Destination</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="1">
-        <widget class="QLineEdit" name="destLocationLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="2">
-        <widget class="QLabel" name="doftDisplayLabel">
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QLineEdit" name="deptLocationLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="2">
-        <widget class="QLabel" name="deptNameLabel">
-         <property name="enabled">
-          <bool>false</bool>
-         </property>
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="font">
-          <font>
-           <italic>true</italic>
-          </font>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="4">
-        <widget class="QLineEdit" name="picNameLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="4">
-        <widget class="QLineEdit" name="sicNameLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="2">
-        <widget class="QLabel" name="destNameLabel">
-         <property name="enabled">
-          <bool>false</bool>
-         </property>
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="font">
-          <font>
-           <italic>true</italic>
-          </font>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="0">
-        <widget class="QLabel" name="tofbLabel">
-         <property name="text">
-          <string>Off Blocks</string>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="2">
-        <widget class="QLabel" name="tofbSpacerLabel">
-         <property name="enabled">
-          <bool>false</bool>
-         </property>
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="2">
-        <widget class="QLabel" name="tonbSpacerLabel">
-         <property name="enabled">
-          <bool>false</bool>
-         </property>
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-       <item row="5" column="1">
-        <widget class="QLabel" name="tblkDisplayLabel">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="text">
-          <string>00:00</string>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="3">
-        <widget class="QLabel" name="thirdPilotLabel">
-         <property name="text">
-          <string>Third Pilot</string>
-         </property>
-         <property name="alignment">
-          <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="1">
-        <widget class="QLineEdit" name="tonbTimeLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="5" column="4">
-        <widget class="QLineEdit" name="remarksLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="1">
-        <widget class="QLineEdit" name="tofbTimeLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="4">
-        <widget class="QLineEdit" name="thirdPilotNameLineEdit">
-         <property name="minimumSize">
-          <size>
-           <width>160</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>120</width>
-           <height>16777215</height>
-          </size>
-         </property>
-        </widget>
-       </item>
-       <item row="5" column="2">
-        <widget class="QLabel" name="submissionReadyLabel">
-         <property name="minimumSize">
-          <size>
-           <width>200</width>
-           <height>0</height>
-          </size>
-         </property>
-         <property name="maximumSize">
-          <size>
-           <width>200</width>
-           <height>16777215</height>
-          </size>
-         </property>
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-     <item row="0" column="1">
-      <widget class="Line" name="line_2">
-       <property name="orientation">
-        <enum>Qt::Vertical</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="2">
-      <layout class="QGridLayout" name="gridLayout_2">
-       <item row="0" column="0" colspan="2">
-        <widget class="QCheckBox" name="pilotFlyingCheckBox">
-         <property name="text">
-          <string>Pilot Flying</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="2">
-        <widget class="QCheckBox" name="ifrCheckBox">
-         <property name="text">
-          <string>IFR</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="takeOffLabel">
-         <property name="text">
-          <string>Take Off</string>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QSpinBox" name="takeOffSpinBox"/>
-       </item>
-       <item row="1" column="2">
-        <widget class="QCheckBox" name="toNightCheckBox">
-         <property name="text">
-          <string>Night</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="0">
-        <widget class="QLabel" name="landingLabel">
-         <property name="text">
-          <string>Landing</string>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="1">
-        <widget class="QSpinBox" name="landingSpinBox"/>
-       </item>
-       <item row="2" column="2">
-        <widget class="QCheckBox" name="ldgNightCheckBox">
-         <property name="text">
-          <string>Night</string>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="0">
-        <widget class="QLabel" name="functionLabel">
-         <property name="text">
-          <string>Function</string>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="1" colspan="2">
-        <widget class="QComboBox" name="functionComboBox"/>
-       </item>
-       <item row="4" column="0">
-        <widget class="QLabel" name="approachLabel">
-         <property name="text">
-          <string>Approach</string>
-         </property>
-        </widget>
-       </item>
-       <item row="4" column="1" colspan="2">
-        <widget class="QComboBox" name="approachComboBox"/>
-       </item>
-       <item row="5" column="0" colspan="3">
-        <widget class="QLabel" name="spacerLabel">
-         <property name="text">
-          <string/>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-    </layout>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
    </item>
-   <item row="0" column="4" rowspan="2">
-    <spacer name="rightSpacer">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
+   <item row="2" column="2">
+    <widget class="QLineEdit" name="deptLocationLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
      </property>
-     <property name="sizeHint" stdset="0">
+     <property name="maximumSize">
       <size>
-       <width>22</width>
-       <height>228</height>
+       <width>120</width>
+       <height>16777215</height>
       </size>
      </property>
-    </spacer>
+    </widget>
    </item>
-   <item row="1" column="1">
-    <widget class="QPushButton" name="pushButton_2">
+   <item row="3" column="5">
+    <widget class="QLineEdit" name="sicNameLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="4">
+    <widget class="QLabel" name="takeOffLabel">
      <property name="text">
-      <string>Details</string>
+      <string>Take Off</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="2">
-    <widget class="QToolButton" name="toolButton">
+   <item row="2" column="3">
+    <widget class="QLabel" name="deptNameLabel">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <italic>true</italic>
+      </font>
+     </property>
      <property name="text">
-      <string>?</string>
+      <string/>
      </property>
     </widget>
    </item>
-   <item row="1" column="3">
+   <item row="1" column="5">
+    <widget class="QLineEdit" name="acftLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="5">
+    <widget class="QSpinBox" name="takeOffSpinBox"/>
+   </item>
+   <item row="2" column="0">
+    <widget class="QLabel" name="deptLabel">
+     <property name="text">
+      <string>Departure</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="5">
+    <widget class="QLineEdit" name="thirdPilotNameLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0">
+    <widget class="QLabel" name="tonbLabel">
+     <property name="text">
+      <string>On Blocks</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="2">
+    <widget class="QLineEdit" name="destLocationLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="0">
+    <widget class="QLabel" name="tblkLabel">
+     <property name="text">
+      <string>Total Time</string>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="2">
+    <widget class="QLabel" name="tblkDisplayLabel">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="text">
+      <string>00:00</string>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="4" colspan="2">
     <widget class="QDialogButtonBox" name="buttonBox">
      <property name="enabled">
       <bool>true</bool>
@@ -591,30 +194,344 @@
      </property>
     </widget>
    </item>
+   <item row="5" column="2">
+    <widget class="QLineEdit" name="tonbTimeLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QLabel" name="destLabel">
+     <property name="text">
+      <string>Destination</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="4">
+    <widget class="QLabel" name="acftLabel">
+     <property name="text">
+      <string>Aircraft</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QLabel" name="tofbLabel">
+     <property name="text">
+      <string>Off Blocks</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="QLineEdit" name="doftLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="placeholderText">
+      <string>YYYY-MM-DD</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="3">
+    <widget class="QLabel" name="tofbSpacerLabel">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="5">
+    <widget class="QLineEdit" name="picNameLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="3">
+    <widget class="QLabel" name="destNameLabel">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="font">
+      <font>
+       <italic>true</italic>
+      </font>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="3">
+    <widget class="QLabel" name="tonbSpacerLabel">
+     <property name="enabled">
+      <bool>false</bool>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="5">
+    <widget class="QLineEdit" name="remarksLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="4">
+    <widget class="QLabel" name="remarksLabel">
+     <property name="text">
+      <string>Remarks</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="4">
+    <widget class="QLabel" name="flightNumberLabel">
+     <property name="text">
+      <string>Flight Number</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="4">
+    <widget class="QLabel" name="picLabel">
+     <property name="text">
+      <string>PIC</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="4">
+    <widget class="QLabel" name="sicLabel">
+     <property name="text">
+      <string>SIC</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="doftLabel">
+     <property name="text">
+      <string>Date of flight</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="4">
+    <widget class="QLabel" name="thirdPilotLabel">
+     <property name="text">
+      <string>Third Pilot</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="0">
+    <widget class="QLabel" name="functionLabel">
+     <property name="text">
+      <string>Function</string>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="0">
+    <widget class="QLabel" name="approachLabel">
+     <property name="text">
+      <string>Approach</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="2">
+    <widget class="QLineEdit" name="tofbTimeLineEdit">
+     <property name="minimumSize">
+      <size>
+       <width>160</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>120</width>
+       <height>16777215</height>
+      </size>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="0">
+    <widget class="QLabel" name="flightRulesLabel">
+     <property name="text">
+      <string>Flight Rules</string>
+     </property>
+    </widget>
+   </item>
+   <item row="6" column="2">
+    <widget class="QComboBox" name="functionComboBox"/>
+   </item>
+   <item row="7" column="2">
+    <widget class="QComboBox" name="approachComboBox"/>
+   </item>
+   <item row="8" column="2">
+    <widget class="QComboBox" name="flightRulesComboBox">
+     <item>
+      <property name="text">
+       <string>VFR</string>
+      </property>
+     </item>
+     <item>
+      <property name="text">
+       <string>IFR</string>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item row="8" column="4">
+    <widget class="QLabel" name="landingLabel">
+     <property name="text">
+      <string>Landing</string>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="5">
+    <widget class="QSpinBox" name="landingSpinBox"/>
+   </item>
+   <item row="1" column="3">
+    <widget class="QLabel" name="doftDisplayLabel">
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="3">
+    <widget class="QLabel" name="submissionReadyLabel">
+     <property name="minimumSize">
+      <size>
+       <width>200</width>
+       <height>0</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
   </layout>
  </widget>
  <tabstops>
-  <tabstop>doftLineEdit</tabstop>
   <tabstop>deptLocationLineEdit</tabstop>
   <tabstop>destLocationLineEdit</tabstop>
   <tabstop>tofbTimeLineEdit</tabstop>
   <tabstop>tonbTimeLineEdit</tabstop>
-  <tabstop>acftLineEdit</tabstop>
   <tabstop>picNameLineEdit</tabstop>
   <tabstop>sicNameLineEdit</tabstop>
   <tabstop>thirdPilotNameLineEdit</tabstop>
   <tabstop>flightNumberLineEdit</tabstop>
   <tabstop>remarksLineEdit</tabstop>
-  <tabstop>pilotFlyingCheckBox</tabstop>
-  <tabstop>ifrCheckBox</tabstop>
   <tabstop>takeOffSpinBox</tabstop>
-  <tabstop>toNightCheckBox</tabstop>
-  <tabstop>landingSpinBox</tabstop>
-  <tabstop>ldgNightCheckBox</tabstop>
-  <tabstop>functionComboBox</tabstop>
   <tabstop>approachComboBox</tabstop>
-  <tabstop>pushButton_2</tabstop>
-  <tabstop>toolButton</tabstop>
  </tabstops>
  <resources/>
  <connections>

+ 1 - 1
src/gui/dialogues/newpilotdialog.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 2 - 2
src/gui/dialogues/newpilotdialog.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -23,7 +23,7 @@
 #include <QRegularExpression>
 #include <QRegularExpressionValidator>
 #include <QCompleter>
-#include "src/database/row.h"
+#include "src/database/pilotentry.h"
 
 namespace Ui {
 class NewPilot;

+ 20 - 19
src/gui/dialogues/newsimdialog.cpp

@@ -3,7 +3,7 @@
 #include "src/gui/verification/timeinput.h"
 #include "ui_newsimdialog.h"
 #include "src/opl.h"
-#include "src/functions/time.h"
+#include "src/classes/time.h"
 #include "src/functions/datetime.h"
 #include "src/database/database.h"
 #include <QCompleter>
@@ -55,12 +55,12 @@ void NewSimDialog::init()
 void NewSimDialog::fillEntryData()
 {
     const auto& data = entry.getData();
-    ui->dateLineEdit->setText(data.value(OPL::Db::SIMULATORS_DATE).toString());
-    ui->totalTimeLineEdit->setText(OPL::Time::toString(data.value(OPL::Db::SIMULATORS_TIME).toInt()));
-    ui->deviceTypeComboBox->setCurrentIndex(data.value(OPL::Db::SIMULATORS_TYPE).toInt());
-    ui->aircraftTypeLineEdit->setText(data.value(OPL::Db::SIMULATORS_ACFT).toString());
-    ui->registrationLineEdit->setText(data.value(OPL::Db::SIMULATORS_REG).toString());
-    ui->remarksLineEdit->setText(data.value(OPL::Db::SIMULATORS_REMARKS).toString());
+    ui->dateLineEdit->setText(data.value(OPL::SimulatorEntry::DATE).toString());
+    ui->totalTimeLineEdit->setText(OPL::Time(data.value(OPL::SimulatorEntry::TIME).toInt()).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());
+    ui->remarksLineEdit->setText(data.value(OPL::SimulatorEntry::REMARKS).toString());
 }
 
 NewSimDialog::~NewSimDialog()
@@ -80,7 +80,7 @@ void NewSimDialog::on_dateLineEdit_editingFinished()
         return;
     } else {
         ui->dateLineEdit->setText(QString());
-        ui->dateLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+        ui->dateLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
     }
 }
 
@@ -94,7 +94,7 @@ void NewSimDialog::on_totalTimeLineEdit_editingFinished()
         QString fixed = input.fixup();
         if(fixed == QString()) {
             ui->totalTimeLineEdit->setText(QString());
-            ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+            ui->totalTimeLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
         } else {
             ui->totalTimeLineEdit->setText(fixed);
             ui->totalTimeLineEdit->setStyleSheet(QString());
@@ -127,7 +127,7 @@ bool NewSimDialog::verifyInput(QString& error_msg)
     const auto date = OPL::DateTime::parseInput(text, date_format);
 
     if (!date.isValid()) {
-        ui->dateLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+        ui->dateLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
         ui->dateLineEdit->setText(QString());
         error_msg = tr("Invalid Date");
         return false;
@@ -135,10 +135,11 @@ bool NewSimDialog::verifyInput(QString& error_msg)
     // Time
     if(!TimeInput(ui->totalTimeLineEdit->text()).isValid())
         return false;
-    const QTime time = OPL::Time::fromString(ui->totalTimeLineEdit->text());
 
-    if (!time.isValid()) {
-        ui->totalTimeLineEdit->setStyleSheet(OPL::Styles::RED_BORDER);
+    const OPL::Time time = OPL::Time::fromString(ui->totalTimeLineEdit->text());
+
+    if (!time.isValidTimeOfDay()) {
+        ui->totalTimeLineEdit->setStyleSheet(OPL::CssStyles::RED_BORDER);
         ui->totalTimeLineEdit->setText(QString());
         error_msg = tr("Invalid time");
         return false;
@@ -158,19 +159,19 @@ OPL::RowData_T NewSimDialog::collectInput()
 {
     OPL::RowData_T new_entry;
     // Date
-    new_entry.insert(OPL::Db::SIMULATORS_DATE, ui->dateLineEdit->text());
+    new_entry.insert(OPL::SimulatorEntry::DATE, ui->dateLineEdit->text());
     // Time
-    new_entry.insert(OPL::Db::SIMULATORS_TIME, OPL::Time::toMinutes(ui->totalTimeLineEdit->text()));
+    new_entry.insert(OPL::SimulatorEntry::TIME, OPL::Time::fromString(ui->totalTimeLineEdit->text()).toMinutes());
     // Device Type
-    new_entry.insert(OPL::Db::SIMULATORS_TYPE, ui->deviceTypeComboBox->currentText());
+    new_entry.insert(OPL::SimulatorEntry::TYPE, ui->deviceTypeComboBox->currentText());
     // Aircraft Type
-    new_entry.insert(OPL::Db::SIMULATORS_ACFT, ui->aircraftTypeLineEdit->text());
+    new_entry.insert(OPL::SimulatorEntry::ACFT, ui->aircraftTypeLineEdit->text());
     // Registration
     if (!ui->registrationLineEdit->text().isEmpty())
-        new_entry.insert(OPL::Db::SIMULATORS_REG, ui->registrationLineEdit->text());
+        new_entry.insert(OPL::SimulatorEntry::REG, ui->registrationLineEdit->text());
     // Remarks
     if (!ui->remarksLineEdit->text().isEmpty())
-        new_entry.insert(OPL::Db::FLIGHTS_REMARKS, ui->remarksLineEdit->text());
+        new_entry.insert(OPL::SimulatorEntry::REMARKS, ui->remarksLineEdit->text());
 
     return new_entry;
 }

+ 1 - 1
src/gui/dialogues/newsimdialog.h

@@ -2,7 +2,7 @@
 #define NEWSIMDIALOG_H
 
 #include <QDialog>
-#include "src/database/row.h"
+#include "src/database/simulatorentry.h"
 
 namespace Ui {
 class NewSimDialog;

+ 10 - 9
src/gui/dialogues/newtaildialog.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,6 +16,7 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "newtaildialog.h"
+#include "src/database/database.h"
 #include "src/database/databasecache.h"
 #include "ui_newtail.h"
 #include "src/opl.h"
@@ -121,10 +122,10 @@ void NewTailDialog::fillForm(OPL::Row entry, bool is_template)
         le->setText(data.value(key).toString());
     }
 
-    ui->operationComboBox->setCurrentIndex(data.value(OPL::Db::TAILS_MULTIPILOT).toInt() + 1);
-    ui->ppNumberComboBox ->setCurrentIndex(data.value(OPL::Db::TAILS_MULTIENGINE).toInt() + 1);
-    ui->ppTypeComboBox->setCurrentIndex(data.value(OPL::Db::TAILS_ENGINETYPE).toInt() + 1);
-    ui->weightComboBox->setCurrentIndex(data.value(OPL::Db::TAILS_WEIGHTCLASS).toInt() + 1);
+    ui->operationComboBox->setCurrentIndex(data.value(OPL::TailEntry::MULTI_PILOT).toInt() + 1);
+    ui->ppNumberComboBox ->setCurrentIndex(data.value(OPL::TailEntry::MULTI_ENGINE).toInt() + 1);
+    ui->ppTypeComboBox->setCurrentIndex(data.value(OPL::TailEntry::ENGINE_TYPE).toInt() + 1);
+    ui->weightComboBox->setCurrentIndex(data.value(OPL::TailEntry::WEIGHT_CLASS).toInt() + 1);
 }
 
 /*!
@@ -186,16 +187,16 @@ void NewTailDialog::submitForm()
     }
 
     if (ui->operationComboBox->currentIndex() != 0) { // bool Multipilot
-        new_data.insert(OPL::Db::TAILS_MULTIPILOT, ui->operationComboBox->currentIndex() - 1);
+        new_data.insert(OPL::TailEntry::MULTI_PILOT, ui->operationComboBox->currentIndex() - 1);
     }
     if (ui->ppNumberComboBox->currentIndex() != 0) { // bool MultiEngine
-        new_data.insert(OPL::Db::TAILS_MULTIENGINE, ui->ppNumberComboBox->currentIndex() - 1);
+        new_data.insert(OPL::TailEntry::MULTI_ENGINE, ui->ppNumberComboBox->currentIndex() - 1);
     }
     if (ui->ppTypeComboBox->currentIndex() != 0) { // int 0=unpowered,....4=jet
-        new_data.insert(OPL::Db::TAILS_ENGINETYPE, ui->ppTypeComboBox->currentIndex() - 1);
+        new_data.insert(OPL::TailEntry::ENGINE_TYPE, ui->ppTypeComboBox->currentIndex() - 1);
     }
     if (ui->weightComboBox->currentIndex() != 0) { // int 0=light...3=super
-        new_data.insert(OPL::Db::TAILS_WEIGHTCLASS, ui->weightComboBox->currentIndex() - 1);
+        new_data.insert(OPL::TailEntry::WEIGHT_CLASS, ui->weightComboBox->currentIndex() - 1);
     }
 
     //create db object

+ 2 - 4
src/gui/dialogues/newtaildialog.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -24,10 +24,8 @@
 #include <QRegularExpression>
 #include <QComboBox>
 
-#include "src/classes/settings.h"
-#include "src/functions/calc.h"
-#include "src/database/database.h"
 #include "src/database/row.h"
+#include "src/database/tailentry.h"
 
 namespace Ui {
 class NewTail;

+ 2 - 2
src/gui/verification/timeinput.cpp

@@ -18,13 +18,13 @@ QString TimeInput::fixup() const
 
     if (input.contains(':')) { // contains seperator
         if(input.length() == 4)
-            fixed.prepend('0');
+            fixed.prepend(QLatin1Char('0'));
     } else { // does not contain seperator
         if(input.length() == 4) {
             fixed.insert(2, ':');
         }
         if(input.length() == 3) {
-            fixed.prepend('0');
+            fixed.prepend(QLatin1Char('0'));
             fixed.insert(2, ':');
         }
     }

+ 1 - 1
src/gui/widgets/airportwidget.cpp

@@ -91,7 +91,7 @@ void AirportWidget::on_deletePushButton_clicked()
         QStringList selected_airport_names;
         for (const auto row_id : qAsConst(selectedEntries)) {
             const auto data = DB->getRowData(OPL::DbTable::Airports, row_id);
-            selected_airport_names.append(data.value(OPL::Db::AIRPORTS_NAME).toString());
+            selected_airport_names.append(data.value(OPL::AirportEntry::NAME).toString());
         }
 
         QString selected_airports_string;

+ 2 - 2
src/gui/widgets/backupwidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -88,7 +88,7 @@ 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),
-                owner.lastName()
+                                                  owner.getLastName()
                 );
 }
 

+ 1 - 2
src/gui/widgets/backupwidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -18,7 +18,6 @@
 #ifndef BACKUPWIDGET_H
 #define BACKUPWIDGET_H
 
-#include "src/classes/paths.h"
 
 #include <QWidget>
 #include <QStandardItemModel>

+ 11 - 5
src/gui/widgets/debugwidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,10 +16,8 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "debugwidget.h"
-#include "src/gui/verification/airportinput.h"
 #include "src/gui/verification/completerprovider.h"
 #include "src/gui/verification/pilotinput.h"
-#include "src/gui/verification/timeinput.h"
 #include "src/testing/importCrewlounge/processaircraft.h"
 #include "src/testing/importCrewlounge/processflights.h"
 #include "src/testing/importCrewlounge/processpilots.h"
@@ -28,9 +26,9 @@
 #include "src/classes/downloadhelper.h"
 #include "src/functions/readcsv.h"
 #include "src/database/database.h"
-#include "src/database/row.h"
 #include "src/testing/atimer.h"
-#include "src/functions/log.h"
+#include "src/classes/settings.h"
+
 void DebugWidget::on_debugPushButton_clicked()
 {
     auto rawCsvData = CSV::readCsvAsRows("/home/felix/git/importMCC/assets/data/felix.csv");
@@ -77,6 +75,7 @@ void DebugWidget::on_resetUserTablesPushButton_clicked()
         emit DB->dataBaseUpdated(OPL::DbTable::Any);
     } else
         LOG <<"Errors have occurred. Check console for Debug output. ";
+    Settings::resetToDefaults();
 }
 
 void DebugWidget::on_resetDatabasePushButton_clicked()
@@ -297,3 +296,10 @@ void DebugWidget::on_debug2LineEdit_editingFinished()
 
 }
 
+
+void DebugWidget::on_pushButton_clicked()
+{
+    Settings::resetToDefaults();
+    Settings::write(Settings::Main::SetupComplete, false);
+}
+

+ 3 - 1
src/gui/widgets/debugwidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -57,6 +57,8 @@ private slots:
 
     void on_debug2LineEdit_editingFinished();
 
+    void on_pushButton_clicked();
+
 private:
     Ui::DebugWidget *ui;
 

+ 66 - 59
src/gui/widgets/debugwidget.ui

@@ -24,38 +24,38 @@
        <string>Database</string>
       </attribute>
       <layout class="QGridLayout" name="gridLayout_2">
-       <item row="2" column="3">
-        <widget class="QLabel" name="label_3">
-         <property name="text">
-          <string>Fill a new database with sample entries</string>
-         </property>
-        </widget>
-       </item>
-       <item row="3" column="3">
-        <widget class="QLineEdit" name="importCsvLineEdit">
+       <item row="0" column="0">
+        <widget class="QPushButton" name="resetDatabasePushButton">
          <property name="minimumSize">
           <size>
-           <width>110</width>
+           <width>220</width>
            <height>0</height>
           </size>
          </property>
-         <property name="placeholderText">
-          <string>/path/to/file.csv</string>
+         <property name="text">
+          <string>Reset Database</string>
          </property>
         </widget>
        </item>
-       <item row="4" column="3">
-        <widget class="QLineEdit" name="debugLineEdit"/>
+       <item row="0" column="2">
+        <widget class="QLineEdit" name="branchLineEdit">
+         <property name="text">
+          <string>develop</string>
+         </property>
+         <property name="placeholderText">
+          <string>develop</string>
+         </property>
+        </widget>
        </item>
-       <item row="2" column="0">
-        <widget class="QPushButton" name="fillUserDataPushButton">
+       <item row="5" column="0">
+        <widget class="QPushButton" name="debugPushButton">
          <property name="text">
-          <string>Fill User Table with test data</string>
+          <string>Do Debug Stuff!</string>
          </property>
         </widget>
        </item>
-       <item row="3" column="0">
-        <widget class="QPushButton" name="importCsvPushButton">
+       <item row="4" column="4">
+        <widget class="QPushButton" name="selectCsvPushButton">
          <property name="minimumSize">
           <size>
            <width>110</width>
@@ -63,39 +63,40 @@
           </size>
          </property>
          <property name="text">
-          <string>Import CSV</string>
+          <string>Select File</string>
          </property>
         </widget>
        </item>
-       <item row="4" column="0">
-        <widget class="QPushButton" name="debugPushButton">
+       <item row="0" column="1">
+        <widget class="QLabel" name="branchLabel">
          <property name="text">
-          <string>Do Debug Stuff!</string>
+          <string>branch:</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="3">
-        <widget class="QLabel" name="label_2">
+       <item row="3" column="3">
+        <widget class="QLabel" name="label_3">
          <property name="text">
-          <string>Keep current database but delete entries in pilots, aircraft and flights</string>
+          <string>Fill a new database with sample entries</string>
          </property>
         </widget>
        </item>
-       <item row="1" column="0">
-        <widget class="QPushButton" name="resetUserTablesPushButton">
-         <property name="minimumSize">
-          <size>
-           <width>220</width>
-           <height>0</height>
-          </size>
+       <item row="3" column="0">
+        <widget class="QPushButton" name="fillUserDataPushButton">
+         <property name="text">
+          <string>Fill User Table with test data</string>
          </property>
+        </widget>
+       </item>
+       <item row="0" column="3">
+        <widget class="QLabel" name="label">
          <property name="text">
-          <string>Reset User Tables</string>
+          <string>Backup current database (if exists) and create a new one from scratch.</string>
          </property>
         </widget>
        </item>
-       <item row="3" column="4">
-        <widget class="QPushButton" name="selectCsvPushButton">
+       <item row="4" column="0">
+        <widget class="QPushButton" name="importCsvPushButton">
          <property name="minimumSize">
           <size>
            <width>110</width>
@@ -103,19 +104,12 @@
           </size>
          </property>
          <property name="text">
-          <string>Select File</string>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="3">
-        <widget class="QLabel" name="label">
-         <property name="text">
-          <string>Backup current database (if exists) and create a new one from scratch.</string>
+          <string>Import CSV</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="0">
-        <widget class="QPushButton" name="resetDatabasePushButton">
+       <item row="1" column="0">
+        <widget class="QPushButton" name="resetUserTablesPushButton">
          <property name="minimumSize">
           <size>
            <width>220</width>
@@ -123,11 +117,14 @@
           </size>
          </property>
          <property name="text">
-          <string>Reset Database</string>
+          <string>Reset User Tables and Settings</string>
          </property>
         </widget>
        </item>
-       <item row="3" column="1" colspan="2">
+       <item row="6" column="3">
+        <widget class="QLineEdit" name="debug2LineEdit"/>
+       </item>
+       <item row="4" column="1" colspan="2">
         <widget class="QComboBox" name="tableComboBox">
          <property name="minimumSize">
           <size>
@@ -142,23 +139,33 @@
          </item>
         </widget>
        </item>
-       <item row="5" column="3">
-        <widget class="QLineEdit" name="debug2LineEdit"/>
+       <item row="4" column="3">
+        <widget class="QLineEdit" name="importCsvLineEdit">
+         <property name="minimumSize">
+          <size>
+           <width>110</width>
+           <height>0</height>
+          </size>
+         </property>
+         <property name="placeholderText">
+          <string>/path/to/file.csv</string>
+         </property>
+        </widget>
        </item>
-       <item row="0" column="1">
-        <widget class="QLabel" name="branchLabel">
+       <item row="1" column="3">
+        <widget class="QLabel" name="label_2">
          <property name="text">
-          <string>branch:</string>
+          <string>Keep current database but delete entries in pilots, aircraft and flights</string>
          </property>
         </widget>
        </item>
-       <item row="0" column="2">
-        <widget class="QLineEdit" name="branchLineEdit">
+       <item row="5" column="3">
+        <widget class="QLineEdit" name="debugLineEdit"/>
+       </item>
+       <item row="2" column="0">
+        <widget class="QPushButton" name="pushButton">
          <property name="text">
-          <string>develop</string>
-         </property>
-         <property name="placeholderText">
-          <string>develop</string>
+          <string>Trigger Setup Dialog on Next Launch</string>
          </property>
         </widget>
        </item>

+ 26 - 15
src/gui/widgets/homewidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,9 +16,11 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "homewidget.h"
+#include "src/functions/statistics.h"
+#include "src/gui/widgets/totalswidget.h"
 #include "ui_homewidget.h"
 #include "src/database/database.h"
-#include "src/functions/time.h"
+#include "src/classes/time.h"
 #include "src/classes/settings.h"
 #include "src/database/row.h"
 
@@ -41,7 +43,7 @@ HomeWidget::HomeWidget(QWidget *parent) :
     currWarningThreshold = Settings::read(Settings::UserData::CurrWarningThreshold).toInt();
     auto logo = QPixmap(OPL::Assets::LOGO);
     ui->logoLabel->setPixmap(logo);
-    ui->welcomeLabel->setText(tr("Welcome to openPilotLog, %1!").arg(userName()));
+    ui->welcomeLabel->setText(tr("Welcome to openPilotLog, %1!").arg(getLogbookOwnerName()));
 
 
     limitationDisplayLabels = {
@@ -82,7 +84,7 @@ 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(userName()));
+        ui->welcomeLabel->setText(tr("Welcome to openPilotLog, %1!").arg(getLogbookOwnerName()));
 }
 
 void HomeWidget::changeEvent(QEvent *event)
@@ -98,11 +100,9 @@ void HomeWidget::changeEvent(QEvent *event)
  */
 void HomeWidget::fillTotals()
 {
-    const auto data = OPL::Statistics::totals();
-    for (const auto &field : data) {
-        auto line_edit = this->findChild<QLineEdit *>(field.first + QLatin1String("LineEdit"));
-        line_edit->setText(field.second);
-    }
+    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)
@@ -110,14 +110,14 @@ void HomeWidget::fillCurrency(OPL::CurrencyName currency_name, QLabel* display_l
     const auto currency_entry = DB->getCurrencyEntry(static_cast<int>(currency_name));
 
     if (currency_name == OPL::CurrencyName::Custom1) {
-        ui->currCustom1Label->setText(currency_entry.getData().value(OPL::Db::CURRENCIES_CURRENCYNAME).toString());
+        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::Db::CURRENCIES_CURRENCYNAME).toString());
+        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::Db::CURRENCIES_EXPIRYDATE).toString(),
+                                               OPL::CurrencyEntry::EXPIRYDATE).toString(),
                                                Qt::ISODate);
         display_label->setText(currency_date.toString(Qt::TextDate));
         setLabelColour(display_label, Colour::None);
@@ -201,7 +201,7 @@ void HomeWidget::fillCurrencyTakeOffLanding()
 void HomeWidget::fillLimitations()
 {
     int minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::Rolling28Days);
-    ui->FlightTime28dDisplayLabel->setText(OPL::Time::toString(minutes));
+    ui->FlightTime28dDisplayLabel->setText(OPL::Time(minutes).toString());
     if (minutes >= ROLLING_28_DAYS) {
         setLabelColour(ui->FlightTime28dDisplayLabel, Colour::Red);
     } else if (minutes >= ROLLING_28_DAYS * ftlWarningThreshold) {
@@ -209,7 +209,7 @@ void HomeWidget::fillLimitations()
     }
 
     minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::Rolling12Months);
-    ui->FlightTime12mDisplayLabel->setText(OPL::Time::toString(minutes));
+    ui->FlightTime12mDisplayLabel->setText(OPL::Time(minutes).toString());
     if (minutes >= ROLLING_12_MONTHS) {
         setLabelColour(ui->FlightTime12mDisplayLabel, Colour::Red);
     } else if (minutes >= ROLLING_12_MONTHS * ftlWarningThreshold) {
@@ -217,10 +217,21 @@ void HomeWidget::fillLimitations()
     }
 
     minutes = OPL::Statistics::totalTime(OPL::Statistics::TimeFrame::CalendarYear);
-    ui->FlightTimeCalYearDisplayLabel->setText(OPL::Time::toString(minutes));
+    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()
+{
+    OPL::PilotEntry owner = DB->getLogbookOwner();
+    QString name = owner.getFirstName();
+    if(name.isEmpty()) {
+        name = owner.getLastName();
+    }
+    DEB << "owner name: " << name;
+    return name;
+}

+ 2 - 4
src/gui/widgets/homewidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -23,9 +23,7 @@
 #include <QLabel>
 #include <QLineEdit>
 #include <QSettings>
-#include "src/functions/statistics.h"
 #include "src/database/database.h"
-#include "src/classes/settings.h"
 
 namespace Ui {
 class HomeWidget;
@@ -96,7 +94,7 @@ private:
     /*!
      * \brief Retreives the users first name from the database.
      */
-    const inline QString userName() { return DB->getPilotEntry(1).firstName(); }
+    const QString getLogbookOwnerName();
 
 public slots:
     void refresh();

+ 96 - 633
src/gui/widgets/homewidget.ui

@@ -14,84 +14,7 @@
    <string>Form</string>
   </property>
   <layout class="QGridLayout" name="gridLayout_4">
-   <item row="3" column="0">
-    <widget class="Line" name="line_7">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="2" column="0">
-    <widget class="Line" name="line_2">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="8" column="0">
-    <widget class="Line" name="line_4">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="4" column="0">
-    <widget class="QLabel" name="totalsLabel">
-     <property name="font">
-      <font>
-       <weight>75</weight>
-       <bold>true</bold>
-      </font>
-     </property>
-     <property name="text">
-      <string>Your Totals</string>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="1" column="0">
-    <widget class="QLabel" name="welcomeLabel">
-     <property name="text">
-      <string>Welcome to openPilotLog!</string>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="7" column="0">
-    <widget class="QLabel" name="currencyLabel">
-     <property name="font">
-      <font>
-       <weight>75</weight>
-       <bold>true</bold>
-      </font>
-     </property>
-     <property name="text">
-      <string>Currency</string>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="5" column="0">
-    <widget class="Line" name="line">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="11" column="0">
-    <widget class="Line" name="line_3">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-    </widget>
-   </item>
-   <item row="12" column="0">
+   <item row="13" column="0">
     <layout class="QGridLayout" name="gridLayout_2">
      <item row="0" column="0">
       <widget class="QLabel" name="FlightTime28dLabel">
@@ -156,22 +79,6 @@
     </layout>
    </item>
    <item row="10" column="0">
-    <widget class="QLabel" name="limitationsLabel">
-     <property name="font">
-      <font>
-       <weight>75</weight>
-       <bold>true</bold>
-      </font>
-     </property>
-     <property name="text">
-      <string>Limitations</string>
-     </property>
-     <property name="alignment">
-      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
-     </property>
-    </widget>
-   </item>
-   <item row="9" column="0">
     <layout class="QGridLayout" name="gridLayout_3">
      <item row="0" column="0">
       <widget class="QLabel" name="TakeOffLabel">
@@ -184,7 +91,6 @@
       <widget class="QLabel" name="TakeOffDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -210,7 +116,6 @@
       <widget class="QLabel" name="LandingsDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -241,7 +146,6 @@
       <widget class="QLabel" name="currToLdgDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -269,7 +173,6 @@
       <widget class="QLabel" name="currLicDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -297,7 +200,6 @@
       <widget class="QLabel" name="currTrDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -325,7 +227,6 @@
       <widget class="QLabel" name="currLckDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -353,7 +254,6 @@
       <widget class="QLabel" name="currMedDisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -381,7 +281,6 @@
       <widget class="QLabel" name="currCustom1DisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -409,7 +308,6 @@
       <widget class="QLabel" name="currCustom2DisplayLabel">
        <property name="font">
         <font>
-         <weight>75</weight>
          <bold>true</bold>
         </font>
        </property>
@@ -423,536 +321,56 @@
      </item>
     </layout>
    </item>
-   <item row="6" column="0">
-    <layout class="QGridLayout" name="gridLayout">
-     <item row="0" column="0">
-      <widget class="QLabel" name="totalLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>Total</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="1">
-      <widget class="QLineEdit" name="totalLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-       <property name="text">
-        <string/>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="2">
-      <widget class="QLabel" name="picusLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>PICus</string>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="3">
-      <widget class="QLineEdit" name="picusLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="0">
-      <widget class="QLabel" name="spseLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>SP SE</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="1">
-      <widget class="QLineEdit" name="spseLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="2">
-      <widget class="QLabel" name="ifrLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>IFR</string>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="3">
-      <widget class="QLineEdit" name="ifrLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="0">
-      <widget class="QLabel" name="spmeLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>SP ME</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QLineEdit" name="spmeLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="2">
-      <widget class="QLabel" name="nightLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>Night</string>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="3">
-      <widget class="QLineEdit" name="nightLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="0">
-      <widget class="QLabel" name="multipilotLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>Multi Pilot</string>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="1">
-      <widget class="QLineEdit" name="multipilotLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="2">
-      <widget class="QLabel" name="simLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>Simulator</string>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="3">
-      <widget class="QLineEdit" name="simLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="0">
-      <widget class="QLabel" name="piclabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>PIC</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="1">
-      <widget class="QLineEdit" name="picLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="2">
-      <widget class="QLabel" name="todayLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>TO Day</string>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="3">
-      <widget class="QLineEdit" name="todayLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-       <property name="text">
-        <string>0</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="0">
-      <widget class="QLabel" name="sicLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>SIC</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="1">
-      <widget class="QLineEdit" name="sicLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="2">
-      <widget class="QLabel" name="tonightLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>TO Night</string>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="3">
-      <widget class="QLineEdit" name="tonightLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-       <property name="text">
-        <string>0</string>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="0">
-      <widget class="QLabel" name="dualLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>DUAL</string>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="1">
-      <widget class="QLineEdit" name="dualLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="2">
-      <widget class="QLabel" name="ldgdayLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>LDG Day</string>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="3">
-      <widget class="QLineEdit" name="ldgdayLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-       <property name="text">
-        <string>0</string>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="0">
-      <widget class="QLabel" name="fiLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>FI</string>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="2">
-      <widget class="QLabel" name="ldgnightLabel">
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>LDG Night</string>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="3">
-      <widget class="QLineEdit" name="ldgnightLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-       <property name="text">
-        <string>0</string>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="1">
-      <widget class="QLineEdit" name="fiLineEdit">
-       <property name="minimumSize">
-        <size>
-         <width>100</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>120</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <property name="focusPolicy">
-        <enum>Qt::NoFocus</enum>
-       </property>
-      </widget>
-     </item>
-    </layout>
+   <item row="9" column="0">
+    <widget class="Line" name="line_4">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="8" column="0">
+    <widget class="QLabel" name="currencyLabel">
+     <property name="font">
+      <font>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Currency</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="12" column="0">
+    <widget class="Line" name="line_3">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="5" column="0">
+    <widget class="QLabel" name="totalsLabel">
+     <property name="font">
+      <font>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Your Totals</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="Line" name="line_7">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
    </item>
    <item row="0" column="0">
     <widget class="QLabel" name="logoLabel">
@@ -964,6 +382,51 @@
      </property>
     </widget>
    </item>
+   <item row="6" column="0">
+    <widget class="Line" name="line">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="Line" name="line_2">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QLabel" name="welcomeLabel">
+     <property name="text">
+      <string>Welcome to openPilotLog!</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="11" column="0">
+    <widget class="QLabel" name="limitationsLabel">
+     <property name="font">
+      <font>
+       <bold>true</bold>
+      </font>
+     </property>
+     <property name="text">
+      <string>Limitations</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignBottom|Qt::AlignHCenter</set>
+     </property>
+    </widget>
+   </item>
+   <item row="7" column="0">
+    <widget class="QStackedWidget" name="totalsStackedWidget">
+     <widget class="QWidget" name="page"/>
+     <widget class="QWidget" name="page_2"/>
+    </widget>
+   </item>
   </layout>
  </widget>
  <resources/>

+ 7 - 9
src/gui/widgets/logbookwidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -15,6 +15,7 @@
  *You should have received a copy of the GNU General Public License
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
+#include "src/classes/time.h"
 #include "src/database/database.h"
 #include "logbookwidget.h"
 #include "ui_logbookwidget.h"
@@ -23,9 +24,6 @@
 #include "src/classes/settings.h"
 #include "src/gui/dialogues/newflightdialog.h"
 #include "src/gui/dialogues/newsimdialog.h"
-#include "src/functions/time.h"
-
-
 
 LogbookWidget::LogbookWidget(QWidget *parent) :
     QWidget(parent),
@@ -96,13 +94,13 @@ const QString LogbookWidget::getFlightSummary(const OPL::FlightEntry &flight) co
     auto tableData = flight.getData();
     QString flight_summary;
     auto space = QLatin1Char(' ');
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DOFT).toString() + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEPT).toString() + space);
-    flight_summary.append(OPL::Time::toString(tableData.value(OPL::Db::FLIGHTS_TOFB).toInt())
+    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::toString(tableData.value(OPL::Db::FLIGHTS_TONB).toInt())
+    flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TONB).toInt()).toString()
                           + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEST).toString());
+    flight_summary.append(tableData.value(OPL::FlightEntry::DEST).toString());
 
     return flight_summary;
 }

+ 2 - 3
src/gui/widgets/logbookwidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -25,9 +25,8 @@
 #include <QDebug>
 #include <QMenu>
 #include <QTableView>
-#include "src/database/row.h"
+#include "src/database/flightentry.h"
 #include "src/gui/widgets/settingswidget.h"
-#include "src/opl.h"
 
 namespace Ui {
 class LogbookWidget;

+ 9 - 10
src/gui/widgets/pilotswidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -21,7 +21,7 @@
 #include "src/opl.h"
 #include "src/database/database.h"
 #include "src/database/row.h"
-#include "src/functions/time.h"
+#include "src/classes/time.h"
 #include "src/classes/settings.h"
 
 PilotsWidget::PilotsWidget(QWidget *parent) :
@@ -238,13 +238,12 @@ void PilotsWidget::repopulateModel()
     connectSignalsAndSlots();
 }
 
-const QString PilotsWidget::getPilotName(const OPL::PilotEntry &pilot)
+const QString PilotsWidget::getPilotName(const OPL::PilotEntry &pilot) const
 {
     if (!pilot.isValid())
         return QString();
 
-    return pilot.getData().value(OPL::Db::PILOTS_LASTNAME).toString() + QLatin1String(", ")
-            + pilot.getData().value(OPL::Db::PILOTS_FIRSTNAME).toString();
+    return pilot.getLastName() + QLatin1String(", ") + pilot.getFirstName();
 }
 
 const QString PilotsWidget::getFlightSummary(const OPL::FlightEntry &flight) const
@@ -256,13 +255,13 @@ const QString PilotsWidget::getFlightSummary(const OPL::FlightEntry &flight) con
     auto tableData = flight.getData();
     QString flight_summary;
     auto space = QLatin1Char(' ');
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DOFT).toString() + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEPT).toString() + space);
-    flight_summary.append(OPL::Time::toString(tableData.value(OPL::Db::FLIGHTS_TOFB).toInt())
+    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::toString(tableData.value(OPL::Db::FLIGHTS_TONB).toInt())
+    flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TONB).toInt()).toString()
                           + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEST).toString());
+    flight_summary.append(tableData.value(OPL::FlightEntry::DEST).toString());
 
     return flight_summary;
 

+ 4 - 3
src/gui/widgets/pilotswidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -22,7 +22,8 @@
 #include <QItemSelection>
 #include <QSqlTableModel>
 #include <QTableView>
-#include "src/database/row.h"
+#include "src/database/flightentry.h"
+#include "src/database/pilotentry.h"
 #include "src/gui/widgets/settingswidget.h"
 
 namespace Ui {
@@ -93,7 +94,7 @@ private:
 
     QVector<qint32> selectedPilots;
 
-    const QString getPilotName(const OPL::PilotEntry &pilot);
+    const QString getPilotName(const OPL::PilotEntry &pilot) const;
 
     const QString getFlightSummary(const OPL::FlightEntry &flight) const;
 

+ 48 - 55
src/gui/widgets/settingswidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -17,11 +17,11 @@
  */
 #include "settingswidget.h"
 #include "src/gui/dialogues/exporttocsvdialog.h"
+#include "src/gui/widgets/totalswidget.h"
 #include "ui_settingswidget.h"
 #include "src/classes/style.h"
 #include "src/classes/settings.h"
 #include "src/database/database.h"
-#include "src/database/row.h"
 #include "src/opl.h"
 #include "src/functions/datetime.h"
 #include "src/gui/widgets/backupwidget.h"
@@ -34,6 +34,7 @@ SettingsWidget::SettingsWidget(QWidget *parent) :
     ui->tabWidget->setCurrentIndex(0);
 
     loadBackupWidget();
+    loadPreviousExperienceWidget();
     setupComboBoxes();
     setupDateEdits();
     setupValidators();
@@ -89,7 +90,7 @@ void SettingsWidget::setupDateEdits()
         const auto entry = DB->getCurrencyEntry(static_cast<int>(pair.first));
         if (entry.isValid()) { // set date
             const auto date = QDate::fromString(
-                        entry.getData().value(OPL::Db::CURRENCIES_EXPIRYDATE).toString(),
+                entry.getData().value(OPL::CurrencyEntry::EXPIRYDATE).toString(),
                         Qt::ISODate);
             if(date.isValid())
                 pair.second->setDate(date);
@@ -106,6 +107,13 @@ void SettingsWidget::loadBackupWidget()
     ui->backupStackedWidget->setCurrentWidget(bw);
 }
 
+void SettingsWidget::loadPreviousExperienceWidget()
+{
+    auto pxp = new TotalsWidget(TotalsWidget::WidgetType::PreviousExperienceWidget);
+    ui->previousExpStackedWidget->addWidget(pxp);
+    ui->previousExpStackedWidget->setCurrentWidget(pxp);
+}
+
 /*!
  * \brief SettingsWidget::readSettings Reads settings from Settings and sets up the UI accordingly
  */
@@ -114,13 +122,17 @@ void SettingsWidget::readSettings()
     //const QSignalBlocker blocker(this); // don't emit editing finished for setting these values
 
     // Personal Data Tab
-    auto user_data = DB->getPilotEntry(1).getData();
-    ui->lastnameLineEdit->setText(user_data.value(OPL::Db::PILOTS_LASTNAME).toString());
-    ui->firstnameLineEdit->setText(user_data.value(OPL::Db::PILOTS_FIRSTNAME).toString());
-    ui->companyLineEdit->setText(user_data.value(OPL::Db::PILOTS_COMPANY).toString());
-    ui->employeeidLineEdit->setText(user_data.value(OPL::Db::PILOTS_EMPLOYEEID).toString());
-    ui->phoneLineEdit->setText(user_data.value(OPL::Db::PILOTS_PHONE).toString());
-    ui->emailLineEdit->setText(user_data.value(OPL::Db::PILOTS_EMAIL).toString());
+    const auto user_data = DB->getLogbookOwner().getData();
+    QString lastName = user_data.value(OPL::PilotEntry::LASTNAME).toString();
+    if(lastName.isEmpty()) {
+        lastName = "Please enter your last name.";
+    }
+    ui->lastnameLineEdit->setText(lastName);
+    ui->firstnameLineEdit->setText(user_data.value(OPL::PilotEntry::FIRSTNAME).toString());
+    ui->companyLineEdit->setText(user_data.value(OPL::PilotEntry::COMPANY).toString());
+    ui->employeeidLineEdit->setText(user_data.value(OPL::PilotEntry::EMPLOYEEID).toString());
+    ui->phoneLineEdit->setText(user_data.value(OPL::PilotEntry::PHONE).toString());
+    ui->emailLineEdit->setText(user_data.value(OPL::PilotEntry::EMAIL).toString());
 
     // FLight Logging Tab
     ui->functionComboBox->setCurrentIndex(Settings::read(Settings::FlightLogging::Function).toInt());
@@ -166,22 +178,8 @@ void SettingsWidget::readSettings()
 
 void SettingsWidget::setupValidators()
 {
-    const QHash<QLineEdit*, QRegularExpression> validator_map = {
-        {ui->firstnameLineEdit, QRegularExpression(QLatin1String("\\w+"))},
-        {ui->lastnameLineEdit, QRegularExpression(QLatin1String("\\w+"))},
-        {ui->phoneLineEdit, QRegularExpression(QLatin1String("^[+]{0,1}[0-9\\-\\s]+"))},
-        {ui->emailLineEdit, QRegularExpression(QString("\\A[a-z0-9!#$%&'*+/=?^_‘{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_‘{|}~-]+)*@"
-         "(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\z"))},
-        {ui->companyLineEdit, QRegularExpression(QLatin1String("\\w+"))},
-        {ui->employeeidLineEdit, QRegularExpression(QLatin1String("\\w+"))},
-        {ui->prefixLineEdit, QRegularExpression(QLatin1String("\\w+"))},
-    };
-
-    QHash<QLineEdit*, QRegularExpression>::const_iterator i;
-    for (i = validator_map.constBegin(); i != validator_map.constEnd(); ++i) {
-        auto validator = new QRegularExpressionValidator(i.value(),i.key());
-        i.key()->setValidator(validator);
-    }
+    ui->phoneLineEdit->setValidator(new QRegularExpressionValidator(OPL::RegEx::RX_PHONE_NUMBER, ui->phoneLineEdit));
+    ui->emailLineEdit->setValidator(new QRegularExpressionValidator(OPL::RegEx::RX_EMAIL_ADDRESS, ui->emailLineEdit));
 }
 
 /*!
@@ -192,41 +190,36 @@ void SettingsWidget::updatePersonalDetails()
     OPL::RowData_T user_data;
     switch (ui->aliasComboBox->currentIndex()) {
     case 0:
-        user_data.insert(OPL::Db::PILOTS_ALIAS, QStringLiteral("self"));
+        user_data.insert(OPL::PilotEntry::ALIAS, QStringLiteral("self"));
         break;
     case 1:
-        user_data.insert(OPL::Db::PILOTS_ALIAS, QStringLiteral("SELF"));
+        user_data.insert(OPL::PilotEntry::ALIAS, QStringLiteral("SELF"));
         break;
     case 2:{
         QString name;
         name.append(ui->lastnameLineEdit->text());
-        name.append(QLatin1String(", "));
-        name.append(ui->firstnameLineEdit->text().at(0));
-        name.append(QLatin1Char('.'));
-        user_data.insert(OPL::Db::PILOTS_ALIAS, name);
+        if(ui->firstnameLineEdit->text().size() > 0) {
+            name.append(QLatin1String(", "));
+            name.append(ui->firstnameLineEdit->text().at(0));
+            name.append(QLatin1Char('.'));
+        }
+        user_data.insert(OPL::PilotEntry::ALIAS, name);
     }
         break;
     default:
         break;
     }
-    user_data.insert(OPL::Db::PILOTS_LASTNAME, ui->lastnameLineEdit->text());
-    user_data.insert(OPL::Db::PILOTS_FIRSTNAME, ui->firstnameLineEdit->text());
-    user_data.insert(OPL::Db::PILOTS_COMPANY, ui->companyLineEdit->text());
-    user_data.insert(OPL::Db::PILOTS_EMPLOYEEID, ui->employeeidLineEdit->text());
-    user_data.insert(OPL::Db::PILOTS_PHONE, ui->phoneLineEdit->text());
-    user_data.insert(OPL::Db::PILOTS_EMAIL, ui->emailLineEdit->text());
-
-    auto user = OPL::PilotEntry(1, user_data);
-
-    TODO << "Changing DB does not currently refresh logbook view";
-    TODO << "Check for empty line edits (First, last name should not be empty...validators not a good way because it gives no user feedback)";
-
-    if(!DB->commit(user))
+    user_data.insert(OPL::PilotEntry::LASTNAME, ui->lastnameLineEdit->text());
+    user_data.insert(OPL::PilotEntry::FIRSTNAME, ui->firstnameLineEdit->text());
+    user_data.insert(OPL::PilotEntry::COMPANY, ui->companyLineEdit->text());
+    user_data.insert(OPL::PilotEntry::EMPLOYEEID, ui->employeeidLineEdit->text());
+    user_data.insert(OPL::PilotEntry::PHONE, ui->phoneLineEdit->text());
+    user_data.insert(OPL::PilotEntry::EMAIL, ui->emailLineEdit->text());
+
+    if(!DB->setLogbookOwner(user_data))
         WARN(tr("Unable to update Database:<br>") + DB->lastError.text());
     else
         LOG << "User updated successfully.";
-
-
 }
 
 /*
@@ -505,7 +498,7 @@ void SettingsWidget::on_resetStylePushButton_clicked()
 
 void SettingsWidget::on_currLicDateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)}};
+    const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
     const OPL::CurrencyEntry entry(static_cast<int>(OPL::CurrencyName::Licence), row_data);
     if (!DB->commit(entry))
         WARN(tr("Unable to update currency. The following error has ocurred:<br>%1").arg(DB->lastError.text()));
@@ -515,7 +508,7 @@ void SettingsWidget::on_currLicDateEdit_userDateChanged(const QDate &date)
 
 void SettingsWidget::on_currTrDateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)}};
+    const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
     const OPL::CurrencyEntry entry(static_cast<int>(OPL::CurrencyName::TypeRating), row_data);
     if (!DB->commit(entry))
         WARN(tr("Unable to update currency. The following error has ocurred:<br>%1").arg(DB->lastError.text()));
@@ -525,7 +518,7 @@ void SettingsWidget::on_currTrDateEdit_userDateChanged(const QDate &date)
 
 void SettingsWidget::on_currLckDateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)}};
+    const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
     const OPL::CurrencyEntry entry(static_cast<int>(OPL::CurrencyName::LineCheck), row_data);
     if (!DB->commit(entry))
         WARN(tr("Unable to update currency. The following error has ocurred:<br>%1").arg(DB->lastError.text()));
@@ -535,7 +528,7 @@ void SettingsWidget::on_currLckDateEdit_userDateChanged(const QDate &date)
 
 void SettingsWidget::on_currMedDateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)}};
+    const OPL::RowData_T row_data = {{OPL::CurrencyEntry::EXPIRYDATE, date.toString(Qt::ISODate)}};
     const OPL::CurrencyEntry entry(static_cast<int>(OPL::CurrencyName::Medical), row_data);
     if (!DB->commit(entry))
         WARN(tr("Unable to update currency. The following error has ocurred:<br>%1").arg(DB->lastError.text()));
@@ -545,8 +538,8 @@ void SettingsWidget::on_currMedDateEdit_userDateChanged(const QDate &date)
 
 void SettingsWidget::on_currCustom1DateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)},
-                                {OPL::Db::CURRENCIES_CURRENCYNAME, ui->currCustom1LineEdit->text()}};
+    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<int>(OPL::CurrencyName::Custom1), row_data);
     DEB << entry;
     if (!DB->commit(entry))
@@ -557,8 +550,8 @@ void SettingsWidget::on_currCustom1DateEdit_userDateChanged(const QDate &date)
 
 void SettingsWidget::on_currCustom2DateEdit_userDateChanged(const QDate &date)
 {
-    const OPL::RowData_T row_data = {{OPL::Db::CURRENCIES_EXPIRYDATE, date.toString(Qt::ISODate)},
-                                {OPL::Db::CURRENCIES_CURRENCYNAME, ui->currCustom2LineEdit->text()}};
+    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<int>(OPL::CurrencyName::Custom2), row_data);
     if (!DB->commit(entry))
         WARN(tr("Unable to update currency. The following error has ocurred:<br><br>%1").arg(DB->lastError.text()));

+ 5 - 1
src/gui/widgets/settingswidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -105,10 +105,14 @@ private:
 
     void loadBackupWidget();
 
+    void loadPreviousExperienceWidget();
+
     void updatePersonalDetails();
 
     bool usingStylesheet();
 
+    const static int SELF_ROW_ID = 1;
+
 signals:
 
     /*!

+ 15 - 2
src/gui/widgets/settingswidget.ui

@@ -17,7 +17,7 @@
    <item row="0" column="0">
     <widget class="QTabWidget" name="tabWidget">
      <property name="currentIndex">
-      <number>5</number>
+      <number>2</number>
      </property>
      <widget class="QWidget" name="personalTab">
       <attribute name="title">
@@ -307,6 +307,19 @@
        </item>
       </layout>
      </widget>
+     <widget class="QWidget" name="previousExpTab">
+      <property name="toolTip">
+       <string>Enter your total experience from previous logbooks</string>
+      </property>
+      <attribute name="title">
+       <string>Previous Experience</string>
+      </attribute>
+      <layout class="QGridLayout" name="gridLayout_9">
+       <item row="0" column="0">
+        <widget class="QStackedWidget" name="previousExpStackedWidget"/>
+       </item>
+      </layout>
+     </widget>
      <widget class="QWidget" name="currenciesTab">
       <attribute name="title">
        <string>Currencies</string>
@@ -979,7 +992,7 @@
        </item>
       </layout>
      </widget>
-     <widget class="QWidget" name="tab">
+     <widget class="QWidget" name="helpTab">
       <attribute name="title">
        <string>Help</string>
       </attribute>

+ 14 - 14
src/gui/widgets/tailswidget.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -16,11 +16,11 @@
  *along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 #include "tailswidget.h"
+#include "src/classes/time.h"
 #include "ui_aircraftwidget.h"
 #include "src/opl.h"
 #include "src/classes/settings.h"
 #include "src/database/database.h"
-#include "src/database/row.h"
 #include "src/gui/dialogues/newtaildialog.h"
 
 
@@ -182,7 +182,7 @@ void TailsWidget::on_deleteAircraftButton_clicked()
         message_box.setWindowTitle(tr("Delete Aircraft"));
         message_box.setText(tr("You are deleting the following aircraft:<br><br><b><tt>"
                                "%1 - (%2)</b></tt><br><br>Are you sure?"
-                               ).arg(entry.getData().value(OPL::Db::TAILS_REGISTRATION).toString(),
+                               ).arg(entry.getData().value(OPL::TailEntry::REGISTRATION).toString(),
                                      getAircraftTypeString(entry)));
 
         if (message_box.exec() == QMessageBox::Yes) {
@@ -264,12 +264,12 @@ void TailsWidget::repopulateModel()
 const QString TailsWidget::getAircraftTypeString(const OPL::Row &row) const
 {
     QString type_string;
-    if (!row.getData().value(OPL::Db::TAILS_MAKE).toString().isEmpty())
-        type_string.append(row.getData().value(OPL::Db::TAILS_MAKE).toString() + QLatin1Char(' '));
-    if (!row.getData().value(OPL::Db::TAILS_MODEL).toString().isEmpty())
-        type_string.append(row.getData().value(OPL::Db::TAILS_MODEL).toString());
-    if (!row.getData().value(OPL::Db::TAILS_VARIANT).toString().isEmpty())
-        type_string.append(QLatin1Char('-') + row.getData().value(OPL::Db::TAILS_VARIANT).toString());
+    if (!row.getData().value(OPL::TailEntry::MAKE).toString().isEmpty())
+        type_string.append(row.getData().value(OPL::TailEntry::MAKE).toString() + QLatin1Char(' '));
+    if (!row.getData().value(OPL::TailEntry::MODEL).toString().isEmpty())
+        type_string.append(row.getData().value(OPL::TailEntry::MODEL).toString());
+    if (!row.getData().value(OPL::TailEntry::VARIANT).toString().isEmpty())
+        type_string.append(QLatin1Char('-') + row.getData().value(OPL::TailEntry::VARIANT).toString());
 
     return type_string;
 }
@@ -282,13 +282,13 @@ const QString TailsWidget::getFlightSummary(const OPL::FlightEntry &flight) cons
     auto tableData = flight.getData();
     QString flight_summary;
     auto space = QLatin1Char(' ');
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DOFT).toString() + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEPT).toString() + space);
-    flight_summary.append(OPL::Time::toString(tableData.value(OPL::Db::FLIGHTS_TOFB).toInt())
+    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::toString(tableData.value(OPL::Db::FLIGHTS_TONB).toInt())
+    flight_summary.append(OPL::Time(tableData.value(OPL::FlightEntry::TONB).toInt()).toString()
                           + space);
-    flight_summary.append(tableData.value(OPL::Db::FLIGHTS_DEST).toString());
+    flight_summary.append(tableData.value(OPL::FlightEntry::DEST).toString());
 
     return flight_summary;
 }

+ 2 - 2
src/gui/widgets/tailswidget.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -22,7 +22,7 @@
 #include <QItemSelection>
 #include <QSqlTableModel>
 #include <QTableView>
-#include "src/database/row.h"
+#include "src/database/flightentry.h"
 #include "src/gui/widgets/settingswidget.h"
 
 namespace Ui {

+ 208 - 0
src/gui/widgets/totalswidget.cpp

@@ -0,0 +1,208 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#include "totalswidget.h"
+#include "QtWidgets/qlineedit.h"
+#include "src/database/database.h"
+#include "src/database/previousexperienceentry.h"
+#include "src/opl.h"
+#include "src/classes/time.h"
+#include "ui_totalswidget.h"
+
+TotalsWidget::TotalsWidget(WidgetType widgetType, QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::TotalsWidget)
+{
+    ui->setupUi(this);
+    setup(widgetType);
+}
+
+TotalsWidget::~TotalsWidget()
+{
+    delete ui;
+}
+
+/*!
+ * \brief TotalsWidget::setup Sets the line edits as editable or read-only and connects signals if required
+ * \details This widget can be used to either display the totals (in the home widget) or
+ * to edit the total previous experience, from previous logbooks (in the settings widget).
+ */
+void TotalsWidget::setup(const WidgetType widgetType)
+{
+    const QList<QLineEdit *> lineEdits = this->findChildren<QLineEdit *>();
+
+    switch (widgetType) {
+    case TotalTimeWidget:
+        LOG << "Setting up totals widget";
+        // disable editing
+        for (const auto &lineEdit : lineEdits) {
+            lineEdit->setFocusPolicy(Qt::FocusPolicy::NoFocus);
+        }
+        // populate the UI
+        fillTotals(widgetType);
+        break;
+    case PreviousExperienceWidget:
+        LOG << "Setting up previous XP widget";
+        for (const auto &lineEdit : lineEdits) {
+            lineEdit->setFocusPolicy(Qt::FocusPolicy::StrongFocus);
+            // set a validator for the TO/LDG line edits, the other ones get validated seperately
+            if(lineEdit->objectName().contains(QLatin1String("to")) || lineEdit->objectName().contains(QLatin1String("ldg"))) {
+                lineEdit->setValidator(new QIntValidator(0, std::numeric_limits<int>::max(), this));
+            }
+        }
+        // initialise m_rowData
+        m_rowData = DB->getRowData(OPL::DbTable::PreviousExperience, ROW_ID);
+
+        // populate the UI
+        fillTotals(widgetType);
+        connectSignalsAndSlots();
+        break;
+    default:
+        break;
+    }
+}
+
+/*!
+ * \brief HomeWidget::fillTotals Retreives a Database Summary of Total Flight Time and fills the UI.
+ */
+void TotalsWidget::fillTotals(const WidgetType widgetType)
+{
+    OPL::RowData_T time_data;
+
+    // retreive times from database
+    switch (widgetType) {
+    case TotalTimeWidget:
+        time_data = DB->getTotals(true);
+        break;
+    case PreviousExperienceWidget:
+        time_data = DB->getRowData(OPL::DbTable::PreviousExperience, ROW_ID);
+    }
+
+    // fill the line edits with the data obtained
+    const OPL::RowData_T &const_time_data = qAsConst(time_data);
+    for (const auto &field : const_time_data) {
+        // match the db entries to the line edits using their object name
+        const QString search_term = time_data.key(field) + QLatin1String("LineEdit");
+        QLineEdit* line_edit = this->findChild<QLineEdit *>(search_term);
+        // fill the line edit with the corresponding data
+        if(line_edit != nullptr) {
+            const QString &le_name = line_edit->objectName();
+            if(le_name.contains("to") || le_name.contains("ldg")) {
+                // line edits for take offs and landings
+                line_edit->setText(field.toString());
+            } else {
+                // line edits for total time
+                OPL::Time time = OPL::Time(field.toInt());// = Time(field.toInt());
+                line_edit->setText(time.toString());
+            }
+        }
+
+    }
+}
+
+/*!
+ * \brief TotalsWidget::connectSignalsAndSlots If the widget is editable, connects the signals and slots
+ */
+void TotalsWidget::connectSignalsAndSlots()
+{
+    connect(ui->tblkLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tSPSELineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tSPMELineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tMPLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+
+    connect(ui->tPICLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tSICLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tDUALLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tFILineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tPICUSLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tIFRLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tNIGHTLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+    connect(ui->tSIMLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::timeLineEditEditingFinished);
+
+    connect(ui->toDayLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::movementLineEditEditingFinished);
+    connect(ui->toNightLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::movementLineEditEditingFinished);
+    connect(ui->ldgDayLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::movementLineEditEditingFinished);
+    connect(ui->ldgNightLineEdit, &QLineEdit::editingFinished,
+            this, &TotalsWidget::movementLineEditEditingFinished);
+}
+
+
+void TotalsWidget::timeLineEditEditingFinished()
+{
+    LOG << sender()->objectName() + "Editing finished.";
+    QLineEdit* line_edit = this->findChild<QLineEdit*>(sender()->objectName());
+    const QString& text = line_edit->text();
+
+    // make sure the input is usable
+    if(!text.contains(QChar(':'))) {
+        WARN(tr("Please enter the time as: <br><br> hh:mm"));
+        line_edit->setText(QString());
+        return;
+    }
+
+    // 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();
+
+    m_rowData.insert(db_field, value);
+    LOG << "Added row data: " + db_field + ": " + value.toString();
+
+    const auto previous_experience = OPL::PreviousExperienceEntry(ROW_ID, m_rowData);
+    DB->commit(previous_experience);
+
+    // 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());
+    line_edit->setText(new_time.toString());
+}
+
+void TotalsWidget::movementLineEditEditingFinished()
+{
+    // input validation is done by the QValidator
+    QLineEdit* line_edit = this->findChild<QLineEdit*>(sender()->objectName());
+    LOG << line_edit->objectName() + "Editing finished.";
+
+    // extract the value from the input and update the DB
+    const QString db_field = line_edit->objectName().remove(QLatin1String("LineEdit"));
+    const QVariant value = line_edit->text().toInt();
+
+    m_rowData.insert(db_field, value);
+
+    const auto previous_experience = OPL::PreviousExperienceEntry(ROW_ID, m_rowData);
+    DB->commit(previous_experience);
+
+    // read back the value and set the line edit to the retreived value to give user feedback
+    m_rowData = DB->getRowData(OPL::DbTable::PreviousExperience, ROW_ID);
+    const QString new_value = QString::number(m_rowData.value(db_field).toInt());
+    line_edit->setText(new_value);
+}
+

+ 64 - 0
src/gui/widgets/totalswidget.h

@@ -0,0 +1,64 @@
+/*
+ *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 <https://www.gnu.org/licenses/>.
+ */
+#ifndef TOTALSWIDGET_H
+#define TOTALSWIDGET_H
+
+#include "QtWidgets/qlineedit.h"
+#include "src/gui/verification/timeinput.h"
+#include "src/opl.h"
+#include <QWidget>
+#include <QRegularExpressionValidator>
+
+namespace Ui {
+class TotalsWidget;
+}
+
+class TotalsWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    enum WidgetType {TotalTimeWidget, PreviousExperienceWidget};
+    explicit TotalsWidget(WidgetType widgetType, QWidget *parent = nullptr);
+    ~TotalsWidget();
+
+
+
+private:
+    Ui::TotalsWidget *ui;
+    /*!
+     * \brief m_rowData holds the data displayed in the line edits
+     */
+    OPL::RowData_T m_rowData;
+    /*!
+     * \brief ROW_ID the row ID for previous experience entries (1)
+     */
+    const static int ROW_ID = 1;
+    void fillTotals(const WidgetType widgetType);
+    void setup(const WidgetType widgetType);
+    void connectSignalsAndSlots();
+    bool verifyUserTimeInput(QLineEdit *line_edit, const TimeInput &input);
+    bool updateTimeEntry(const QLineEdit* line_edit);
+    bool updateMovementEntry(const QLineEdit* line_edit);
+
+private slots:
+    void timeLineEditEditingFinished();
+    void movementLineEditEditingFinished();
+};
+
+#endif // TOTALSWIDGET_H

+ 570 - 0
src/gui/widgets/totalswidget.ui

@@ -0,0 +1,570 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TotalsWidget</class>
+ <widget class="QWidget" name="TotalsWidget">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <layout class="QGridLayout" name="gridLayout_3">
+     <item row="2" column="2">
+      <widget class="QLabel" name="nightLabel_2">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Night</string>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="2">
+      <widget class="QLabel" name="ldgnightLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>LDG Night</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="3">
+      <widget class="QLineEdit" name="toNightLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="spmeLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>SP ME</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="3">
+      <widget class="QLineEdit" name="ldgDayLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QLineEdit" name="tMPLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="1">
+      <widget class="QLineEdit" name="tFILineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="0">
+      <widget class="QLabel" name="dualLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>DUAL</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="2">
+      <widget class="QLabel" name="tonightLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>TO Night</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="tSPSELineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="1">
+      <widget class="QLineEdit" name="tSICLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="1">
+      <widget class="QLineEdit" name="tDUALLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="3">
+      <widget class="QLineEdit" name="ldgNightLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="0">
+      <widget class="QLabel" name="piclabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>PIC</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="picusLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>PICus</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QLabel" name="ifrLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>IFR</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="QLineEdit" name="tPICUSLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="multipilotLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Multi Pilot</string>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="3">
+      <widget class="QLineEdit" name="tNIGHTLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="3">
+      <widget class="QLineEdit" name="toDayLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+       <property name="text">
+        <string>0</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="2">
+      <widget class="QLabel" name="ldgdayLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>LDG Day</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="2">
+      <widget class="QLabel" name="simLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Simulator</string>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="3">
+      <widget class="QLineEdit" name="tSIMLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QLabel" name="totalLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Total</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="spseLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>SP SE</string>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="0">
+      <widget class="QLabel" name="sicLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>SIC</string>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="0">
+      <widget class="QLabel" name="fiLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>FI</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="tblkLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+       <property name="text">
+        <string/>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="QLineEdit" name="tIFRLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLineEdit" name="tSPMELineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QLineEdit" name="tPICLineEdit">
+       <property name="minimumSize">
+        <size>
+         <width>100</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="focusPolicy">
+        <enum>Qt::TabFocus</enum>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="2">
+      <widget class="QLabel" name="todayLabel">
+       <property name="maximumSize">
+        <size>
+         <width>120</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>TO Day</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>tblkLineEdit</tabstop>
+  <tabstop>tSPSELineEdit</tabstop>
+  <tabstop>tSPMELineEdit</tabstop>
+  <tabstop>tMPLineEdit</tabstop>
+  <tabstop>tPICLineEdit</tabstop>
+  <tabstop>tSICLineEdit</tabstop>
+  <tabstop>tDUALLineEdit</tabstop>
+  <tabstop>tFILineEdit</tabstop>
+  <tabstop>tPICUSLineEdit</tabstop>
+  <tabstop>tIFRLineEdit</tabstop>
+  <tabstop>tNIGHTLineEdit</tabstop>
+  <tabstop>tSIMLineEdit</tabstop>
+  <tabstop>toDayLineEdit</tabstop>
+  <tabstop>toNightLineEdit</tabstop>
+  <tabstop>ldgDayLineEdit</tabstop>
+  <tabstop>ldgNightLineEdit</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>

+ 37 - 115
src/opl.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -67,6 +67,20 @@ namespace OPL {
 #define WARN(msg) OPL::ANotificationHandler::warn(msg, this)  // Use for warnings (will be displayed in GUI)
 #define CRIT(msg) OPL::ANotificationHandler::crit(msg, this)  // Use for critical warnings (will be displayed in GUI)
 
+/**
+ * @brief Defines the row ID for non-user entries in the database;
+ */
+const 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";
+/**
+ * @brief Defines a registration for a non-existent (dummy) aircraft: "XX-XXX"
+ */
+const static char* STUB_AIRCRAFT_REG = "XX-XXX";
+
 /*!
  * \brief The ANotificationHandler class handles displaying of user-directed messages. It displays
  * information to the user in a QMessageBox and forwards the displayed message to ALog so it is written
@@ -94,6 +108,16 @@ public:
 
 using RowData_T = QHash<QString, QVariant>;
 
+struct ToLdgCount_T {
+    int toDay;
+    int toNight;
+    int ldgDay;
+    int ldgNight;
+
+    ToLdgCount_T(int toDay, int toNight, int ldgDay, int ldgNight)
+        : toDay(toDay), toNight(toNight), ldgDay(ldgDay), ldgNight(ldgNight) {}
+};
+
 /*!
  * \brief ADateFormats enumerates the accepted date formats for QDateEdits
  * \todo At the moment, only ISODate is accepet as a valid date format.
@@ -128,7 +152,7 @@ enum class SimulatorType {FNPTI = 0, FNPTII = 1, FSTD = 2};
 /*!
  * \brief Enumerates the tables in the database
  */
-enum class DbTable {Any, Flights, Simulators, Pilots, Tails, Aircraft, Airports, Currencies, Changelog};
+enum class DbTable {Any, Flights, Simulators, Pilots, Tails, Aircraft, Airports, Currencies, Changelog, PreviousExperience};
 
 /*!
  * \brief Enumerates the currency names
@@ -202,6 +226,7 @@ private:
         {DbTable::Airports,     QStringLiteral("airports")},
         {DbTable::Currencies,   QStringLiteral("currencies")},
         {DbTable::Changelog,    QStringLiteral("changelog")},
+        {DbTable::PreviousExperience,    QStringLiteral("previousExperience")},
     };
 
     const static inline QStringList APPROACH_TYPES = {
@@ -233,118 +258,6 @@ private:
 //Make available as a global static
 Q_GLOBAL_STATIC(OplGlobals, GLOBALS)
 
-/*!
- *  The OPL::Db namespace provides string literals to programatically access the database
- *
- *  Example usage, do:
- *  newData.insert(OPL::Db::FLIGHTS_DEP, ui->deptLocLineEdit->text());
- *  newData.value(OPL::Db::AIRCRAFT_MULTIPILOT);
- *
- *  instead of:
- *  newData.insert("dept", ui->deptLocLineEdit->text());
- *  newData.value("multipilot");
- *
- *  Declaring these literals here avoids memory allocation at runtime for construction of temporary
- *  qstrings like ("dept").
- */
-namespace Db {
-
-
-// Table names
-const inline auto TABLE_FLIGHTS          = QStringLiteral("flights");
-const inline auto TABLE_PILOTS           = QStringLiteral("pilots");
-const inline auto TABLE_TAILS            = QStringLiteral("tails");
-const inline auto TABLE_AIRCRAFT         = QStringLiteral("aircraft");
-const inline auto TABLE_AIRPORTS         = QStringLiteral("airports");
-const inline auto TABLE_CURRENCIES       = QStringLiteral("currencies");
-const inline auto TABLE_SIMULATORS       = QStringLiteral("simulators");
-
-// Flights table columns
-const inline auto FLIGHTS_ROWID          = QStringLiteral("flight_id");
-const inline auto FLIGHTS_DOFT           = QStringLiteral("doft");
-const inline auto FLIGHTS_DEPT           = QStringLiteral("dept");
-const inline auto FLIGHTS_DEST           = QStringLiteral("dest");
-const inline auto FLIGHTS_TOFB           = QStringLiteral("tofb");
-const inline auto FLIGHTS_TONB           = QStringLiteral("tonb");
-const inline auto FLIGHTS_PIC            = QStringLiteral("pic");
-const inline auto FLIGHTS_ACFT           = QStringLiteral("acft");
-const inline auto FLIGHTS_TBLK           = QStringLiteral("tblk");
-const inline auto FLIGHTS_TSPSE          = QStringLiteral("tSPSE");
-const inline auto FLIGHTS_TSPME          = QStringLiteral("tSPME");
-const inline auto FLIGHTS_TMP            = QStringLiteral("tMP");
-const inline auto FLIGHTS_TNIGHT         = QStringLiteral("tNIGHT");
-const inline auto FLIGHTS_TIFR           = QStringLiteral("tIFR");
-const inline auto FLIGHTS_TPIC           = QStringLiteral("tPIC");
-const inline auto FLIGHTS_TPICUS         = QStringLiteral("tPICUS");
-const inline auto FLIGHTS_TSIC           = QStringLiteral("tSIC");
-const inline auto FLIGHTS_TDUAL          = QStringLiteral("tDUAL");
-const inline auto FLIGHTS_TFI            = QStringLiteral("tFI");
-const inline auto FLIGHTS_TSIM           = QStringLiteral("tSIM");
-const inline auto FLIGHTS_PILOTFLYING    = QStringLiteral("pilotFlying");
-const inline auto FLIGHTS_TODAY          = QStringLiteral("toDay");
-const inline auto FLIGHTS_TONIGHT        = QStringLiteral("toNight");
-const inline auto FLIGHTS_LDGDAY         = QStringLiteral("ldgDay");
-const inline auto FLIGHTS_LDGNIGHT       = QStringLiteral("ldgNight");
-const inline auto FLIGHTS_AUTOLAND       = QStringLiteral("autoland");
-const inline auto FLIGHTS_SECONDPILOT    = QStringLiteral("secondPilot");
-const inline auto FLIGHTS_THIRDPILOT     = QStringLiteral("thirdPilot");
-const inline auto FLIGHTS_APPROACHTYPE   = QStringLiteral("approachType");
-const inline auto FLIGHTS_FLIGHTNUMBER   = QStringLiteral("flightNumber");
-const inline auto FLIGHTS_REMARKS        = QStringLiteral("remarks");
-
-// tails table
-
-const inline auto TAILS_ROWID            = QStringLiteral("tail_id");
-const inline auto TAILS_REGISTRATION     = QStringLiteral("registration");
-const inline auto TAILS_COMPANY          = QStringLiteral("company");
-const inline auto TAILS_MAKE             = QStringLiteral("make");
-const inline auto TAILS_MODEL            = QStringLiteral("model");
-const inline auto TAILS_VARIANT          = QStringLiteral("variant");
-const inline auto TAILS_MULTIPILOT       = QStringLiteral("multipilot");
-const inline auto TAILS_MULTIENGINE      = QStringLiteral("multiengine");
-const inline auto TAILS_ENGINETYPE       = QStringLiteral("engineType");
-const inline auto TAILS_WEIGHTCLASS      = QStringLiteral("weightClass");
-
-// pilots table
-
-const inline auto  PILOTS_ROWID           = QStringLiteral("pilot_id");
-const inline auto  PILOTS_LASTNAME        = QStringLiteral("lastname");
-const inline auto  PILOTS_FIRSTNAME       = QStringLiteral("firstname");
-const inline auto  PILOTS_ALIAS           = QStringLiteral("alias");
-const inline auto  PILOTS_COMPANY         = QStringLiteral("company");
-const inline auto  PILOTS_EMPLOYEEID      = QStringLiteral("employeeid");
-const inline auto  PILOTS_PHONE           = QStringLiteral("phone");
-const inline auto  PILOTS_EMAIL           = QStringLiteral("email");
-
-// Currencies table
-const inline auto  CURRENCIES_EXPIRYDATE  = QStringLiteral("expiryDate");
-const inline auto  CURRENCIES_CURRENCYNAME = QStringLiteral("currencyName");
-
-// Simulators table
-const inline auto  SIMULATORS_ROWID       = QStringLiteral("session_id");
-const inline auto  SIMULATORS_DATE        = QStringLiteral("date");
-const inline auto  SIMULATORS_TIME        = QStringLiteral("totalTime");
-const inline auto  SIMULATORS_TYPE        = QStringLiteral("deviceType");
-const inline auto  SIMULATORS_ACFT        = QStringLiteral("aircraftType");
-const inline auto  SIMULATORS_REG         = QStringLiteral("registration");
-const inline auto  SIMULATORS_REMARKS     = QStringLiteral("remarks");
-
-// Airports table
-const inline auto AIRPORTS_ICAO           = QStringLiteral("icao");
-const inline auto AIRPORTS_IATA           = QStringLiteral("iata");
-const inline auto AIRPORTS_NAME           = QStringLiteral("name");
-const inline auto AIRPORTS_LAT            = QStringLiteral("lat");
-const inline auto AIRPORTS_LON            = QStringLiteral("long");
-const inline auto AIRPORTS_COUNTRY        = QStringLiteral("country");
-const inline auto AIRPORTS_ALTITIDUE      = QStringLiteral("alt");
-const inline auto AIRPORTS_UTC_OFFSET     = QStringLiteral("utcoffset");
-const inline auto AIRPORTS_TZ_OLSON       = QStringLiteral("tzolson");
-
-// all tables
-const inline auto  ROWID                  = QStringLiteral("rowid");
-const inline auto  NULL_TIME_hhmm         = QStringLiteral("00:00");
-
-} // namespace OPL::db
 
 namespace Assets {
 
@@ -382,7 +295,7 @@ const inline auto  ICON_TOOLBAR_BACKUP_DARK      = QStringLiteral(":/icons/opl-i
 
 }
 
-namespace Styles {
+namespace CssStyles {
 
 const inline auto  RED_BORDER = QStringLiteral("border: 1px solid red");
 } // namespace Styles
@@ -393,6 +306,15 @@ const inline auto TIME_FORMAT = QStringLiteral("hh:mm");
 
 } // 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_AIRPORT_CODE  = QRegularExpression(QStringLiteral("[a-zA-Z0-9]{1,4}"));
+
+} // namespace RegEx
+
 } // namespace opl
 
 #endif // OPLCONSTANTS_H

+ 1 - 1
src/testing/atimer.cpp

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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

+ 1 - 2
src/testing/atimer.h

@@ -1,6 +1,6 @@
 /*
  *openPilotLog - A FOSS Pilot Logbook Application
- *Copyright (C) 2020-2022 Felix Turowsky
+ *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
@@ -21,7 +21,6 @@
 #include <QObject>
 #include <chrono>
 #include <QDebug>
-#include "src/functions/log.h"
 
 /*!
  * \brief The ATimer class provides an easy to use performance timer.

+ 2 - 3
src/testing/importCrewlounge/importcrewlounge.cpp

@@ -1,7 +1,6 @@
 #include "importcrewlounge.h"
 #include "src/database/database.h"
 #include "src/opl.h"
-#include "src/database/row.h"
 #include "src/testing/importCrewlounge/processpilots.h"
 #include "src/testing/importCrewlounge/processaircraft.h"
 #include "src/testing/importCrewlounge/processflights.h"
@@ -30,7 +29,7 @@ void exec(const QString &csv_file_path)
     const auto p_maps = proc_pilots.getProcessedPilotMaps();
 
     for (const auto & pilot_data : p_maps) {
-        OPL::PilotEntry pe(pilot_data.value(OPL::Db::PILOTS_ROWID).toInt(), pilot_data);
+        OPL::PilotEntry pe(pilot_data.value(OPL::PilotEntry::ROWID).toInt(), pilot_data);
         DB->commit(pe);
     }
 
@@ -40,7 +39,7 @@ void exec(const QString &csv_file_path)
     const auto t_maps = proc_tails.getProcessedTailMaps();
 
     for (const auto& tail_data : t_maps) {
-        OPL::TailEntry te(tail_data.value(OPL::Db::PILOTS_ROWID).toInt(), tail_data);
+        OPL::TailEntry te(tail_data.value(OPL::PilotEntry::ROWID).toInt(), tail_data);
         DB->commit(te);
     }
 

+ 14 - 13
src/testing/importCrewlounge/processaircraft.cpp

@@ -1,4 +1,5 @@
 #include "processaircraft.h"
+#include "src/database/tailentry.h"
 
 void ProcessAircraft::parseRawData()
 {
@@ -23,31 +24,31 @@ void ProcessAircraft::processParsedData()
 
     QHash<QString, QVariant> new_tail_data;
     for (const auto &list : qAsConst(unique_tails)) {
-        new_tail_data.insert(OPL::Db::TAILS_REGISTRATION, list[0]);
-        new_tail_data.insert(OPL::Db::TAILS_COMPANY, list[1]);
-        new_tail_data.insert(OPL::Db::TAILS_MAKE, list[2]);
-        new_tail_data.insert(OPL::Db::TAILS_MODEL, list[3]);
-        new_tail_data.insert(OPL::Db::TAILS_VARIANT, list[4]);
+        new_tail_data.insert(OPL::TailEntry::REGISTRATION, list[0]);
+        new_tail_data.insert(OPL::TailEntry::COMPANY, list[1]);
+        new_tail_data.insert(OPL::TailEntry::MAKE, list[2]);
+        new_tail_data.insert(OPL::TailEntry::MODEL, list[3]);
+        new_tail_data.insert(OPL::TailEntry::VARIANT, list[4]);
 
         if (list[5] == "TRUE")
-            new_tail_data.insert(OPL::Db::TAILS_MULTIPILOT, 1);
+            new_tail_data.insert(OPL::TailEntry::MULTI_PILOT, 1);
         else
-            new_tail_data.insert(OPL::Db::TAILS_MULTIPILOT, 0);
+            new_tail_data.insert(OPL::TailEntry::MULTI_PILOT, 0);
 
         if (list[6] == "TRUE")
-            new_tail_data.insert(OPL::Db::TAILS_MULTIENGINE, 1);
+            new_tail_data.insert(OPL::TailEntry::MULTI_ENGINE, 1);
         else
-            new_tail_data.insert(OPL::Db::TAILS_MULTIENGINE, 0);
+            new_tail_data.insert(OPL::TailEntry::MULTI_ENGINE, 0);
 
         if (list[7] == "Piston") // other values need to be added as needed, do later
-            new_tail_data.insert(OPL::Db::TAILS_ENGINETYPE, 1);
+            new_tail_data.insert(OPL::TailEntry::ENGINE_TYPE, 1);
         else if (list[7] == "Turbine (jet-fan)")
-            new_tail_data.insert(OPL::Db::TAILS_ENGINETYPE, 3);
+            new_tail_data.insert(OPL::TailEntry::ENGINE_TYPE, 3);
 
         if (list[8] == "TRUE") // this is a above 7.5t switch in MCC, so default to medium for now
-            new_tail_data.insert(OPL::Db::TAILS_WEIGHTCLASS, 1);
+            new_tail_data.insert(OPL::TailEntry::WEIGHT_CLASS, 1);
         else
-            new_tail_data.insert(OPL::Db::TAILS_WEIGHTCLASS, 0);
+            new_tail_data.insert(OPL::TailEntry::WEIGHT_CLASS, 0);
 
         new_tail_data.insert(QStringLiteral("tail_id"), unique_tail_id);
 

+ 0 - 1
src/testing/importCrewlounge/processaircraft.h

@@ -1,7 +1,6 @@
 #ifndef PROCESSAIRCRAFT_H
 #define PROCESSAIRCRAFT_H
 #include <QtCore>
-#include "src/opl.h"
 
 class ProcessAircraft
 {

+ 29 - 28
src/testing/importCrewlounge/processflights.cpp

@@ -1,5 +1,6 @@
 #include "processflights.h"
-#include <src/functions/time.h>
+#include "src/classes/time.h"
+#include "src/database/flightentry.h"
 
 void ProcessFlights::parseRawData()
 {
@@ -23,57 +24,57 @@ void ProcessFlights::processParsedData()
 
     for (const auto &row : qAsConst(rawFlightData)) {
         // insert values that don't require editing
-        new_flight_data.insert(OPL::Db::FLIGHTS_FLIGHTNUMBER, row[1]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_DEPT, row[2]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_DEST, row[3]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TBLK, row[6]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TPIC, row[7]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TSIC, row[8]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TDUAL, row[9]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TPICUS, row[10]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TFI, row[11]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TNIGHT, row[12]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TODAY, row[16]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TONIGHT, row[17]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_LDGDAY, row[18]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, row[19]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_APPROACHTYPE, row[21]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_REMARKS, row[22]);
+        new_flight_data.insert(OPL::FlightEntry::FLIGHTNUMBER, row[1]);
+        new_flight_data.insert(OPL::FlightEntry::DEPT, row[2]);
+        new_flight_data.insert(OPL::FlightEntry::DEST, row[3]);
+        new_flight_data.insert(OPL::FlightEntry::TBLK, row[6]);
+        new_flight_data.insert(OPL::FlightEntry::TPIC, row[7]);
+        new_flight_data.insert(OPL::FlightEntry::TSIC, row[8]);
+        new_flight_data.insert(OPL::FlightEntry::TDUAL, row[9]);
+        new_flight_data.insert(OPL::FlightEntry::TPICUS, row[10]);
+        new_flight_data.insert(OPL::FlightEntry::TFI, row[11]);
+        new_flight_data.insert(OPL::FlightEntry::TNIGHT, row[12]);
+        new_flight_data.insert(OPL::FlightEntry::TODAY, row[16]);
+        new_flight_data.insert(OPL::FlightEntry::TONIGHT, row[17]);
+        new_flight_data.insert(OPL::FlightEntry::LDGDAY, row[18]);
+        new_flight_data.insert(OPL::FlightEntry::LDGNIGHT, row[19]);
+        new_flight_data.insert(OPL::FlightEntry::APPROACHTYPE, row[21]);
+        new_flight_data.insert(OPL::FlightEntry::REMARKS, row[22]);
 
         // PF
         if (row[20] == QLatin1String("TRUE"))
-            new_flight_data.insert(OPL::Db::FLIGHTS_PILOTFLYING, 1);
+            new_flight_data.insert(OPL::FlightEntry::PILOTFLYING, 1);
         else
-            new_flight_data.insert(OPL::Db::FLIGHTS_PILOTFLYING, 0);
+            new_flight_data.insert(OPL::FlightEntry::PILOTFLYING, 0);
 
         // Convert Date and Time
         const QDate doft = QDate::fromString(row[0],QStringLiteral("dd/MM/yyyy"));
-        new_flight_data.insert(OPL::Db::FLIGHTS_DOFT, doft.toString(Qt::ISODate));
+        new_flight_data.insert(OPL::FlightEntry::DOFT, doft.toString(Qt::ISODate));
 
         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::toMinutes(time_off);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TOFB, tofb);
+        int tofb = OPL::Time::fromString(time_off.toString()).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::toMinutes(time_on);
-        new_flight_data.insert(OPL::Db::FLIGHTS_TONB, tonb);
+        int tonb = OPL::Time::fromString(time_on.toString()).toMinutes();
+        new_flight_data.insert(OPL::FlightEntry::TONB, tonb);
 
         // map pilots
         int pic = processedPilotsIds.value(row[13]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_PIC, pic);
+        new_flight_data.insert(OPL::FlightEntry::PIC, pic);
         int second_pilot = processedPilotsIds.value(row[14]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, second_pilot);
+        new_flight_data.insert(OPL::FlightEntry::SECONDPILOT, second_pilot);
         int third_pilot = processedPilotsIds.value(row[15]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_THIRDPILOT, third_pilot);
+        new_flight_data.insert(OPL::FlightEntry::THIRDPILOT, third_pilot);
 
         // map tail
         int acft = processedTailsIds.value(row[23]);
-        new_flight_data.insert(OPL::Db::FLIGHTS_ACFT, acft);
+        new_flight_data.insert(OPL::FlightEntry::ACFT, acft);
 
         // set id, fix opl to include alias
         new_flight_data.insert(QStringLiteral("flight_id"), flight_id);

+ 7 - 6
src/testing/importCrewlounge/processpilots.cpp

@@ -1,4 +1,5 @@
 #include "processpilots.h"
+#include "src/database/pilotentry.h"
 
 void ProcessPilots::parseRawData()
 {
@@ -51,19 +52,19 @@ void ProcessPilots::processParsedData()
         // process name [1]
         auto temp_list = pair.first[1].split(QLatin1Char(' '));
         if (!temp_list.isEmpty()) {
-            new_pilot_data.insert(OPL::Db::PILOTS_LASTNAME, temp_list.first());
+            new_pilot_data.insert(OPL::PilotEntry::LASTNAME, temp_list.first());
             temp_list.pop_front();
 
             if (!temp_list.isEmpty())
-                new_pilot_data.insert(OPL::Db::PILOTS_FIRSTNAME, temp_list.join(QLatin1Char(' ')));
+                new_pilot_data.insert(OPL::PilotEntry::FIRSTNAME, temp_list.join(QLatin1Char(' ')));
         } else {
-            new_pilot_data.insert(OPL::Db::PILOTS_LASTNAME, QStringLiteral("UNKNOWN"));
+            new_pilot_data.insert(OPL::PilotEntry::LASTNAME, QStringLiteral("UNKNOWN"));
         }
 
         // add additional data
-        new_pilot_data.insert(OPL::Db::PILOTS_EMPLOYEEID, pair.first[0]);
-        new_pilot_data.insert(OPL::Db::PILOTS_PHONE, pair.first[2]);
-        new_pilot_data.insert(OPL::Db::PILOTS_EMAIL, pair.first[3]);
+        new_pilot_data.insert(OPL::PilotEntry::EMPLOYEEID, pair.first[0]);
+        new_pilot_data.insert(OPL::PilotEntry::PHONE, pair.first[2]);
+        new_pilot_data.insert(OPL::PilotEntry::EMAIL, pair.first[3]);
 
         // add pilot_id (workaround with literal until OPL::Db is updated)
         new_pilot_data.insert(QStringLiteral("pilot_id"), pair.second);

+ 21 - 22
src/testing/randomgenerator.cpp

@@ -2,7 +2,6 @@
 #include "src/database/database.h"
 #include "src/functions/calc.h"
 #include "src/opl.h"
-#include "src/functions/time.h"
 
 namespace OPL {
 
@@ -20,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);
-    int tofb = OPL::Time::toMinutes(dept_dt.time());
-    int tonb = OPL::Time::toMinutes(dest_dt.time());
+    OPL::Time tofb = OPL::Time::fromString(dept_dt.time().toString());
+    OPL::Time tonb = OPL::Time::fromString(dest_dt.time().toString());
 
     int pic = randomPilot();
     int acft = randomTail();
@@ -29,43 +28,43 @@ const FlightEntry RandomGenerator::randomFlight()
     const QString dept = randomAirport();
     const QString dest = randomAirport();
 
-    int tblk = OPL::Time::blockMinutes(dept_dt.time(), dest_dt.time());
+    int tblk = OPL::Time::blockMinutes(tofb, tonb);
     int tNight = OPL::Calc::calculateNightTime(dept, dest, dept_dt, tblk, 6);
 
     auto flt_data = OPL::RowData_T();
-    flt_data.insert(OPL::Db::FLIGHTS_DOFT, doft);
-    flt_data.insert(OPL::Db::FLIGHTS_DEPT, dept);
-    flt_data.insert(OPL::Db::FLIGHTS_DEST, dest);
-    flt_data.insert(OPL::Db::FLIGHTS_PIC, pic);
-    flt_data.insert(OPL::Db::FLIGHTS_ACFT, acft);
-    flt_data.insert(OPL::Db::FLIGHTS_TOFB, tofb);
-    flt_data.insert(OPL::Db::FLIGHTS_TONB, tonb);
-    flt_data.insert(OPL::Db::FLIGHTS_TBLK, tblk);
+    flt_data.insert(OPL::FlightEntry::DOFT, doft);
+    flt_data.insert(OPL::FlightEntry::DEPT, dept);
+    flt_data.insert(OPL::FlightEntry::DEST, dest);
+    flt_data.insert(OPL::FlightEntry::PIC, pic);
+    flt_data.insert(OPL::FlightEntry::ACFT, acft);
+    flt_data.insert(OPL::FlightEntry::TOFB, tofb.toMinutes());
+    flt_data.insert(OPL::FlightEntry::TONB, tonb.toMinutes());
+    flt_data.insert(OPL::FlightEntry::TBLK, tblk);
 
-    if (tNight > 0) flt_data.insert(OPL::Db::FLIGHTS_TNIGHT, tNight);
+    if (tNight > 0) flt_data.insert(OPL::FlightEntry::TNIGHT, tNight);
 
     bool pf = randomBool(); // Pilot Flying
 
     // Take-Off and Landing
     if (pf) {
-        flt_data.insert(OPL::Db::FLIGHTS_PILOTFLYING, 1);
+        flt_data.insert(OPL::FlightEntry::PILOTFLYING, 1);
         if (OPL::Calc::isNight(dept, dept_dt, 6))
-            flt_data.insert(OPL::Db::FLIGHTS_TONIGHT, 1);
+            flt_data.insert(OPL::FlightEntry::TONIGHT, 1);
         else
-            flt_data.insert(OPL::Db::FLIGHTS_TODAY, 1);
+            flt_data.insert(OPL::FlightEntry::TODAY, 1);
         if (OPL::Calc::isNight(dest, dest_dt, 6))
-            flt_data.insert(OPL::Db::FLIGHTS_LDGNIGHT, 1);
+            flt_data.insert(OPL::FlightEntry::LDGNIGHT, 1);
         else
-            flt_data.insert(OPL::Db::FLIGHTS_LDGDAY, 1);
+            flt_data.insert(OPL::FlightEntry::LDGDAY, 1);
     }
 
     int function;
     if (pic == 1) {
-        flt_data.insert(OPL::Db::FLIGHTS_TPIC, tblk);
-        flt_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, randomPilot());
+        flt_data.insert(OPL::FlightEntry::TPIC, tblk);
+        flt_data.insert(OPL::FlightEntry::SECONDPILOT, randomPilot());
     } else {
         function = QRandomGenerator::global()->bounded(1,4);
-        flt_data.insert(OPL::Db::FLIGHTS_SECONDPILOT, 1);
+        flt_data.insert(OPL::FlightEntry::SECONDPILOT, 1);
         flt_data.insert(m_function_times[function], tblk);
     }
 
@@ -100,7 +99,7 @@ const QDateTime RandomGenerator::randomDateTime()
 
 const QString RandomGenerator::randomAirport()
 {
-    return DB->getAirportEntry(QRandomGenerator::global()->bounded(1, m_numberOfAirports)).icao();
+    return DB->getAirportEntry(QRandomGenerator::global()->bounded(1, m_numberOfAirports)).getIcaoCode();
 }
 
 const int RandomGenerator::randomPilot()

+ 6 - 6
src/testing/randomgenerator.h

@@ -1,7 +1,7 @@
 #ifndef RANDOMGENERATOR_H
 #define RANDOMGENERATOR_H
 
-#include "src/database/row.h"
+#include "src/database/flightentry.h"
 namespace OPL {
 
 /*!
@@ -30,11 +30,11 @@ public:
 private:
     bool safeMode = false;
     const static inline QStringList m_function_times = {
-        OPL::Db::FLIGHTS_TPIC,
-        OPL::Db::FLIGHTS_TPICUS,
-        OPL::Db::FLIGHTS_TSIC,
-        OPL::Db::FLIGHTS_TDUAL,
-        OPL::Db::FLIGHTS_TFI,
+        OPL::FlightEntry::TPIC,
+        OPL::FlightEntry::TPICUS,
+        OPL::FlightEntry::TSIC,
+        OPL::FlightEntry::TDUAL,
+        OPL::FlightEntry::TFI,
     };
 
     int m_numberOfPilots;