32#include "model/base_platform.h"
34#include "model/navutil_base.h"
37#include "wx/filename.h"
38#include "model/comm_appmsg_bus.h"
41extern std::shared_ptr<ObservableListener> ack_listener;
42extern RouteList* pRouteList;
44void ReportError(
const std::string zmsg);
46static bool executeSQL(sqlite3* db,
const char* sql) {
47 char* errMsg =
nullptr;
48 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
50 wxString::Format(_(
"navobj database error.") +
" %s", errMsg);
52 auto& noteman = NotificationManager::GetInstance();
53 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
60static bool executeSQL(sqlite3* db, wxString& sql) {
61 return executeSQL(db, sql.ToStdString().c_str());
64bool CreateTables(sqlite3* db) {
66 const char* create_tables_sql = R
"(
67 CREATE TABLE IF NOT EXISTS tracks (
68 guid TEXT PRIMARY KEY NOT NULL,
77 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
80 CREATE TABLE IF NOT EXISTS trk_points (
81 track_guid TEXT NOT NULL,
82 latitude REAL NOT NULL,
83 longitude REAL NOT NULL,
84 timestamp TEXT NOT NULL,
86 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
90 CREATE TABLE IF NOT EXISTS track_html_links (
91 guid TEXT PRIMARY KEY,
92 track_guid TEXT NOT NULL,
94 html_description TEXT,
96 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
100 CREATE TABLE IF NOT EXISTS routes (
101 guid TEXT PRIMARY KEY NOT NULL,
106 planned_departure TEXT,
113 shared_wp_viz INTEGER,
114 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
118 CREATE TABLE IF NOT EXISTS routepoints (
119 guid TEXT PRIMARY KEY NOT NULL,
131 RangeRingsNumber INTEGER,
133 RangeRingsStepUnits INTEGER,
134 RangeRingsVisible INTEGER,
135 RangeRingsColour TEXT,
143 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
146 CREATE TABLE IF NOT EXISTS routepoints_link (
150 PRIMARY KEY (route_guid, point_order),
151 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
154 CREATE TABLE IF NOT EXISTS route_html_links (
155 guid TEXT PRIMARY KEY,
156 route_guid TEXT NOT NULL,
158 html_description TEXT,
160 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
163 CREATE TABLE IF NOT EXISTS routepoint_html_links (
164 guid TEXT PRIMARY KEY,
165 routepoint_guid TEXT NOT NULL,
167 html_description TEXT,
169 FOREIGN KEY (routepoint_guid) REFERENCES routepoints(guid) ON DELETE CASCADE
174 if (!executeSQL(db, create_tables_sql))
return false;
179bool TrackExists(sqlite3* db,
const std::string& track_guid) {
180 const char* sql =
"SELECT 1 FROM tracks WHERE guid = ? LIMIT 1";
184 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
185 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
187 if (sqlite3_step(stmt) == SQLITE_ROW) {
191 sqlite3_finalize(stmt);
193 ReportError(
"TrackExists:prepare");
199bool TrackHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
200 const char* sql =
"SELECT 1 FROM track_html_links WHERE guid = ? LIMIT 1";
204 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
205 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
207 if (sqlite3_step(stmt) == SQLITE_ROW) {
211 sqlite3_finalize(stmt);
213 ReportError(
"TrackHtmlLinkExists:prepare");
219bool DeleteAllCommentsForTrack(sqlite3* db,
const std::string& track_guid) {
220 const char* sql =
"DELETE FROM track_html_links WHERE track_guid = ?";
223 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
224 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
225 if (sqlite3_step(stmt) != SQLITE_DONE) {
226 ReportError(
"DeleteAllCommentsForTrack:step");
230 sqlite3_finalize(stmt);
232 ReportError(
"DeleteAllCommentsForTrack:prepare");
238bool InsertTrackPoint(sqlite3* db,
const std::string& track_guid,
double lat,
239 double lon,
const std::string& timestamp,
int i_point) {
240 const char* sql = R
"(
241 INSERT INTO trk_points (track_guid, latitude, longitude, timestamp, point_order)
242 VALUES (?, ?, ?, ?, ?)
246 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
247 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
248 sqlite3_bind_double(stmt, 2, lat);
249 sqlite3_bind_double(stmt, 3, lon);
250 sqlite3_bind_text(stmt, 4, timestamp.c_str(), -1, SQLITE_TRANSIENT);
251 sqlite3_bind_int(stmt, 5, i_point);
252 if (sqlite3_step(stmt) != SQLITE_DONE) {
253 ReportError(
"InsertTrackPoint:step");
254 sqlite3_finalize(stmt);
257 sqlite3_finalize(stmt);
264bool InsertTrackHTML(sqlite3* db,
const std::string& track_guid,
265 const std::string& link_guid,
const std::string& descrText,
266 const std::string& link,
const std::string& ltype) {
267 const char* sql = R
"(
268 INSERT INTO track_html_links (guid, track_guid, html_link, html_description, html_type)
269 VALUES (?, ?, ?, ?, ?)
273 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
274 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
275 sqlite3_bind_text(stmt, 2, track_guid.c_str(), -1, SQLITE_TRANSIENT);
276 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
277 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
278 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
279 if (sqlite3_step(stmt) != SQLITE_DONE) {
280 ReportError(
"InsertTrackHTML:step");
281 sqlite3_finalize(stmt);
284 sqlite3_finalize(stmt);
293bool DeleteAllCommentsForRoute(sqlite3* db,
const std::string& route_guid) {
294 const char* sql = R
"(
295 DELETE FROM route_html_links WHERE route_guid = ?
298 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
299 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
300 if (sqlite3_step(stmt) != SQLITE_DONE) {
301 ReportError(
"DeleteAllCommentsForRoute:step");
302 sqlite3_finalize(stmt);
305 sqlite3_finalize(stmt);
312bool RouteHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
313 const char* sql =
"SELECT 1 FROM route_html_links WHERE guid = ? LIMIT 1";
317 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
318 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
320 if (sqlite3_step(stmt) == SQLITE_ROW) {
324 sqlite3_finalize(stmt);
331bool RoutePointHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
333 "SELECT 1 FROM routepoint_html_links WHERE guid = ? LIMIT 1";
337 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
338 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
340 if (sqlite3_step(stmt) == SQLITE_ROW) {
344 sqlite3_finalize(stmt);
351bool RouteExistsDB(sqlite3* db,
const std::string& route_guid) {
352 const char* sql =
"SELECT 1 FROM routes WHERE guid = ? LIMIT 1";
356 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
357 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
359 if (sqlite3_step(stmt) == SQLITE_ROW) {
363 sqlite3_finalize(stmt);
370bool InsertRouteHTML(sqlite3* db,
const std::string& route_guid,
371 const std::string& link_guid,
const std::string& descrText,
372 const std::string& link,
const std::string& ltype) {
373 const char* sql = R
"(
374 INSERT INTO route_html_links (guid, route_guid, html_link, html_description, html_type)
375 VALUES (?, ?, ?, ?, ?)
379 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
380 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
381 sqlite3_bind_text(stmt, 2, route_guid.c_str(), -1, SQLITE_TRANSIENT);
382 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
383 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
384 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
385 if (sqlite3_step(stmt) != SQLITE_DONE) {
386 ReportError(
"InsertRouteHTML:step");
387 sqlite3_finalize(stmt);
390 sqlite3_finalize(stmt);
397bool RoutePointExists(sqlite3* db,
const std::string& routepoint_guid) {
398 const char* sql =
"SELECT 1 FROM routepoints WHERE guid = ? LIMIT 1";
402 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
403 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
405 if (sqlite3_step(stmt) == SQLITE_ROW) {
409 sqlite3_finalize(stmt);
416bool InsertRoutePointHTML(sqlite3* db,
const std::string& point_guid,
417 const std::string& link_guid,
418 const std::string& descrText,
const std::string& link,
419 const std::string& ltype) {
420 const char* sql = R
"(
421 INSERT INTO routepoint_html_links (guid, routepoint_guid, html_link, html_description, html_type)
422 VALUES (?, ?, ?, ?, ?)
426 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
427 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
428 sqlite3_bind_text(stmt, 2, point_guid.c_str(), -1, SQLITE_TRANSIENT);
429 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
430 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
431 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
432 if (sqlite3_step(stmt) != SQLITE_DONE) {
433 ReportError(
"InsertRoutePointHTML:step");
434 sqlite3_finalize(stmt);
437 sqlite3_finalize(stmt);
443bool DeleteAllCommentsForRoutePoint(sqlite3* db,
444 const std::string& routepoint_guid) {
446 "DELETE FROM routepoint_html_links WHERE routepoint_guid = ?";
449 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
450 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
451 if (sqlite3_step(stmt) != SQLITE_DONE) {
452 ReportError(
"DeleteAllCommentsForRoutepoint:step");
456 sqlite3_finalize(stmt);
458 ReportError(
"DeleteAllCommentsForRoutepoint:prepare");
464bool InsertRoutePointDB(sqlite3* db,
RoutePoint* point) {
465 const char* sql = R
"(
466 INSERT or REPLACE INTO routepoints(guid)
471 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
472 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
474 if (sqlite3_step(stmt) != SQLITE_DONE) {
475 ReportError(
"InsertRoutePointDB:step");
476 sqlite3_finalize(stmt);
479 sqlite3_finalize(stmt);
488 const char* sql = R
"(
489 INSERT or IGNORE INTO routepoints_link (route_guid, point_guid, point_order)
495 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
496 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
498 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
500 sqlite3_bind_int(stmt, 3, point_order);
501 if (sqlite3_step(stmt) != SQLITE_DONE) {
502 ReportError(
"InsertTrackPointLink:step");
503 sqlite3_finalize(stmt);
506 sqlite3_finalize(stmt);
513void DeleteOrphanedRoutepoint(sqlite3* db) {
514 const char* sql = R
"(
515 DELETE FROM routepoints
516 WHERE guid NOT IN (SELECT point_guid FROM routepoints_link)
518 char* errMsg =
nullptr;
520 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
525void errorLogCallback(
void* pArg,
int iErrCode,
const char* zMsg) {
527 wxString::Format(_(
"navobj database error.") +
" %d: %s", iErrCode, zMsg);
529 auto& noteman = NotificationManager::GetInstance();
530 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
533void ReportError(
const std::string zmsg) {
535 wxString::Format(_(
"navobj database error.") +
" %s", zmsg.c_str());
537 auto& noteman = NotificationManager::GetInstance();
538 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
546NavObj_dB::NavObj_dB() {
547 m_pImportProgress =
nullptr;
550 int ie = sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback,
nullptr);
554 wxFileName::GetPathSeparator() +
"navobj.db";
555 if (!wxFileExists(db_filename)) {
558 wxFileName::GetPathSeparator() +
"navobj.xml";
559 if (wxFileExists(xml_filename)) {
560 wxCopyFile(xml_filename, xml_filename +
".backup");
564 wxFileName::GetPathSeparator() +
565 "navobj.xml.import_backup";
566 if (!wxFileExists(deep_backup_filename)) {
567 wxCopyFile(xml_filename, deep_backup_filename);
573 int create_result = sqlite3_open_v2(
574 db_filename.ToStdString().c_str(),
576 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
579 if (create_result != SQLITE_OK) {
580 wxLogMessage(
"Cannot create new navobj.db database file");
589 int close_result = sqlite3_close_v2(m_db);
590 if (close_result != SQLITE_OK) {
596 int m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
597 SQLITE_OPEN_READWRITE, NULL);
598 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
602 sqlite3_close_v2(m_db);
604 m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
605 SQLITE_OPEN_READWRITE, NULL);
606 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
612NavObj_dB::~NavObj_dB() { sqlite3_close_v2(m_db); }
614void NavObj_dB::Close() {
615 sqlite3_close_v2(m_db);
619bool NavObj_dB::ImportLegacyNavobj(wxFrame* frame) {
621 wxFileName::GetPathSeparator() +
"navobj.xml";
623 if (::wxFileExists(navobj_filename)) {
625 CountImportNavObjects();
626 m_pImportProgress =
new wxProgressDialog(_(
"Importing Navobj database"),
"",
627 m_nImportObjects, frame);
628 m_import_progesscount = 0;
630 rv = ImportLegacyPoints();
631 rv |= ImportLegacyRoutes();
632 rv |= ImportLegacyTracks();
634 m_pImportProgress->Destroy();
638 if (::wxFileExists(navobj_filename)) ::wxRemoveFile(navobj_filename);
643void NavObj_dB::CountImportNavObjects() {
644 m_nImportObjects = 0;
651 wxFileName::GetPathSeparator() +
"navobj.xml";
653 if (::wxFileExists(navobj_filename) &&
654 input_set->load_file(navobj_filename.ToStdString().c_str()).status ==
655 pugi::xml_parse_status::status_ok) {
656 input_set->LoadAllGPXPointObjects();
657 auto pointlist = pWayPointMan->GetWaypointList();
658 wxRoutePointListNode* prpnode = pointlist->GetFirst();
665 prpnode = prpnode->GetNext();
668 input_set->LoadAllGPXRouteObjects();
669 for (wxRouteListNode* node = pRouteList->GetFirst(); node;
670 node = node->GetNext()) {
671 Route* route_import = node->GetData();
674 m_nImportObjects += route_import->GetnPoints();
677 input_set->LoadAllGPXTrackObjects();
678 m_nImportObjects += g_TrackList.size();
679 m_nimportTracks = g_TrackList.size();
681 for (
Track* track_import : g_TrackList) {
682 m_nImportObjects += track_import->GetnPoints();
688bool NavObj_dB::ImportLegacyTracks() {
689 std::vector<Track*> tracks_added;
692 for (
Track* track_import : g_TrackList) {
693 if (InsertTrack(track_import)) {
694 tracks_added.push_back(track_import);
697 m_import_progesscount += track_import->GetnPoints() + 1;
698 wxString msg = wxString::Format(
"Tracks %d/%d", ntrack, m_nimportTracks);
699 m_pImportProgress->Update(m_import_progesscount, msg);
700 m_pImportProgress->Show();
704 for (
Track* ptrack : tracks_added) {
705 if (ptrack->m_bIsInLayer)
continue;
706 g_pRouteMan->DeleteTrack(ptrack);
712bool NavObj_dB::ImportLegacyRoutes() {
713 std::vector<Route*> routes_added;
716 for (wxRouteListNode* node = pRouteList->GetFirst(); node;
717 node = node->GetNext()) {
718 Route* route_import = node->GetData();
719 if (InsertRoute(route_import)) {
720 routes_added.push_back(route_import);
723 m_import_progesscount += route_import->GetnPoints() + 1;
724 wxString msg = wxString::Format(
"Routes %d/%d", nroute, m_nimportRoutes);
725 m_pImportProgress->Update(m_import_progesscount, msg);
726 m_pImportProgress->Show();
730 for (
Route* route : routes_added) {
736 pWayPointMan->DeleteAllWaypoints(
true);
741bool NavObj_dB::ImportLegacyPoints() {
742 std::vector<RoutePoint*> points_added;
746 if (m_nimportPoints > 1000) nmod = 10;
747 if (m_nimportPoints > 10000) nmod = 100;
749 auto pointlist = pWayPointMan->GetWaypointList();
750 wxRoutePointListNode* prpnode = pointlist->GetFirst();
754 if (InsertRoutePointDB(m_db, point)) {
755 points_added.push_back(point);
758 UpdateDBRoutePointAttributes(point);
759 m_import_progesscount += 1;
760 if ((npoint % nmod) == 0) {
762 wxString::Format(
"Points %d/%d", npoint, m_nimportPoints);
763 m_pImportProgress->Update(m_import_progesscount, msg);
764 m_pImportProgress->Show();
768 prpnode = prpnode->GetNext();
780void NavObj_dB::LoadNavObjects() {
786bool NavObj_dB::InsertTrack(
Track* track) {
787 if (TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
791 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
793 ReportError(
"InsertTrack:BEGIN TRANSACTION");
798 wxString sql = wxString::Format(
"INSERT INTO tracks (guid) VALUES ('%s')",
799 track->m_GUID.ToStdString().c_str());
800 if (!executeSQL(m_db, sql)) {
801 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
805 UpdateDBTrackAttributes(track);
808 for (
int i = 0; i < track->GetnPoints(); i++) {
809 auto point = track->GetPoint(i);
811 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
812 point->m_lon, point->GetTimeString(), i);
816 int NbrOfLinks = track->m_TrackHyperlinkList->GetCount();
817 if (NbrOfLinks > 0) {
818 wxHyperlinkListNode* linknode = track->m_TrackHyperlinkList->GetFirst();
822 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
823 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
824 link->DescrText.ToStdString(), link->Link.ToStdString(),
825 link->LType.ToStdString());
827 linknode = linknode->GetNext();
830 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
832 if (errMsg) rv =
false;
837bool NavObj_dB::UpdateTrack(
Track* track) {
841 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
843 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
845 ReportError(
"UpdateTrack:BEGIN TRANSACTION");
849 UpdateDBTrackAttributes(track);
852 const char* sql =
"DELETE FROM trk_points WHERE track_guid = ?";
854 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
855 sqlite3_bind_text(stmt, 1, track->m_GUID.ToStdString().c_str(), -1,
858 ReportError(
"UpdateTrack:prepare");
859 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
862 if (sqlite3_step(stmt) != SQLITE_DONE) {
863 ReportError(
"UpdateTrack:step");
864 sqlite3_finalize(stmt);
865 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
868 sqlite3_finalize(stmt);
871 for (
int i = 0; i < track->GetnPoints(); i++) {
872 auto point = track->GetPoint(i);
875 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
876 point->m_lon, point->GetTimeString(), i);
880 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
883 if (errMsg) rv =
false;
887bool NavObj_dB::UpdateDBTrackAttributes(
Track* track) {
901 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
902 sqlite3_bind_text(stmt, 1, track->GetName().ToStdString().c_str(), -1,
904 sqlite3_bind_text(stmt, 2, track->m_TrackDescription.ToStdString().c_str(),
905 -1, SQLITE_TRANSIENT);
906 sqlite3_bind_int(stmt, 3, track->m_bVisible);
907 sqlite3_bind_text(stmt, 4, track->m_TrackStartString.ToStdString().c_str(),
908 -1, SQLITE_TRANSIENT);
909 sqlite3_bind_text(stmt, 5, track->m_TrackEndString.ToStdString().c_str(),
910 -1, SQLITE_TRANSIENT);
911 sqlite3_bind_int(stmt, 6, track->m_width);
912 sqlite3_bind_int(stmt, 7,
913 (
int)(track->m_style));
914 sqlite3_bind_text(stmt, 8, track->m_Colour.ToStdString().c_str(), -1,
916 sqlite3_bind_text(stmt, 9, track->m_GUID.c_str(), track->m_GUID.size(),
922 if (sqlite3_step(stmt) != SQLITE_DONE) {
923 ReportError(
"UpdateDBTrackAttributesA:step");
924 sqlite3_finalize(stmt);
928 sqlite3_finalize(stmt);
933 DeleteAllCommentsForTrack(m_db, track->m_GUID.ToStdString());
936 int NbrOfLinks = track->m_TrackHyperlinkList->GetCount();
937 if (NbrOfLinks > 0) {
938 wxHyperlinkListNode* linknode = track->m_TrackHyperlinkList->GetFirst();
942 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
943 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
944 link->DescrText.ToStdString(), link->Link.ToStdString(),
945 link->LType.ToStdString());
948 "UPDATE track_html_links SET "
950 "html_description = ?, "
954 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
955 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
957 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
959 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
962 if (sqlite3_step(stmt) != SQLITE_DONE) {
963 ReportError(
"UpdateDBTRackAttributesB:step");
964 sqlite3_finalize(stmt);
968 sqlite3_finalize(stmt);
971 linknode = linknode->GetNext();
980 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
983 int this_point_index = track->GetnPoints();
986 if (!InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
987 point->m_lon, point->GetTimeString(),
988 this_point_index - 1))
994bool NavObj_dB::LoadAllTracks() {
995 const char* sql = R
"(
997 description, visibility, start_string, end_string,
1001 ORDER BY created_at ASC
1005 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1009 while (sqlite3_step(stmt) == SQLITE_ROW) {
1011 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1013 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1014 std::string description =
1015 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1016 int visibility = sqlite3_column_int(stmt, 3);
1017 std::string start_string =
1018 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1019 std::string end_string =
1020 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 5));
1021 int width = sqlite3_column_int(stmt, 6);
1022 int style = sqlite3_column_int(stmt, 7);
1024 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 8));
1025 std::string created =
1026 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1028 Track* new_trk = NULL;
1031 const char* sql = R
"(
1032 SELECT latitude, longitude, timestamp, point_order
1034 WHERE track_guid = ?
1035 ORDER BY point_order ASC
1038 sqlite3_stmt* stmtp;
1039 if (sqlite3_prepare_v2(m_db, sql, -1, &stmtp,
nullptr) != SQLITE_OK) {
1043 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1046 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1048 new_trk =
new Track;
1049 new_trk->m_GUID = guid;
1052 new_trk->SetVisible(visibility == 1);
1053 new_trk->SetName(name.c_str());
1054 new_trk->m_TrackStartString = start_string.c_str();
1055 new_trk->m_TrackEndString = end_string.c_str();
1056 new_trk->m_width = width;
1057 new_trk->m_style = (wxPenStyle)style;
1058 new_trk->m_Colour = color;
1061 double latitude = sqlite3_column_double(stmtp, 0);
1062 double longitude = sqlite3_column_double(stmtp, 1);
1063 std::string timestamp =
1064 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, 2));
1065 int point_order = sqlite3_column_int(stmtp, 3);
1067 auto point =
new TrackPoint(latitude, longitude, timestamp);
1069 point->m_GPXTrkSegNo = GPXTrkSeg;
1070 new_trk->AddPoint(point);
1072 sqlite3_finalize(stmtp);
1075 new_trk->SetCurrentTrackSeg(GPXTrkSeg);
1078 const char* sqlh = R
"(
1079 SELECT guid, html_link, html_description, html_type
1080 FROM track_html_links
1081 WHERE track_guid = ?
1082 ORDER BY html_type ASC
1087 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1088 sqlite3_bind_text(stmt, 1, new_trk->m_GUID.ToStdString().c_str(), -1,
1091 while (sqlite3_step(stmt) == SQLITE_ROW) {
1092 std::string link_guid =
1093 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1094 std::string link_link =
1095 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1096 std::string link_description =
1097 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1098 std::string link_type =
1099 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1102 h->DescrText = link_description;
1103 h->Link = link_link;
1104 h->LType = link_type;
1106 new_trk->m_TrackHyperlinkList->Append(h);
1110 sqlite3_finalize(stmt);
1117 g_TrackList.push_back(new_trk);
1119 pSelect->AddAllSelectableTrackSegments(new_trk);
1125bool NavObj_dB::DeleteTrack(
Track* track) {
1126 if (!track)
return false;
1127 std::string track_guid = track->m_GUID.ToStdString();
1128 const char* sql =
"DELETE FROM tracks WHERE guid = ?";
1131 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1132 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
1133 if (sqlite3_step(stmt) != SQLITE_DONE) {
1134 ReportError(
"DeleteTrack:step");
1135 sqlite3_finalize(stmt);
1139 sqlite3_finalize(stmt);
1148bool NavObj_dB::InsertRoute(
Route* route) {
1152 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString())) {
1154 wxString sql = wxString::Format(
"INSERT INTO routes (guid) VALUES ('%s')",
1155 route->
m_GUID.ToStdString().c_str());
1156 if (!executeSQL(m_db, sql)) {
1159 UpdateDBRouteAttributes(route);
1162 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1164 ReportError(
"InsertRoute:BEGIN TRANSACTION");
1169 for (
int i = 0; i < route->GetnPoints(); i++) {
1170 auto point = route->GetPoint(i + 1);
1173 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1174 InsertRoutePointDB(m_db, point);
1175 UpdateDBRoutePointAttributes(point);
1181 for (
int i = 0; i < route->GetnPoints(); i++) {
1182 auto point = route->GetPoint(i + 1);
1185 InsertRoutePointLink(m_db, route, point, i + 1);
1191 if (NbrOfLinks > 0) {
1196 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1197 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1198 link->DescrText.ToStdString(), link->Link.ToStdString(),
1199 link->LType.ToStdString());
1201 linknode = linknode->GetNext();
1205 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1208 ReportError(
"InsertRoute:commit");
1214bool NavObj_dB::UpdateRoute(
Route* route) {
1218 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1220 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1222 ReportError(
"UpdateRoute:BEGIN TRANSACTION");
1226 UpdateDBRouteAttributes(route);
1229 for (
int i = 0; i < route->GetnPoints(); i++) {
1230 auto point = route->GetPoint(i + 1);
1233 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1234 InsertRoutePointDB(m_db, point);
1236 UpdateDBRoutePointAttributes(point);
1241 const char* sql =
"DELETE FROM routepoints_link WHERE route_guid = ?";
1243 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1244 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1247 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1250 if (sqlite3_step(stmt) != SQLITE_DONE) {
1251 ReportError(
"UpdateRoute:step");
1252 sqlite3_finalize(stmt);
1253 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1257 sqlite3_finalize(stmt);
1259 for (
int i = 0; i < route->GetnPoints(); i++) {
1260 auto point = route->GetPoint(i + 1);
1262 InsertRoutePointLink(m_db, route, point, i + 1);
1268 if (NbrOfLinks > 0) {
1273 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1274 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1275 link->DescrText.ToStdString(), link->Link.ToStdString(),
1276 link->LType.ToStdString());
1278 linknode = linknode->GetNext();
1281 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
1284 if (errMsg) rv =
false;
1289bool NavObj_dB::UpdateRouteViz(
Route* route) {
1292 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1294 UpdateDBRouteAttributes(route);
1296 for (
int i = 0; i < route->GetnPoints(); i++) {
1297 auto point = route->GetPoint(i + 1);
1300 UpdateDBRoutePointViz(point);
1304 if (errMsg) rv =
false;
1309bool NavObj_dB::UpdateDBRouteAttributes(
Route* route) {
1311 "UPDATE routes SET "
1314 "start_string = ?, "
1317 "shared_wp_viz = ?, "
1318 "planned_departure = ?, "
1327 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1328 sqlite3_bind_text(stmt, 1, route->GetName().ToStdString().c_str(), -1,
1331 -1, SQLITE_TRANSIENT);
1333 -1, SQLITE_TRANSIENT);
1335 -1, SQLITE_TRANSIENT);
1336 sqlite3_bind_int(stmt, 5, route->IsVisible());
1337 sqlite3_bind_int(stmt, 6, route->GetSharedWPViz());
1342 -1, SQLITE_TRANSIENT);
1343 sqlite3_bind_int(stmt, 10, route->
m_width);
1344 sqlite3_bind_int(stmt, 11,
1346 sqlite3_bind_text(stmt, 12, route->
m_Colour.ToStdString().c_str(), -1,
1348 sqlite3_bind_text(stmt, 13, route->
m_GUID.c_str(), route->
m_GUID.size(),
1354 if (sqlite3_step(stmt) != SQLITE_DONE) {
1355 ReportError(
"UpdateDBRouteAttributesA:step");
1356 sqlite3_finalize(stmt);
1360 sqlite3_finalize(stmt);
1365 DeleteAllCommentsForRoute(m_db, route->
m_GUID.ToStdString());
1369 if (NbrOfLinks > 0) {
1374 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1375 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1376 link->DescrText.ToStdString(), link->Link.ToStdString(),
1377 link->LType.ToStdString());
1380 "UPDATE route_html_links SET "
1382 "html_description = ?, "
1386 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1387 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1389 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1391 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1394 if (sqlite3_step(stmt) != SQLITE_DONE) {
1397 if (sqlite3_step(stmt) != SQLITE_DONE) {
1398 ReportError(
"UpdateDBRouteAttributesB:step");
1399 sqlite3_finalize(stmt);
1403 sqlite3_finalize(stmt);
1406 linknode = linknode->GetNext();
1412bool NavObj_dB::UpdateDBRoutePointAttributes(
RoutePoint* point) {
1414 "UPDATE routepoints SET "
1425 "ArrivalRadius = ?, "
1426 "RangeRingsNumber = ?, "
1427 "RangeRingsStep = ?, "
1428 "RangeRingsStepUnits = ?, "
1429 "RangeRingsVisible = ?, "
1430 "RangeRingsColour = ?, "
1441 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1442 sqlite3_bind_double(stmt, 1, point->GetLatitude());
1443 sqlite3_bind_double(stmt, 2, point->GetLongitude());
1444 sqlite3_bind_text(stmt, 3, point->GetIconName().ToStdString().c_str(), -1,
1446 sqlite3_bind_text(stmt, 4, point->GetName().ToStdString().c_str(), -1,
1448 sqlite3_bind_text(stmt, 5, point->GetDescription().ToStdString().c_str(),
1449 -1, SQLITE_TRANSIENT);
1450 sqlite3_bind_text(stmt, 6, point->
m_TideStation.ToStdString().c_str(), -1,
1455 sqlite3_bind_int(stmt, 8, etd);
1456 sqlite3_bind_text(stmt, 9,
"type", -1, SQLITE_TRANSIENT);
1457 std::string timit = point->
m_timestring.ToStdString().c_str();
1458 sqlite3_bind_text(stmt, 10, point->
m_timestring.ToStdString().c_str(), -1,
1471 -1, SQLITE_TRANSIENT);
1473 sqlite3_bind_int(stmt, 17, point->GetScaMin());
1474 sqlite3_bind_int(stmt, 18, point->GetScaMax());
1475 sqlite3_bind_int(stmt, 19, point->GetUseSca());
1477 sqlite3_bind_int(stmt, 20, point->IsVisible());
1478 sqlite3_bind_int(stmt, 21, point->IsNameShown());
1479 sqlite3_bind_int(stmt, 22, point->IsShared());
1481 sqlite3_bind_int(stmt, 23, iso);
1483 sqlite3_bind_text(stmt, 24, point->
m_GUID.ToStdString().c_str(), -1,
1490 if (sqlite3_step(stmt) != SQLITE_DONE) {
1491 ReportError(
"UpdateDBRoutePointAttributesA:step");
1492 sqlite3_finalize(stmt);
1496 sqlite3_finalize(stmt);
1501 DeleteAllCommentsForRoutePoint(m_db, point->
m_GUID.ToStdString());
1505 if (NbrOfLinks > 0) {
1510 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
1511 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
1512 link->DescrText.ToStdString(),
1513 link->Link.ToStdString(),
1514 link->LType.ToStdString());
1517 "UPDATE routepoint_html_links SET "
1519 "html_description = ?, "
1523 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1524 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1526 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1528 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1531 if (sqlite3_step(stmt) != SQLITE_DONE) {
1534 if (sqlite3_step(stmt) != SQLITE_DONE) {
1535 ReportError(
"UpdateDBRoutePointAttributesB:step-h");
1536 sqlite3_finalize(stmt);
1540 sqlite3_finalize(stmt);
1543 linknode = linknode->GetNext();
1550bool NavObj_dB::UpdateDBRoutePointViz(
RoutePoint* point) {
1552 "UPDATE routepoints SET "
1557 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1558 sqlite3_bind_int(stmt, 1, point->IsVisible());
1559 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
1566 if (sqlite3_step(stmt) != SQLITE_DONE) {
1567 ReportError(
"UpdateDBRoutePointVizA:step");
1568 sqlite3_finalize(stmt);
1572 sqlite3_finalize(stmt);
1577bool NavObj_dB::DeleteRoute(
Route* route) {
1578 if (m_importing)
return false;
1579 if (!route)
return false;
1580 std::string route_guid = route->
m_GUID.ToStdString();
1581 const char* sql =
"DELETE FROM routes WHERE guid = ?";
1584 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1585 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
1586 if (sqlite3_step(stmt) != SQLITE_DONE) {
1587 ReportError(
"DeleteRoute:step");
1588 sqlite3_finalize(stmt);
1591 sqlite3_finalize(stmt);
1598bool NavObj_dB::LoadAllRoutes() {
1608 "planned_departure, "
1615 "ORDER BY created_at ASC";
1618 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1622 int errcode0 = SQLITE_OK;
1623 while ((errcode0 = sqlite3_step(stmt)) == SQLITE_ROW) {
1625 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1627 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1628 std::string description =
1629 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1630 std::string start_string =
1631 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1632 std::string end_string =
1633 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1634 int visibility = sqlite3_column_int(stmt, 5);
1635 int sharewp_viz = sqlite3_column_int(stmt, 6);
1636 time_t planned_departure_ticks = sqlite3_column_int(stmt, 7);
1637 double plan_speed = sqlite3_column_double(stmt, 8);
1638 std::string time_format =
1639 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1641 int width = sqlite3_column_int(stmt, 10);
1642 int style = sqlite3_column_int(stmt, 11);
1644 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 12));
1646 Route* route = NULL;
1649 const char* sql = R
"(
1650 SELECT latitude, longitude, timestamp, point_order
1652 WHERE track_guid = ?
1653 ORDER BY point_order ASC
1669 "p.RangeRingsNumber, "
1670 "p.RangeRingsStep, "
1671 "p.RangeRingsStepUnits, "
1672 "p.RangeRingsVisible, "
1673 "p.RangeRingsColour, "
1682 "FROM routepoints_link tp "
1683 "JOIN routepoints p ON p.guid = tp.point_guid "
1684 "WHERE tp.route_guid = ? "
1685 "ORDER BY tp.point_order ASC";
1687 sqlite3_stmt* stmtp;
1688 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1689 ReportError(
"LoadAllRoutes-B:prepare");
1693 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1696 int errcode = SQLITE_OK;
1697 while ((errcode = sqlite3_step(stmtp)) == SQLITE_ROW) {
1703 route->SetVisible(visibility == 1);
1708 route->SetVisible(visibility == 1);
1709 route->SetSharedWPViz(sharewp_viz == 1);
1715 route->
m_style = (wxPenStyle)style;
1721 std::string point_guid =
1722 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1723 double latitude = sqlite3_column_double(stmtp, col++);
1724 double longitude = sqlite3_column_double(stmtp, col++);
1725 std::string symbol =
1726 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1728 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1729 std::string description =
1730 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1731 std::string tide_station =
1732 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1733 double plan_speed = sqlite3_column_double(stmtp, col++);
1734 time_t etd_epoch = sqlite3_column_int(stmtp, col++);
1736 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1738 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1739 double arrival_radius = sqlite3_column_double(stmtp, col++);
1741 int range_ring_number = sqlite3_column_int(stmtp, col++);
1742 double range_ring_step = sqlite3_column_double(stmtp, col++);
1743 int range_ring_units = sqlite3_column_int(stmtp, col++);
1744 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1745 std::string range_ring_color =
1746 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1748 int scamin = sqlite3_column_int(stmtp, col++);
1749 int scamax = sqlite3_column_int(stmtp, col++);
1750 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1752 int visibility = sqlite3_column_int(stmtp, col++);
1753 int viz_name = sqlite3_column_int(stmtp, col++);
1754 int shared = sqlite3_column_int(stmtp, col++);
1755 int isolated = sqlite3_column_int(stmtp, col++);
1756 std::string point_created_at =
1757 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1761 auto containing_route =
1762 g_pRouteMan->FindRouteContainingWaypoint(point_guid);
1764 if (containing_route) {
1765 point = containing_route->GetPoint(point_guid);
1768 new RoutePoint(latitude, longitude, symbol, name, point_guid,
true);
1772 point->SetPlannedSpeed(plan_speed);
1775 etd.Set((time_t)etd_epoch);
1776 if (etd.IsValid()) point->
SetETD(etd);
1783 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1787 point->SetScaMin(scamin);
1788 point->SetScaMax(scamax);
1789 point->SetUseSca(use_scaminmax == 1);
1791 point->SetVisible(visibility == 1);
1792 point->SetNameShown(viz_name == 1);
1793 point->SetShared(shared == 1);
1796 if (point_created_at.size()) {
1800 std::istringstream ss(point_created_at);
1801 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
1802 time_t epoch_time = mktime(&tm);
1807 const char* sqlh = R
"(
1808 SELECT guid, html_link, html_description, html_type
1809 FROM routepoint_html_links
1810 WHERE routepoint_guid = ?
1811 ORDER BY html_type ASC
1816 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1817 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
1820 while (sqlite3_step(stmt) == SQLITE_ROW) {
1821 std::string link_guid =
1822 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1823 std::string link_link =
1824 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1825 std::string link_description =
1826 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1827 std::string link_type =
1828 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1831 h->DescrText = link_description;
1832 h->Link = link_link;
1833 h->LType = link_type;
1840 route->AddPoint(point);
1842 sqlite3_finalize(stmtp);
1843 if (errcode != SQLITE_DONE) {
1844 ReportError(
"LoadAllRoutes-A:step");
1851 const char* sqlh = R
"(
1852 SELECT guid, html_link, html_description, html_type
1853 FROM route_html_links
1854 WHERE route_guid = ?
1855 ORDER BY html_type ASC
1860 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1861 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1864 int errcode2 = SQLITE_OK;
1865 while ((errcode2 = sqlite3_step(stmt)) == SQLITE_ROW) {
1866 std::string link_guid =
1867 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1868 std::string link_link =
1869 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1870 std::string link_description =
1871 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1872 std::string link_type =
1873 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1876 h->DescrText = link_description;
1877 h->Link = link_link;
1878 h->LType = link_type;
1882 if (errcode != SQLITE_DONE) {
1883 ReportError(
"LoadAllRoutes-B:step");
1887 sqlite3_finalize(stmt);
1890 ReportError(
"LoadAllRoutes-B:prepare");
1901 if (errcode0 != SQLITE_DONE) {
1902 ReportError(
"LoadAllRoutes-C:step");
1909bool NavObj_dB::LoadAllPoints() {
1924 "p.RangeRingsNumber, "
1925 "p.RangeRingsStep, "
1926 "p.RangeRingsStepUnits, "
1927 "p.RangeRingsVisible, "
1928 "p.RangeRingsColour, "
1937 "FROM routepoints p ";
1941 sqlite3_stmt* stmtp;
1942 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1946 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1949 std::string point_guid =
1950 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1951 double latitude = sqlite3_column_double(stmtp, col++);
1952 double longitude = sqlite3_column_double(stmtp, col++);
1953 std::string symbol =
1954 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1956 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1957 std::string description =
1958 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1959 std::string tide_station =
1960 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1961 double plan_speed = sqlite3_column_double(stmtp, col++);
1962 time_t etd = sqlite3_column_int(stmtp, col++);
1964 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1965 std::string point_time_string =
1966 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1967 double arrival_radius = sqlite3_column_double(stmtp, col++);
1969 int range_ring_number = sqlite3_column_int(stmtp, col++);
1970 double range_ring_step = sqlite3_column_double(stmtp, col++);
1971 int range_ring_units = sqlite3_column_int(stmtp, col++);
1972 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1973 std::string range_ring_color =
1974 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1976 int scamin = sqlite3_column_int(stmtp, col++);
1977 int scamax = sqlite3_column_int(stmtp, col++);
1978 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1980 int visibility = sqlite3_column_int(stmtp, col++);
1981 int viz_name = sqlite3_column_int(stmtp, col++);
1982 int shared = sqlite3_column_int(stmtp, col++);
1983 int isolated = sqlite3_column_int(stmtp, col++);
1984 std::string point_created_at =
1985 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1989 new RoutePoint(latitude, longitude, symbol, name, point_guid,
false);
1993 point->SetPlannedSpeed(plan_speed);
1999 point->SetShowWaypointRangeRings(range_ring_visible == 1);
2003 point->SetScaMin(scamin);
2004 point->SetScaMax(scamax);
2005 point->SetUseSca(use_scaminmax == 1);
2007 point->SetVisible(visibility == 1);
2008 point->SetNameShown(viz_name == 1);
2009 point->SetShared(shared == 1);
2012 if (point_created_at.size()) {
2016 std::istringstream ss(point_created_at);
2017 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
2018 time_t epoch_time = mktime(&tm);
2024 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
2027 sqlite3_finalize(stmtp);
2031 const char* sqlh = R
"(
2032 SELECT guid, html_link, html_description, html_type
2033 FROM routepoint_html_links
2034 WHERE routepoint_guid = ?
2035 ORDER BY html_type ASC
2040 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
2041 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
2044 while (sqlite3_step(stmt) == SQLITE_ROW) {
2045 std::string link_guid =
2046 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
2047 std::string link_link =
2048 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
2049 std::string link_description =
2050 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
2051 std::string link_type =
2052 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
2055 h->DescrText = link_description;
2056 h->Link = link_link;
2057 h->LType = link_type;
2062 sqlite3_finalize(stmt);
2070bool NavObj_dB::InsertRoutePoint(
RoutePoint* point) {
2074 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString())) {
2077 wxString::Format(
"INSERT INTO routepoints (guid) VALUES ('%s')",
2078 point->
m_GUID.ToStdString().c_str());
2079 if (!executeSQL(m_db, sql)) {
2084 UpdateDBRoutePointAttributes(point);
2088 if (NbrOfLinks > 0) {
2093 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
2094 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
2095 link->DescrText.ToStdString(),
2096 link->Link.ToStdString(),
2097 link->LType.ToStdString());
2099 linknode = linknode->GetNext();
2106bool NavObj_dB::DeleteRoutePoint(
RoutePoint* point) {
2107 if (m_importing)
return false;
2108 if (!point)
return false;
2110 std::string point_guid = point->
m_GUID.ToStdString();
2114 const char* sql =
"DELETE FROM routepoints WHERE guid = ?";
2117 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
2118 sqlite3_bind_text(stmt, 1, point_guid.c_str(), -1, SQLITE_TRANSIENT);
2119 if (sqlite3_step(stmt) != SQLITE_DONE) {
2120 ReportError(
"DeleteRoutePoint:step");
2121 sqlite3_finalize(stmt);
2125 sqlite3_finalize(stmt);
2132bool NavObj_dB::UpdateRoutePoint(
RoutePoint* point) {
2133 if (m_importing)
return false;
2134 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString()))
return false;
2135 UpdateDBRoutePointAttributes(point);
2139bool NavObj_dB::Backup(wxString fileName) {
2140 sqlite3_backup* pBackup;
2141 sqlite3* backupDatabase;
2143 if (sqlite3_open(fileName.c_str(), &backupDatabase) == SQLITE_OK) {
2144 pBackup = sqlite3_backup_init(backupDatabase,
"main", m_db,
"main");
2146 int result = sqlite3_backup_step(pBackup, -1);
2147 if ((result == SQLITE_OK) || (result == SQLITE_DONE)) {
2148 if (sqlite3_backup_finish(pBackup) == SQLITE_OK) {
2149 sqlite3_close_v2(backupDatabase);
2155 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.
bool exists(const std::string &name)
Class NotificationManager.