31#include <wx/filename.h>
41static void ReportError(
const std::string zmsg);
43static bool executeSQL(sqlite3* db,
const char* sql) {
44 char* errMsg =
nullptr;
45 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
47 wxString::Format(_(
"navobj database error.") +
" %s", errMsg);
49 auto& noteman = NotificationManager::GetInstance();
50 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
57static bool executeSQL(sqlite3* db, wxString& sql) {
58 return executeSQL(db, sql.ToStdString().c_str());
61bool CreateTables(sqlite3* db) {
63 const char* create_tables_sql = R
"(
64 CREATE TABLE IF NOT EXISTS tracks (
65 guid TEXT PRIMARY KEY NOT NULL,
74 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
77 CREATE TABLE IF NOT EXISTS trk_points (
78 track_guid TEXT NOT NULL,
79 latitude REAL NOT NULL,
80 longitude REAL NOT NULL,
81 timestamp TEXT NOT NULL,
83 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
87 CREATE TABLE IF NOT EXISTS track_html_links (
88 guid TEXT PRIMARY KEY,
89 track_guid TEXT NOT NULL,
91 html_description TEXT,
93 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
97 CREATE TABLE IF NOT EXISTS routes (
98 guid TEXT PRIMARY KEY NOT NULL,
103 planned_departure TEXT,
110 shared_wp_viz INTEGER,
111 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
115 CREATE TABLE IF NOT EXISTS routepoints (
116 guid TEXT PRIMARY KEY NOT NULL,
128 RangeRingsNumber INTEGER,
130 RangeRingsStepUnits INTEGER,
131 RangeRingsVisible INTEGER,
132 RangeRingsColour TEXT,
140 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
143 CREATE TABLE IF NOT EXISTS routepoints_link (
147 PRIMARY KEY (route_guid, point_order),
148 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
151 CREATE TABLE IF NOT EXISTS route_html_links (
152 guid TEXT PRIMARY KEY,
153 route_guid TEXT NOT NULL,
155 html_description TEXT,
157 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
160 CREATE TABLE IF NOT EXISTS routepoint_html_links (
161 guid TEXT PRIMARY KEY,
162 routepoint_guid TEXT NOT NULL,
164 html_description TEXT,
166 FOREIGN KEY (routepoint_guid) REFERENCES routepoints(guid) ON DELETE CASCADE
171 if (!executeSQL(db, create_tables_sql))
return false;
176bool TrackExists(sqlite3* db,
const std::string& track_guid) {
177 const char* sql =
"SELECT 1 FROM tracks WHERE guid = ? LIMIT 1";
181 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
182 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
184 if (sqlite3_step(stmt) == SQLITE_ROW) {
188 sqlite3_finalize(stmt);
190 ReportError(
"TrackExists:prepare");
196bool TrackHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
197 const char* sql =
"SELECT 1 FROM track_html_links WHERE guid = ? LIMIT 1";
201 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
202 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
204 if (sqlite3_step(stmt) == SQLITE_ROW) {
208 sqlite3_finalize(stmt);
210 ReportError(
"TrackHtmlLinkExists:prepare");
216bool DeleteAllCommentsForTrack(sqlite3* db,
const std::string& track_guid) {
217 const char* sql =
"DELETE FROM track_html_links WHERE track_guid = ?";
220 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
221 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
222 if (sqlite3_step(stmt) != SQLITE_DONE) {
223 ReportError(
"DeleteAllCommentsForTrack:step");
227 sqlite3_finalize(stmt);
229 ReportError(
"DeleteAllCommentsForTrack:prepare");
235bool InsertTrackPoint(sqlite3* db,
const std::string& track_guid,
double lat,
236 double lon,
const std::string& timestamp,
int i_point) {
237 const char* sql = R
"(
238 INSERT INTO trk_points (track_guid, latitude, longitude, timestamp, point_order)
239 VALUES (?, ?, ?, ?, ?)
243 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
244 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
245 sqlite3_bind_double(stmt, 2, lat);
246 sqlite3_bind_double(stmt, 3, lon);
247 sqlite3_bind_text(stmt, 4, timestamp.c_str(), -1, SQLITE_TRANSIENT);
248 sqlite3_bind_int(stmt, 5, i_point);
249 if (sqlite3_step(stmt) != SQLITE_DONE) {
250 ReportError(
"InsertTrackPoint:step");
251 sqlite3_finalize(stmt);
254 sqlite3_finalize(stmt);
261bool InsertTrackHTML(sqlite3* db,
const std::string& track_guid,
262 const std::string& link_guid,
const std::string& descrText,
263 const std::string& link,
const std::string& ltype) {
264 const char* sql = R
"(
265 INSERT INTO track_html_links (guid, track_guid, html_link, html_description, html_type)
266 VALUES (?, ?, ?, ?, ?)
270 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
271 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
272 sqlite3_bind_text(stmt, 2, track_guid.c_str(), -1, SQLITE_TRANSIENT);
273 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
274 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
275 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
276 if (sqlite3_step(stmt) != SQLITE_DONE) {
277 ReportError(
"InsertTrackHTML:step");
278 sqlite3_finalize(stmt);
281 sqlite3_finalize(stmt);
290bool DeleteAllCommentsForRoute(sqlite3* db,
const std::string& route_guid) {
291 const char* sql = R
"(
292 DELETE FROM route_html_links WHERE route_guid = ?
295 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
296 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
297 if (sqlite3_step(stmt) != SQLITE_DONE) {
298 ReportError(
"DeleteAllCommentsForRoute:step");
299 sqlite3_finalize(stmt);
302 sqlite3_finalize(stmt);
309bool RouteHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
310 const char* sql =
"SELECT 1 FROM route_html_links WHERE guid = ? LIMIT 1";
314 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
315 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
317 if (sqlite3_step(stmt) == SQLITE_ROW) {
321 sqlite3_finalize(stmt);
328bool RoutePointHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
330 "SELECT 1 FROM routepoint_html_links WHERE guid = ? LIMIT 1";
334 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
335 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
337 if (sqlite3_step(stmt) == SQLITE_ROW) {
341 sqlite3_finalize(stmt);
348bool RouteExistsDB(sqlite3* db,
const std::string& route_guid) {
349 const char* sql =
"SELECT 1 FROM routes WHERE guid = ? LIMIT 1";
353 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
354 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
356 if (sqlite3_step(stmt) == SQLITE_ROW) {
360 sqlite3_finalize(stmt);
367bool InsertRouteHTML(sqlite3* db,
const std::string& route_guid,
368 const std::string& link_guid,
const std::string& descrText,
369 const std::string& link,
const std::string& ltype) {
370 const char* sql = R
"(
371 INSERT INTO route_html_links (guid, route_guid, html_link, html_description, html_type)
372 VALUES (?, ?, ?, ?, ?)
376 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
377 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
378 sqlite3_bind_text(stmt, 2, route_guid.c_str(), -1, SQLITE_TRANSIENT);
379 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
380 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
381 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
382 if (sqlite3_step(stmt) != SQLITE_DONE) {
383 ReportError(
"InsertRouteHTML:step");
384 sqlite3_finalize(stmt);
387 sqlite3_finalize(stmt);
394bool RoutePointExists(sqlite3* db,
const std::string& routepoint_guid) {
395 const char* sql =
"SELECT 1 FROM routepoints WHERE guid = ? LIMIT 1";
399 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
400 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
402 if (sqlite3_step(stmt) == SQLITE_ROW) {
406 sqlite3_finalize(stmt);
413bool InsertRoutePointHTML(sqlite3* db,
const std::string& point_guid,
414 const std::string& link_guid,
415 const std::string& descrText,
const std::string& link,
416 const std::string& ltype) {
417 const char* sql = R
"(
418 INSERT INTO routepoint_html_links (guid, routepoint_guid, html_link, html_description, html_type)
419 VALUES (?, ?, ?, ?, ?)
423 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
424 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
425 sqlite3_bind_text(stmt, 2, point_guid.c_str(), -1, SQLITE_TRANSIENT);
426 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
427 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
428 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
429 if (sqlite3_step(stmt) != SQLITE_DONE) {
430 ReportError(
"InsertRoutePointHTML:step");
431 sqlite3_finalize(stmt);
434 sqlite3_finalize(stmt);
440bool DeleteAllCommentsForRoutePoint(sqlite3* db,
441 const std::string& routepoint_guid) {
443 "DELETE FROM routepoint_html_links WHERE routepoint_guid = ?";
446 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
447 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
448 if (sqlite3_step(stmt) != SQLITE_DONE) {
449 ReportError(
"DeleteAllCommentsForRoutepoint:step");
453 sqlite3_finalize(stmt);
455 ReportError(
"DeleteAllCommentsForRoutepoint:prepare");
461bool InsertRoutePointDB(sqlite3* db,
RoutePoint* point) {
462 const char* sql = R
"(
463 INSERT or REPLACE INTO routepoints(guid)
468 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
469 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
471 if (sqlite3_step(stmt) != SQLITE_DONE) {
472 ReportError(
"InsertRoutePointDB:step");
473 sqlite3_finalize(stmt);
476 sqlite3_finalize(stmt);
485 const char* sql = R
"(
486 INSERT or IGNORE INTO routepoints_link (route_guid, point_guid, point_order)
492 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
493 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
495 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
497 sqlite3_bind_int(stmt, 3, point_order);
498 if (sqlite3_step(stmt) != SQLITE_DONE) {
499 ReportError(
"InsertTrackPointLink:step");
500 sqlite3_finalize(stmt);
503 sqlite3_finalize(stmt);
510void DeleteOrphanedRoutepoint(sqlite3* db) {
511 const char* sql = R
"(
512 DELETE FROM routepoints
513 WHERE guid NOT IN (SELECT point_guid FROM routepoints_link)
515 char* errMsg =
nullptr;
517 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
522void errorLogCallback(
void* pArg,
int iErrCode,
const char* zMsg) {
524 wxString::Format(_(
"navobj database error.") +
" %d: %s", iErrCode, zMsg);
526 auto& noteman = NotificationManager::GetInstance();
527 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
530static void ReportError(
const std::string zmsg) {
532 wxString::Format(_(
"navobj database error.") +
" %s", zmsg.c_str());
534 auto& noteman = NotificationManager::GetInstance();
535 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
543NavObj_dB::NavObj_dB() {
544 m_pImportProgress =
nullptr;
547 int ie = sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback,
nullptr);
551 wxFileName::GetPathSeparator() +
"navobj.db";
552 if (!wxFileExists(db_filename)) {
555 wxFileName::GetPathSeparator() +
"navobj.xml";
556 if (wxFileExists(xml_filename)) {
557 wxCopyFile(xml_filename, xml_filename +
".backup");
561 wxFileName::GetPathSeparator() +
562 "navobj.xml.import_backup";
563 if (!wxFileExists(deep_backup_filename)) {
564 wxCopyFile(xml_filename, deep_backup_filename);
570 int create_result = sqlite3_open_v2(
571 db_filename.ToStdString().c_str(),
573 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
576 if (create_result != SQLITE_OK) {
577 wxLogMessage(
"Cannot create new navobj.db database file");
586 int close_result = sqlite3_close_v2(m_db);
587 if (close_result != SQLITE_OK) {
593 int m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
594 SQLITE_OPEN_READWRITE, NULL);
595 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
599 sqlite3_close_v2(m_db);
601 m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
602 SQLITE_OPEN_READWRITE, NULL);
603 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
609NavObj_dB::~NavObj_dB() { sqlite3_close_v2(m_db); }
611void NavObj_dB::Close() {
612 sqlite3_close_v2(m_db);
616bool NavObj_dB::ImportLegacyNavobj(wxFrame* frame) {
618 wxFileName::GetPathSeparator() +
"navobj.xml";
620 if (::wxFileExists(navobj_filename)) {
622 CountImportNavObjects();
623 m_pImportProgress =
new wxProgressDialog(_(
"Importing Navobj database"),
"",
624 m_nImportObjects, frame);
625 m_import_progesscount = 0;
627 rv = ImportLegacyPoints();
628 rv |= ImportLegacyRoutes();
629 rv |= ImportLegacyTracks();
631 m_pImportProgress->Destroy();
635 if (::wxFileExists(navobj_filename)) ::wxRemoveFile(navobj_filename);
640void NavObj_dB::CountImportNavObjects() {
641 m_nImportObjects = 0;
648 wxFileName::GetPathSeparator() +
"navobj.xml";
650 if (::wxFileExists(navobj_filename) &&
651 input_set->load_file(navobj_filename.ToStdString().c_str()).status ==
652 pugi::xml_parse_status::status_ok) {
653 input_set->LoadAllGPXPointObjects();
654 auto pointlist = pWayPointMan->GetWaypointList();
662 input_set->LoadAllGPXRouteObjects();
666 m_nImportObjects += route_import->GetnPoints();
669 input_set->LoadAllGPXTrackObjects();
674 m_nImportObjects += track_import->GetnPoints();
680bool NavObj_dB::ImportLegacyTracks() {
681 std::vector<Track*> tracks_added;
685 if (InsertTrack(track_import)) {
686 tracks_added.push_back(track_import);
689 m_import_progesscount += track_import->GetnPoints() + 1;
690 wxString msg = wxString::Format(
"Tracks %d/%d", ntrack, m_nimportTracks);
691 m_pImportProgress->Update(m_import_progesscount, msg);
692 m_pImportProgress->Show();
696 for (
Track* ptrack : tracks_added) {
697 if (ptrack->m_bIsInLayer)
continue;
704bool NavObj_dB::ImportLegacyRoutes() {
705 std::vector<Route*> routes_added;
709 if (InsertRoute(route_import)) {
710 routes_added.push_back(route_import);
713 m_import_progesscount += route_import->GetnPoints() + 1;
714 wxString msg = wxString::Format(
"Routes %d/%d", nroute, m_nimportRoutes);
715 m_pImportProgress->Update(m_import_progesscount, msg);
716 m_pImportProgress->Show();
720 for (
Route* route : routes_added) {
726 pWayPointMan->DeleteAllWaypoints(
true);
731bool NavObj_dB::ImportLegacyPoints() {
732 std::vector<RoutePoint*> points_added;
736 if (m_nimportPoints > 1000) nmod = 10;
737 if (m_nimportPoints > 10000) nmod = 100;
739 for (
RoutePoint* point : *pWayPointMan->GetWaypointList()) {
741 if (InsertRoutePointDB(m_db, point)) {
742 points_added.push_back(point);
745 UpdateDBRoutePointAttributes(point);
746 m_import_progesscount += 1;
747 if ((npoint % nmod) == 0) {
749 wxString::Format(
"Points %d/%d", npoint, m_nimportPoints);
750 m_pImportProgress->Update(m_import_progesscount, msg);
751 m_pImportProgress->Show();
766void NavObj_dB::LoadNavObjects() {
772bool NavObj_dB::InsertTrack(
Track* track) {
773 if (TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
777 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
779 ReportError(
"InsertTrack:BEGIN TRANSACTION");
784 wxString sql = wxString::Format(
"INSERT INTO tracks (guid) VALUES ('%s')",
785 track->m_GUID.ToStdString().c_str());
786 if (!executeSQL(m_db, sql)) {
787 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
791 UpdateDBTrackAttributes(track);
794 for (
int i = 0; i < track->GetnPoints(); i++) {
795 auto point = track->GetPoint(i);
797 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
798 point->m_lon, point->GetTimeString(), i);
802 int NbrOfLinks = track->m_TrackHyperlinkList->size();
803 if (NbrOfLinks > 0) {
804 auto& list = track->m_TrackHyperlinkList;
805 for (
auto it = list->begin(); it != list->end(); ++it) {
807 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
808 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
809 link->DescrText.ToStdString(), link->Link.ToStdString(),
810 link->LType.ToStdString());
814 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
816 if (errMsg) rv =
false;
821bool NavObj_dB::UpdateTrack(
Track* track) {
825 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
827 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
829 ReportError(
"UpdateTrack:BEGIN TRANSACTION");
833 UpdateDBTrackAttributes(track);
836 const char* sql =
"DELETE FROM trk_points WHERE track_guid = ?";
838 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
839 sqlite3_bind_text(stmt, 1, track->m_GUID.ToStdString().c_str(), -1,
842 ReportError(
"UpdateTrack:prepare");
843 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
846 if (sqlite3_step(stmt) != SQLITE_DONE) {
847 ReportError(
"UpdateTrack:step");
848 sqlite3_finalize(stmt);
849 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
852 sqlite3_finalize(stmt);
855 for (
int i = 0; i < track->GetnPoints(); i++) {
856 auto point = track->GetPoint(i);
859 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
860 point->m_lon, point->GetTimeString(), i);
864 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
867 if (errMsg) rv =
false;
871bool NavObj_dB::UpdateDBTrackAttributes(
Track* track) {
885 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
886 sqlite3_bind_text(stmt, 1, track->GetName().ToStdString().c_str(), -1,
888 sqlite3_bind_text(stmt, 2, track->m_TrackDescription.ToStdString().c_str(),
889 -1, SQLITE_TRANSIENT);
890 sqlite3_bind_int(stmt, 3, track->m_bVisible);
891 sqlite3_bind_text(stmt, 4, track->m_TrackStartString.ToStdString().c_str(),
892 -1, SQLITE_TRANSIENT);
893 sqlite3_bind_text(stmt, 5, track->m_TrackEndString.ToStdString().c_str(),
894 -1, SQLITE_TRANSIENT);
895 sqlite3_bind_int(stmt, 6, track->m_width);
896 sqlite3_bind_int(stmt, 7,
897 (
int)(track->m_style));
898 sqlite3_bind_text(stmt, 8, track->m_Colour.ToStdString().c_str(), -1,
900 sqlite3_bind_text(stmt, 9, track->m_GUID.c_str(), track->m_GUID.size(),
906 if (sqlite3_step(stmt) != SQLITE_DONE) {
907 ReportError(
"UpdateDBTrackAttributesA:step");
908 sqlite3_finalize(stmt);
912 sqlite3_finalize(stmt);
917 DeleteAllCommentsForTrack(m_db, track->m_GUID.ToStdString());
920 int NbrOfLinks = track->m_TrackHyperlinkList->size();
921 if (NbrOfLinks > 0) {
922 auto& list = track->m_TrackHyperlinkList;
923 for (
auto it = list->begin(); it != list->end(); ++it) {
926 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
927 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
928 link->DescrText.ToStdString(), link->Link.ToStdString(),
929 link->LType.ToStdString());
932 "UPDATE track_html_links SET "
934 "html_description = ?, "
938 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
939 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
941 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
943 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
946 if (sqlite3_step(stmt) != SQLITE_DONE) {
947 ReportError(
"UpdateDBTRackAttributesB:step");
948 sqlite3_finalize(stmt);
951 sqlite3_finalize(stmt);
961 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
964 int this_point_index = track->GetnPoints();
967 if (!InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
968 point->m_lon, point->GetTimeString(),
969 this_point_index - 1))
975bool NavObj_dB::LoadAllTracks() {
976 const char* sql = R
"(
978 description, visibility, start_string, end_string,
982 ORDER BY created_at ASC
986 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
990 while (sqlite3_step(stmt) == SQLITE_ROW) {
992 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
994 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
995 std::string description =
996 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
997 int visibility = sqlite3_column_int(stmt, 3);
998 std::string start_string =
999 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1000 std::string end_string =
1001 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 5));
1002 int width = sqlite3_column_int(stmt, 6);
1003 int style = sqlite3_column_int(stmt, 7);
1005 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 8));
1006 std::string created =
1007 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1009 Track* new_trk = NULL;
1012 const char* sql = R
"(
1013 SELECT latitude, longitude, timestamp, point_order
1015 WHERE track_guid = ?
1016 ORDER BY point_order ASC
1019 sqlite3_stmt* stmtp;
1020 if (sqlite3_prepare_v2(m_db, sql, -1, &stmtp,
nullptr) != SQLITE_OK) {
1024 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1027 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1029 new_trk =
new Track;
1030 new_trk->m_GUID = guid;
1033 new_trk->SetVisible(visibility == 1);
1034 new_trk->SetName(name.c_str());
1035 new_trk->m_TrackStartString = start_string.c_str();
1036 new_trk->m_TrackEndString = end_string.c_str();
1037 new_trk->m_width = width;
1038 new_trk->m_style = (wxPenStyle)style;
1039 new_trk->m_Colour = color;
1042 double latitude = sqlite3_column_double(stmtp, 0);
1043 double longitude = sqlite3_column_double(stmtp, 1);
1044 std::string timestamp =
1045 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, 2));
1046 int point_order = sqlite3_column_int(stmtp, 3);
1048 auto point =
new TrackPoint(latitude, longitude, timestamp);
1050 point->m_GPXTrkSegNo = GPXTrkSeg;
1051 new_trk->AddPoint(point);
1053 sqlite3_finalize(stmtp);
1056 new_trk->SetCurrentTrackSeg(GPXTrkSeg);
1059 const char* sqlh = R
"(
1060 SELECT guid, html_link, html_description, html_type
1061 FROM track_html_links
1062 WHERE track_guid = ?
1063 ORDER BY html_type ASC
1068 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1069 sqlite3_bind_text(stmt, 1, new_trk->m_GUID.ToStdString().c_str(), -1,
1072 while (sqlite3_step(stmt) == SQLITE_ROW) {
1073 std::string link_guid =
1074 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1075 std::string link_link =
1076 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1077 std::string link_description =
1078 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1079 std::string link_type =
1080 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1083 h->DescrText = link_description;
1084 h->Link = link_link;
1085 h->LType = link_type;
1087 new_trk->m_TrackHyperlinkList->push_back(h);
1091 sqlite3_finalize(stmt);
1100 pSelect->AddAllSelectableTrackSegments(new_trk);
1106bool NavObj_dB::DeleteTrack(
Track* track) {
1107 if (!track)
return false;
1108 std::string track_guid = track->m_GUID.ToStdString();
1109 const char* sql =
"DELETE FROM tracks WHERE guid = ?";
1112 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1113 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
1114 if (sqlite3_step(stmt) != SQLITE_DONE) {
1115 ReportError(
"DeleteTrack:step");
1116 sqlite3_finalize(stmt);
1120 sqlite3_finalize(stmt);
1129bool NavObj_dB::InsertRoute(
Route* route) {
1133 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString())) {
1135 wxString sql = wxString::Format(
"INSERT INTO routes (guid) VALUES ('%s')",
1136 route->
m_GUID.ToStdString().c_str());
1137 if (!executeSQL(m_db, sql)) {
1140 UpdateDBRouteAttributes(route);
1143 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1145 ReportError(
"InsertRoute:BEGIN TRANSACTION");
1150 for (
int i = 0; i < route->GetnPoints(); i++) {
1151 auto point = route->GetPoint(i + 1);
1154 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1155 InsertRoutePointDB(m_db, point);
1156 UpdateDBRoutePointAttributes(point);
1162 for (
int i = 0; i < route->GetnPoints(); i++) {
1163 auto point = route->GetPoint(i + 1);
1166 InsertRoutePointLink(m_db, route, point, i + 1);
1172 if (NbrOfLinks > 0) {
1174 for (
auto it = list.begin(); it != list.end(); ++it) {
1176 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1177 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1178 link->DescrText.ToStdString(), link->Link.ToStdString(),
1179 link->LType.ToStdString());
1184 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1187 ReportError(
"InsertRoute:commit");
1193bool NavObj_dB::UpdateRoute(
Route* route) {
1197 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1199 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1201 ReportError(
"UpdateRoute:BEGIN TRANSACTION");
1205 UpdateDBRouteAttributes(route);
1208 for (
int i = 0; i < route->GetnPoints(); i++) {
1209 auto point = route->GetPoint(i + 1);
1212 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1213 InsertRoutePointDB(m_db, point);
1215 UpdateDBRoutePointAttributes(point);
1220 const char* sql =
"DELETE FROM routepoints_link WHERE route_guid = ?";
1222 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1223 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1226 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1229 if (sqlite3_step(stmt) != SQLITE_DONE) {
1230 ReportError(
"UpdateRoute:step");
1231 sqlite3_finalize(stmt);
1232 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1236 sqlite3_finalize(stmt);
1238 for (
int i = 0; i < route->GetnPoints(); i++) {
1239 auto point = route->GetPoint(i + 1);
1241 InsertRoutePointLink(m_db, route, point, i + 1);
1247 if (NbrOfLinks > 0) {
1249 for (
auto it = list.begin(); it != list.end(); ++it) {
1251 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1252 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1253 link->DescrText.ToStdString(), link->Link.ToStdString(),
1254 link->LType.ToStdString());
1258 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
1261 if (errMsg) rv =
false;
1266bool NavObj_dB::UpdateRouteViz(
Route* route) {
1269 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1271 UpdateDBRouteAttributes(route);
1273 for (
int i = 0; i < route->GetnPoints(); i++) {
1274 auto point = route->GetPoint(i + 1);
1277 UpdateDBRoutePointViz(point);
1281 if (errMsg) rv =
false;
1286bool NavObj_dB::UpdateDBRouteAttributes(
Route* route) {
1288 "UPDATE routes SET "
1291 "start_string = ?, "
1294 "shared_wp_viz = ?, "
1295 "planned_departure = ?, "
1304 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1305 sqlite3_bind_text(stmt, 1, route->GetName().ToStdString().c_str(), -1,
1308 -1, SQLITE_TRANSIENT);
1310 -1, SQLITE_TRANSIENT);
1312 -1, SQLITE_TRANSIENT);
1313 sqlite3_bind_int(stmt, 5, route->IsVisible());
1314 sqlite3_bind_int(stmt, 6, route->GetSharedWPViz());
1319 -1, SQLITE_TRANSIENT);
1320 sqlite3_bind_int(stmt, 10, route->
m_width);
1321 sqlite3_bind_int(stmt, 11,
1323 sqlite3_bind_text(stmt, 12, route->
m_Colour.ToStdString().c_str(), -1,
1325 sqlite3_bind_text(stmt, 13, route->
m_GUID.c_str(), route->
m_GUID.size(),
1331 if (sqlite3_step(stmt) != SQLITE_DONE) {
1332 ReportError(
"UpdateDBRouteAttributesA:step");
1333 sqlite3_finalize(stmt);
1337 sqlite3_finalize(stmt);
1342 DeleteAllCommentsForRoute(m_db, route->
m_GUID.ToStdString());
1346 if (NbrOfLinks > 0) {
1348 for (
auto it = list->begin(); it != list->end(); ++it) {
1350 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1351 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1352 link->DescrText.ToStdString(), link->Link.ToStdString(),
1353 link->LType.ToStdString());
1356 "UPDATE route_html_links SET "
1358 "html_description = ?, "
1362 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1363 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1365 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1367 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1370 if (sqlite3_step(stmt) != SQLITE_DONE) {
1373 if (sqlite3_step(stmt) != SQLITE_DONE) {
1374 ReportError(
"UpdateDBRouteAttributesB:step");
1375 sqlite3_finalize(stmt);
1378 sqlite3_finalize(stmt);
1385bool NavObj_dB::UpdateDBRoutePointAttributes(
RoutePoint* point) {
1387 "UPDATE routepoints SET "
1398 "ArrivalRadius = ?, "
1399 "RangeRingsNumber = ?, "
1400 "RangeRingsStep = ?, "
1401 "RangeRingsStepUnits = ?, "
1402 "RangeRingsVisible = ?, "
1403 "RangeRingsColour = ?, "
1414 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1415 sqlite3_bind_double(stmt, 1, point->GetLatitude());
1416 sqlite3_bind_double(stmt, 2, point->GetLongitude());
1417 sqlite3_bind_text(stmt, 3, point->GetIconName().ToStdString().c_str(), -1,
1419 sqlite3_bind_text(stmt, 4, point->GetName().ToStdString().c_str(), -1,
1421 sqlite3_bind_text(stmt, 5, point->GetDescription().ToStdString().c_str(),
1422 -1, SQLITE_TRANSIENT);
1423 sqlite3_bind_text(stmt, 6, point->
m_TideStation.ToStdString().c_str(), -1,
1428 sqlite3_bind_int(stmt, 8, etd);
1429 sqlite3_bind_text(stmt, 9,
"type", -1, SQLITE_TRANSIENT);
1430 std::string timit = point->
m_timestring.ToStdString().c_str();
1431 sqlite3_bind_text(stmt, 10, point->
m_timestring.ToStdString().c_str(), -1,
1444 -1, SQLITE_TRANSIENT);
1446 sqlite3_bind_int(stmt, 17, point->GetScaMin());
1447 sqlite3_bind_int(stmt, 18, point->GetScaMax());
1448 sqlite3_bind_int(stmt, 19, point->GetUseSca());
1450 sqlite3_bind_int(stmt, 20, point->IsVisible());
1451 sqlite3_bind_int(stmt, 21, point->IsNameShown());
1452 sqlite3_bind_int(stmt, 22, point->IsShared());
1454 sqlite3_bind_int(stmt, 23, iso);
1456 sqlite3_bind_text(stmt, 24, point->
m_GUID.ToStdString().c_str(), -1,
1463 if (sqlite3_step(stmt) != SQLITE_DONE) {
1464 ReportError(
"UpdateDBRoutePointAttributesA:step");
1465 sqlite3_finalize(stmt);
1469 sqlite3_finalize(stmt);
1474 DeleteAllCommentsForRoutePoint(m_db, point->
m_GUID.ToStdString());
1478 if (NbrOfLinks > 0) {
1480 for (
auto it = list->begin(); it != list->end(); ++it) {
1482 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
1483 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
1484 link->DescrText.ToStdString(),
1485 link->Link.ToStdString(),
1486 link->LType.ToStdString());
1489 "UPDATE routepoint_html_links SET "
1491 "html_description = ?, "
1495 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1496 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1498 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1500 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1503 if (sqlite3_step(stmt) != SQLITE_DONE) {
1506 if (sqlite3_step(stmt) != SQLITE_DONE) {
1507 ReportError(
"UpdateDBRoutePointAttributesB:step-h");
1508 sqlite3_finalize(stmt);
1511 sqlite3_finalize(stmt);
1519bool NavObj_dB::UpdateDBRoutePointViz(
RoutePoint* point) {
1521 "UPDATE routepoints SET "
1526 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1527 sqlite3_bind_int(stmt, 1, point->IsVisible());
1528 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
1535 if (sqlite3_step(stmt) != SQLITE_DONE) {
1536 ReportError(
"UpdateDBRoutePointVizA:step");
1537 sqlite3_finalize(stmt);
1541 sqlite3_finalize(stmt);
1546bool NavObj_dB::DeleteRoute(
Route* route) {
1547 if (m_importing)
return false;
1548 if (!route)
return false;
1549 std::string route_guid = route->
m_GUID.ToStdString();
1550 const char* sql =
"DELETE FROM routes WHERE guid = ?";
1553 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1554 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
1555 if (sqlite3_step(stmt) != SQLITE_DONE) {
1556 ReportError(
"DeleteRoute:step");
1557 sqlite3_finalize(stmt);
1560 sqlite3_finalize(stmt);
1567bool NavObj_dB::LoadAllRoutes() {
1577 "planned_departure, "
1584 "ORDER BY created_at ASC";
1587 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1591 int errcode0 = SQLITE_OK;
1592 while ((errcode0 = sqlite3_step(stmt)) == SQLITE_ROW) {
1594 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1596 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1597 std::string description =
1598 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1599 std::string start_string =
1600 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1601 std::string end_string =
1602 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1603 int visibility = sqlite3_column_int(stmt, 5);
1604 int sharewp_viz = sqlite3_column_int(stmt, 6);
1605 time_t planned_departure_ticks = sqlite3_column_int(stmt, 7);
1606 double plan_speed = sqlite3_column_double(stmt, 8);
1607 std::string time_format =
1608 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1610 int width = sqlite3_column_int(stmt, 10);
1611 int style = sqlite3_column_int(stmt, 11);
1613 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 12));
1615 Route* route = NULL;
1618 const char* sql = R
"(
1619 SELECT latitude, longitude, timestamp, point_order
1621 WHERE track_guid = ?
1622 ORDER BY point_order ASC
1638 "p.RangeRingsNumber, "
1639 "p.RangeRingsStep, "
1640 "p.RangeRingsStepUnits, "
1641 "p.RangeRingsVisible, "
1642 "p.RangeRingsColour, "
1651 "FROM routepoints_link tp "
1652 "JOIN routepoints p ON p.guid = tp.point_guid "
1653 "WHERE tp.route_guid = ? "
1654 "ORDER BY tp.point_order ASC";
1656 sqlite3_stmt* stmtp;
1657 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1658 ReportError(
"LoadAllRoutes-B:prepare");
1662 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1665 int errcode = SQLITE_OK;
1666 while ((errcode = sqlite3_step(stmtp)) == SQLITE_ROW) {
1672 route->SetVisible(visibility == 1);
1677 route->SetVisible(visibility == 1);
1678 route->SetSharedWPViz(sharewp_viz == 1);
1684 route->
m_style = (wxPenStyle)style;
1690 std::string point_guid =
1691 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1692 double latitude = sqlite3_column_double(stmtp, col++);
1693 double longitude = sqlite3_column_double(stmtp, col++);
1694 std::string symbol =
1695 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1697 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1698 std::string description =
1699 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1700 std::string tide_station =
1701 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1702 double plan_speed = sqlite3_column_double(stmtp, col++);
1703 time_t etd_epoch = sqlite3_column_int(stmtp, col++);
1705 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1707 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1708 double arrival_radius = sqlite3_column_double(stmtp, col++);
1710 int range_ring_number = sqlite3_column_int(stmtp, col++);
1711 double range_ring_step = sqlite3_column_double(stmtp, col++);
1712 int range_ring_units = sqlite3_column_int(stmtp, col++);
1713 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1714 std::string range_ring_color =
1715 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1717 int scamin = sqlite3_column_int(stmtp, col++);
1718 int scamax = sqlite3_column_int(stmtp, col++);
1719 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1721 int visibility = sqlite3_column_int(stmtp, col++);
1722 int viz_name = sqlite3_column_int(stmtp, col++);
1723 int shared = sqlite3_column_int(stmtp, col++);
1724 int isolated = sqlite3_column_int(stmtp, col++);
1725 std::string point_created_at =
1726 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1731 auto containing_route =
1732 g_pRouteMan->FindRouteContainingWaypoint(point_guid);
1734 if (containing_route) {
1735 existing_point = containing_route->GetPoint(point_guid);
1738 if (!existing_point) {
1739 existing_point = pWayPointMan->FindRoutePointByGUID(point_guid.c_str());
1742 if (existing_point) {
1743 point = existing_point;
1744 point->SetShared(
true);
1748 new RoutePoint(latitude, longitude, symbol, name, point_guid,
true);
1752 point->SetPlannedSpeed(plan_speed);
1755 etd.Set((time_t)etd_epoch);
1756 if (etd.IsValid()) point->
SetETD(etd);
1763 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1767 point->SetScaMin(scamin);
1768 point->SetScaMax(scamax);
1769 point->SetUseSca(use_scaminmax == 1);
1771 point->SetVisible(visibility == 1);
1772 point->SetNameShown(viz_name == 1);
1773 point->SetShared(shared == 1);
1776 if (point_created_at.size()) {
1780 std::istringstream ss(point_created_at);
1781 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
1782 time_t epoch_time = mktime(&tm);
1787 const char* sqlh = R
"(
1788 SELECT guid, html_link, html_description, html_type
1789 FROM routepoint_html_links
1790 WHERE routepoint_guid = ?
1791 ORDER BY html_type ASC
1796 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1797 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
1800 while (sqlite3_step(stmt) == SQLITE_ROW) {
1801 std::string link_guid =
1802 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1803 std::string link_link =
1804 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1805 std::string link_description =
1806 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1807 std::string link_type =
1808 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1811 h->DescrText = link_description;
1812 h->Link = link_link;
1813 h->LType = link_type;
1820 route->AddPoint(point);
1822 sqlite3_finalize(stmtp);
1823 if (errcode != SQLITE_DONE) {
1824 ReportError(
"LoadAllRoutes-A:step");
1831 const char* sqlh = R
"(
1832 SELECT guid, html_link, html_description, html_type
1833 FROM route_html_links
1834 WHERE route_guid = ?
1835 ORDER BY html_type ASC
1840 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1841 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1844 int errcode2 = SQLITE_OK;
1845 while ((errcode2 = sqlite3_step(stmt)) == SQLITE_ROW) {
1846 std::string link_guid =
1847 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1848 std::string link_link =
1849 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1850 std::string link_description =
1851 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1852 std::string link_type =
1853 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1856 h->DescrText = link_description;
1857 h->Link = link_link;
1858 h->LType = link_type;
1862 if (errcode != SQLITE_DONE) {
1863 ReportError(
"LoadAllRoutes-B:step");
1867 sqlite3_finalize(stmt);
1870 ReportError(
"LoadAllRoutes-B:prepare");
1881 if (errcode0 != SQLITE_DONE) {
1882 ReportError(
"LoadAllRoutes-C:step");
1889bool NavObj_dB::LoadAllPoints() {
1904 "p.RangeRingsNumber, "
1905 "p.RangeRingsStep, "
1906 "p.RangeRingsStepUnits, "
1907 "p.RangeRingsVisible, "
1908 "p.RangeRingsColour, "
1917 "FROM routepoints p ";
1921 sqlite3_stmt* stmtp;
1922 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1926 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1929 std::string point_guid =
1930 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1931 double latitude = sqlite3_column_double(stmtp, col++);
1932 double longitude = sqlite3_column_double(stmtp, col++);
1933 std::string symbol =
1934 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1936 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1937 std::string description =
1938 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1939 std::string tide_station =
1940 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1941 double plan_speed = sqlite3_column_double(stmtp, col++);
1942 time_t etd = sqlite3_column_int(stmtp, col++);
1944 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1945 std::string point_time_string =
1946 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1947 double arrival_radius = sqlite3_column_double(stmtp, col++);
1949 int range_ring_number = sqlite3_column_int(stmtp, col++);
1950 double range_ring_step = sqlite3_column_double(stmtp, col++);
1951 int range_ring_units = sqlite3_column_int(stmtp, col++);
1952 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1953 std::string range_ring_color =
1954 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1956 int scamin = sqlite3_column_int(stmtp, col++);
1957 int scamax = sqlite3_column_int(stmtp, col++);
1958 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1960 int visibility = sqlite3_column_int(stmtp, col++);
1961 int viz_name = sqlite3_column_int(stmtp, col++);
1962 int shared = sqlite3_column_int(stmtp, col++);
1963 int isolated = sqlite3_column_int(stmtp, col++);
1964 std::string point_created_at =
1965 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1969 new RoutePoint(latitude, longitude, symbol, name, point_guid,
false);
1973 point->SetPlannedSpeed(plan_speed);
1979 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1983 point->SetScaMin(scamin);
1984 point->SetScaMax(scamax);
1985 point->SetUseSca(use_scaminmax == 1);
1987 point->SetVisible(visibility == 1);
1988 point->SetNameShown(viz_name == 1);
1989 point->SetShared(shared == 1);
1992 if (point_created_at.size()) {
1996 std::istringstream ss(point_created_at);
1997 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
1998 time_t epoch_time = mktime(&tm);
2004 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
2007 sqlite3_finalize(stmtp);
2011 const char* sqlh = R
"(
2012 SELECT guid, html_link, html_description, html_type
2013 FROM routepoint_html_links
2014 WHERE routepoint_guid = ?
2015 ORDER BY html_type ASC
2020 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
2021 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
2024 while (sqlite3_step(stmt) == SQLITE_ROW) {
2025 std::string link_guid =
2026 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
2027 std::string link_link =
2028 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
2029 std::string link_description =
2030 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
2031 std::string link_type =
2032 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
2035 h->DescrText = link_description;
2036 h->Link = link_link;
2037 h->LType = link_type;
2042 sqlite3_finalize(stmt);
2050bool NavObj_dB::InsertRoutePoint(
RoutePoint* point) {
2054 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString())) {
2057 wxString::Format(
"INSERT INTO routepoints (guid) VALUES ('%s')",
2058 point->
m_GUID.ToStdString().c_str());
2059 if (!executeSQL(m_db, sql)) {
2064 UpdateDBRoutePointAttributes(point);
2068 if (NbrOfLinks > 0) {
2070 for (
auto it = list->begin(); it != list->end(); ++it) {
2072 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
2073 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
2074 link->DescrText.ToStdString(),
2075 link->Link.ToStdString(),
2076 link->LType.ToStdString());
2084bool NavObj_dB::DeleteRoutePoint(
RoutePoint* point) {
2085 if (m_importing)
return false;
2086 if (!point)
return false;
2088 std::string point_guid = point->
m_GUID.ToStdString();
2092 const char* sql =
"DELETE FROM routepoints WHERE guid = ?";
2095 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
2096 sqlite3_bind_text(stmt, 1, point_guid.c_str(), -1, SQLITE_TRANSIENT);
2097 if (sqlite3_step(stmt) != SQLITE_DONE) {
2098 ReportError(
"DeleteRoutePoint:step");
2099 sqlite3_finalize(stmt);
2103 sqlite3_finalize(stmt);
2110bool NavObj_dB::UpdateRoutePoint(
RoutePoint* point) {
2111 if (m_importing)
return false;
2112 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString()))
return false;
2113 UpdateDBRoutePointAttributes(point);
2117bool NavObj_dB::Backup(wxString fileName) {
2118 sqlite3_backup* pBackup;
2119 sqlite3* backupDatabase;
2121 if (sqlite3_open(fileName.c_str(), &backupDatabase) == SQLITE_OK) {
2122 pBackup = sqlite3_backup_init(backupDatabase,
"main", m_db,
"main");
2124 int result = sqlite3_backup_step(pBackup, -1);
2125 if ((result == SQLITE_OK) || (result == SQLITE_DONE)) {
2126 if (sqlite3_backup_finish(pBackup) == SQLITE_OK) {
2127 sqlite3_close_v2(backupDatabase);
2133 wxLogMessage(
"navobj database backup error: %s", sqlite3_errmsg(m_db));
The navobj SQLite container object, a singleton.
Represents a waypoint or mark within the navigation system.
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this waypoint.
wxColour m_wxcWaypointRangeRingsColour
Color for the range rings display.
wxString m_MarkDescription
Description text for the waypoint.
int m_iWaypointRangeRingsNumber
Number of range rings to display around the waypoint.
wxString m_GUID
Globally Unique Identifier for the waypoint.
wxDateTime m_CreateTimeX
Creation timestamp for the waypoint, in UTC.
bool m_bIsolatedMark
Flag indicating if the waypoint is a standalone mark.
wxDateTime GetManualETD()
Retrieves the manually set Estimated Time of Departure for this waypoint, in UTC.
wxString m_timestring
String representation of the waypoint creation time.
double GetPlannedSpeed()
Return the planned speed associated with this waypoint.
double m_WaypointArrivalRadius
Arrival radius in nautical miles.
int m_iWaypointRangeRingsStepUnits
Units for the range rings step (0=nm, 1=km).
float m_fWaypointRangeRingsStep
Distance between consecutive range rings.
wxString m_TideStation
Associated tide station identifier.
bool m_bShowWaypointRangeRings
Flag indicating if range rings should be shown around the waypoint.
void SetETD(const wxDateTime &etd)
Sets the Estimated Time of Departure for this waypoint, in UTC.
Represents a navigational route in the navigation system.
double m_PlannedSpeed
Default planned speed for the route in knots.
wxString m_RouteStartString
Name or description of the route's starting point.
wxString m_RouteDescription
Additional descriptive information about the route.
wxString m_Colour
Color name for rendering the route on the chart.
wxString m_RouteEndString
Name or description of the route's ending point.
wxPenStyle m_style
Style of the route line when rendered on the chart.
wxString m_TimeDisplayFormat
Format for displaying times in the UI.
int m_width
Width of the route line in pixels when rendered on the chart.
wxString m_RouteNameString
User-assigned name for the route.
wxString m_GUID
Globally unique identifier for this route.
wxDateTime m_PlannedDeparture
Planned departure time for the route, in UTC.
HyperlinkList * m_HyperlinkList
List of hyperlinks associated with this route.
bool DeleteRoute(Route *pRoute)
Represents a single point in a track.
Represents a track, which is a series of connected track points.
bool AddRoutePoint(RoutePoint *prp)
Add a point to list which owns it.
bool RemoveRoutePoint(RoutePoint *prp)
Remove a routepoint from list if present, deallocate it all cases.
Decoded messages send/receive support.
bool exists(const std::string &name)
MySQL based storage for routes, tracks, etc.
Navigation Utility Functions without GUI dependencies.
User notification container.
User notifications manager.
Routeman * g_pRouteMan
Global instance.
RouteList * pRouteList
Global instance.
Select * pSelect
Global instance.
std::vector< Track * > g_TrackList
Global instance.