31#include <wx/filename.h>
42static void ReportError(
const std::string zmsg);
44static bool executeSQL(sqlite3* db,
const char* sql) {
45 char* errMsg =
nullptr;
46 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
48 wxString::Format(_(
"navobj database error.") +
" %s", errMsg);
50 auto& noteman = NotificationManager::GetInstance();
51 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
58static bool executeSQL(sqlite3* db, wxString& sql) {
59 return executeSQL(db, sql.ToStdString().c_str());
62bool CreateTables(sqlite3* db) {
64 const char* create_tables_sql = R
"(
65 CREATE TABLE IF NOT EXISTS tracks (
66 guid TEXT PRIMARY KEY NOT NULL,
75 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
78 CREATE TABLE IF NOT EXISTS trk_points (
79 track_guid TEXT NOT NULL,
80 latitude REAL NOT NULL,
81 longitude REAL NOT NULL,
82 timestamp TEXT NOT NULL,
84 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
88 CREATE TABLE IF NOT EXISTS track_html_links (
89 guid TEXT PRIMARY KEY,
90 track_guid TEXT NOT NULL,
92 html_description TEXT,
94 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
98 CREATE TABLE IF NOT EXISTS routes (
99 guid TEXT PRIMARY KEY NOT NULL,
104 planned_departure TEXT,
111 shared_wp_viz INTEGER,
112 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
116 CREATE TABLE IF NOT EXISTS routepoints (
117 guid TEXT PRIMARY KEY NOT NULL,
129 RangeRingsNumber INTEGER,
131 RangeRingsStepUnits INTEGER,
132 RangeRingsVisible INTEGER,
133 RangeRingsColour TEXT,
141 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
144 CREATE TABLE IF NOT EXISTS routepoints_link (
148 PRIMARY KEY (route_guid, point_order),
149 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
152 CREATE TABLE IF NOT EXISTS route_html_links (
153 guid TEXT PRIMARY KEY,
154 route_guid TEXT NOT NULL,
156 html_description TEXT,
158 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
161 CREATE TABLE IF NOT EXISTS routepoint_html_links (
162 guid TEXT PRIMARY KEY,
163 routepoint_guid TEXT NOT NULL,
165 html_description TEXT,
167 FOREIGN KEY (routepoint_guid) REFERENCES routepoints(guid) ON DELETE CASCADE
170 CREATE INDEX IF NOT EXISTS idx_track_points
171 ON trk_points (track_guid);
175 if (!executeSQL(db, create_tables_sql))
return false;
180bool TrackExists(sqlite3* db,
const std::string& track_guid) {
181 const char* sql =
"SELECT 1 FROM tracks WHERE guid = ? LIMIT 1";
185 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
186 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
188 if (sqlite3_step(stmt) == SQLITE_ROW) {
192 sqlite3_finalize(stmt);
194 ReportError(
"TrackExists:prepare");
200bool TrackHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
201 const char* sql =
"SELECT 1 FROM track_html_links WHERE guid = ? LIMIT 1";
205 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
206 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
208 if (sqlite3_step(stmt) == SQLITE_ROW) {
212 sqlite3_finalize(stmt);
214 ReportError(
"TrackHtmlLinkExists:prepare");
220bool DeleteAllCommentsForTrack(sqlite3* db,
const std::string& track_guid) {
221 const char* sql =
"DELETE FROM track_html_links WHERE track_guid = ?";
224 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
225 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
226 if (sqlite3_step(stmt) != SQLITE_DONE) {
227 ReportError(
"DeleteAllCommentsForTrack:step");
231 sqlite3_finalize(stmt);
233 ReportError(
"DeleteAllCommentsForTrack:prepare");
239bool InsertTrackPoint(sqlite3* db,
const std::string& track_guid,
double lat,
240 double lon,
const std::string& timestamp,
int i_point) {
241 const char* sql = R
"(
242 INSERT INTO trk_points (track_guid, latitude, longitude, timestamp, point_order)
243 VALUES (?, ?, ?, ?, ?)
247 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
248 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
249 sqlite3_bind_double(stmt, 2, lat);
250 sqlite3_bind_double(stmt, 3, lon);
251 sqlite3_bind_text(stmt, 4, timestamp.c_str(), -1, SQLITE_TRANSIENT);
252 sqlite3_bind_int(stmt, 5, i_point);
253 if (sqlite3_step(stmt) != SQLITE_DONE) {
254 ReportError(
"InsertTrackPoint:step");
255 sqlite3_finalize(stmt);
258 sqlite3_finalize(stmt);
265bool InsertTrackHTML(sqlite3* db,
const std::string& track_guid,
266 const std::string& link_guid,
const std::string& descrText,
267 const std::string& link,
const std::string& ltype) {
268 const char* sql = R
"(
269 INSERT INTO track_html_links (guid, track_guid, html_link, html_description, html_type)
270 VALUES (?, ?, ?, ?, ?)
274 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
275 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
276 sqlite3_bind_text(stmt, 2, track_guid.c_str(), -1, SQLITE_TRANSIENT);
277 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
278 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
279 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
280 if (sqlite3_step(stmt) != SQLITE_DONE) {
281 ReportError(
"InsertTrackHTML:step");
282 sqlite3_finalize(stmt);
285 sqlite3_finalize(stmt);
294bool DeleteAllCommentsForRoute(sqlite3* db,
const std::string& route_guid) {
295 const char* sql = R
"(
296 DELETE FROM route_html_links WHERE route_guid = ?
299 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
300 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
301 if (sqlite3_step(stmt) != SQLITE_DONE) {
302 ReportError(
"DeleteAllCommentsForRoute:step");
303 sqlite3_finalize(stmt);
306 sqlite3_finalize(stmt);
313bool RouteHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
314 const char* sql =
"SELECT 1 FROM route_html_links WHERE guid = ? LIMIT 1";
318 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
319 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
321 if (sqlite3_step(stmt) == SQLITE_ROW) {
325 sqlite3_finalize(stmt);
332bool RoutePointHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
334 "SELECT 1 FROM routepoint_html_links WHERE guid = ? LIMIT 1";
338 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
339 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
341 if (sqlite3_step(stmt) == SQLITE_ROW) {
345 sqlite3_finalize(stmt);
352bool RouteExistsDB(sqlite3* db,
const std::string& route_guid) {
353 const char* sql =
"SELECT 1 FROM routes WHERE guid = ? LIMIT 1";
357 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
358 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
360 if (sqlite3_step(stmt) == SQLITE_ROW) {
364 sqlite3_finalize(stmt);
371bool InsertRouteHTML(sqlite3* db,
const std::string& route_guid,
372 const std::string& link_guid,
const std::string& descrText,
373 const std::string& link,
const std::string& ltype) {
374 const char* sql = R
"(
375 INSERT INTO route_html_links (guid, route_guid, html_link, html_description, html_type)
376 VALUES (?, ?, ?, ?, ?)
380 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
381 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
382 sqlite3_bind_text(stmt, 2, route_guid.c_str(), -1, SQLITE_TRANSIENT);
383 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
384 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
385 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
386 if (sqlite3_step(stmt) != SQLITE_DONE) {
387 ReportError(
"InsertRouteHTML:step");
388 sqlite3_finalize(stmt);
391 sqlite3_finalize(stmt);
398bool RoutePointExists(sqlite3* db,
const std::string& routepoint_guid) {
399 const char* sql =
"SELECT 1 FROM routepoints WHERE guid = ? LIMIT 1";
403 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
404 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
406 if (sqlite3_step(stmt) == SQLITE_ROW) {
410 sqlite3_finalize(stmt);
417bool InsertRoutePointHTML(sqlite3* db,
const std::string& point_guid,
418 const std::string& link_guid,
419 const std::string& descrText,
const std::string& link,
420 const std::string& ltype) {
421 const char* sql = R
"(
422 INSERT INTO routepoint_html_links (guid, routepoint_guid, html_link, html_description, html_type)
423 VALUES (?, ?, ?, ?, ?)
427 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
428 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
429 sqlite3_bind_text(stmt, 2, point_guid.c_str(), -1, SQLITE_TRANSIENT);
430 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
431 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
432 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
433 if (sqlite3_step(stmt) != SQLITE_DONE) {
434 ReportError(
"InsertRoutePointHTML:step");
435 sqlite3_finalize(stmt);
438 sqlite3_finalize(stmt);
444bool DeleteAllCommentsForRoutePoint(sqlite3* db,
445 const std::string& routepoint_guid) {
447 "DELETE FROM routepoint_html_links WHERE routepoint_guid = ?";
450 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
451 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
452 if (sqlite3_step(stmt) != SQLITE_DONE) {
453 ReportError(
"DeleteAllCommentsForRoutepoint:step");
457 sqlite3_finalize(stmt);
459 ReportError(
"DeleteAllCommentsForRoutepoint:prepare");
465bool InsertRoutePointDB(sqlite3* db,
RoutePoint* point) {
466 const char* sql = R
"(
467 INSERT or REPLACE INTO routepoints(guid)
472 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
473 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
475 if (sqlite3_step(stmt) != SQLITE_DONE) {
476 ReportError(
"InsertRoutePointDB:step");
477 sqlite3_finalize(stmt);
480 sqlite3_finalize(stmt);
489 const char* sql = R
"(
490 INSERT or IGNORE INTO routepoints_link (route_guid, point_guid, point_order)
496 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
497 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
499 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
501 sqlite3_bind_int(stmt, 3, point_order);
502 if (sqlite3_step(stmt) != SQLITE_DONE) {
503 ReportError(
"InsertTrackPointLink:step");
504 sqlite3_finalize(stmt);
507 sqlite3_finalize(stmt);
514void DeleteOrphanedRoutepoint(sqlite3* db) {
515 const char* sql = R
"(
516 DELETE FROM routepoints
517 WHERE guid NOT IN (SELECT point_guid FROM routepoints_link)
519 char* errMsg =
nullptr;
521 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
526void errorLogCallback(
void* pArg,
int iErrCode,
const char* zMsg) {
528 wxString::Format(_(
"navobj database error.") +
" %d: %s", iErrCode, zMsg);
530 auto& noteman = NotificationManager::GetInstance();
531 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
534static void ReportError(
const std::string zmsg) {
536 wxString::Format(_(
"navobj database error.") +
" %s", zmsg.c_str());
538 auto& noteman = NotificationManager::GetInstance();
539 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
547NavObj_dB::NavObj_dB() {
548 m_pImportProgress =
nullptr;
551 int ie = sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback,
nullptr);
555 wxFileName::GetPathSeparator() +
"navobj.db";
556 if (!wxFileExists(db_filename)) {
559 wxFileName::GetPathSeparator() +
"navobj.xml";
560 if (wxFileExists(xml_filename)) {
561 wxCopyFile(xml_filename, xml_filename +
".backup");
565 wxFileName::GetPathSeparator() +
566 "navobj.xml.import_backup";
567 if (!wxFileExists(deep_backup_filename)) {
568 wxCopyFile(xml_filename, deep_backup_filename);
574 int create_result = sqlite3_open_v2(
575 db_filename.ToStdString().c_str(),
577 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
580 if (create_result != SQLITE_OK) {
581 wxLogMessage(
"Cannot create new navobj.db database file");
590 int close_result = sqlite3_close_v2(m_db);
591 if (close_result != SQLITE_OK) {
597 int m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
598 SQLITE_OPEN_READWRITE, NULL);
599 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
603 sqlite3_close_v2(m_db);
605 m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
606 SQLITE_OPEN_READWRITE, NULL);
607 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
613NavObj_dB::~NavObj_dB() { sqlite3_close_v2(m_db); }
615void NavObj_dB::Close() {
616 sqlite3_close_v2(m_db);
620bool NavObj_dB::FullSchemaMigrate(wxFrame* frame) {
622 if (needsMigration_0_1(m_db)) {
623 std::string rs = SchemaUpdate_0_1(m_db, frame);
625 wxLogMessage(
"Error on: Schema update and migration 0->1");
626 wxLogMessage(wxString(rs.c_str()));
629 wxLogMessage(
"Schema update and migration 0->1 successful");
635 }
catch (
const std::runtime_error& e) {
637 wxLogMessage(
"Error on: Schema update and migration 0->1, setUserVersion");
638 wxLogMessage(wxString(std::string(e.what())).c_str());
647bool NavObj_dB::ImportLegacyNavobj(wxFrame* frame) {
649 wxFileName::GetPathSeparator() +
"navobj.xml";
651 if (::wxFileExists(navobj_filename)) {
653 CountImportNavObjects();
654 m_pImportProgress =
new wxProgressDialog(_(
"Importing Navobj database"),
"",
655 m_nImportObjects, frame);
656 m_import_progesscount = 0;
658 rv = ImportLegacyPoints();
659 rv |= ImportLegacyRoutes();
660 rv |= ImportLegacyTracks();
662 m_pImportProgress->Destroy();
666 if (::wxFileExists(navobj_filename)) ::wxRemoveFile(navobj_filename);
671void NavObj_dB::CountImportNavObjects() {
672 m_nImportObjects = 0;
679 wxFileName::GetPathSeparator() +
"navobj.xml";
681 if (::wxFileExists(navobj_filename) &&
682 input_set->load_file(navobj_filename.ToStdString().c_str()).status ==
683 pugi::xml_parse_status::status_ok) {
684 input_set->LoadAllGPXPointObjects();
685 auto pointlist = pWayPointMan->GetWaypointList();
693 input_set->LoadAllGPXRouteObjects();
697 m_nImportObjects += route_import->GetnPoints();
700 input_set->LoadAllGPXTrackObjects();
705 m_nImportObjects += track_import->GetnPoints();
711bool NavObj_dB::ImportLegacyTracks() {
712 std::vector<Track*> tracks_added;
716 if (InsertTrack(track_import)) {
717 tracks_added.push_back(track_import);
720 m_import_progesscount += track_import->GetnPoints() + 1;
721 wxString msg = wxString::Format(
"Tracks %d/%d", ntrack, m_nimportTracks);
722 m_pImportProgress->Update(m_import_progesscount, msg);
723 m_pImportProgress->Show();
727 for (
Track* ptrack : tracks_added) {
728 if (ptrack->m_bIsInLayer)
continue;
735bool NavObj_dB::ImportLegacyRoutes() {
736 std::vector<Route*> routes_added;
740 if (InsertRoute(route_import)) {
741 routes_added.push_back(route_import);
744 m_import_progesscount += route_import->GetnPoints() + 1;
745 wxString msg = wxString::Format(
"Routes %d/%d", nroute, m_nimportRoutes);
746 m_pImportProgress->Update(m_import_progesscount, msg);
747 m_pImportProgress->Show();
751 for (
Route* route : routes_added) {
757 pWayPointMan->DeleteAllWaypoints(
true);
762bool NavObj_dB::ImportLegacyPoints() {
763 std::vector<RoutePoint*> points_added;
767 if (m_nimportPoints > 1000) nmod = 10;
768 if (m_nimportPoints > 10000) nmod = 100;
770 for (
RoutePoint* point : *pWayPointMan->GetWaypointList()) {
772 if (InsertRoutePointDB(m_db, point)) {
773 points_added.push_back(point);
776 UpdateDBRoutePointAttributes(point);
777 m_import_progesscount += 1;
778 if ((npoint % nmod) == 0) {
780 wxString::Format(
"Points %d/%d", npoint, m_nimportPoints);
781 m_pImportProgress->Update(m_import_progesscount, msg);
782 m_pImportProgress->Show();
797void NavObj_dB::LoadNavObjects() {
803bool NavObj_dB::InsertTrack(
Track* track) {
804 if (TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
808 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
810 ReportError(
"InsertTrack:BEGIN TRANSACTION");
815 wxString sql = wxString::Format(
"INSERT INTO tracks (guid) VALUES ('%s')",
816 track->m_GUID.ToStdString().c_str());
817 if (!executeSQL(m_db, sql)) {
818 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
822 UpdateDBTrackAttributes(track);
825 for (
int i = 0; i < track->GetnPoints(); i++) {
826 auto point = track->GetPoint(i);
828 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
829 point->m_lon, point->GetTimeString(), i);
833 int NbrOfLinks = track->m_TrackHyperlinkList->size();
834 if (NbrOfLinks > 0) {
835 auto& list = track->m_TrackHyperlinkList;
836 for (
auto it = list->begin(); it != list->end(); ++it) {
838 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
839 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
840 link->DescrText.ToStdString(), link->Link.ToStdString(),
841 link->LType.ToStdString());
845 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
847 if (errMsg) rv =
false;
852bool NavObj_dB::UpdateTrack(
Track* track) {
856 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
858 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
860 ReportError(
"UpdateTrack:BEGIN TRANSACTION");
864 UpdateDBTrackAttributes(track);
867 const char* sql =
"DELETE FROM trk_points WHERE track_guid = ?";
869 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
870 sqlite3_bind_text(stmt, 1, track->m_GUID.ToStdString().c_str(), -1,
873 ReportError(
"UpdateTrack:prepare");
874 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
877 if (sqlite3_step(stmt) != SQLITE_DONE) {
878 ReportError(
"UpdateTrack:step");
879 sqlite3_finalize(stmt);
880 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
883 sqlite3_finalize(stmt);
886 for (
int i = 0; i < track->GetnPoints(); i++) {
887 auto point = track->GetPoint(i);
890 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
891 point->m_lon, point->GetTimeString(), i);
895 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
898 if (errMsg) rv =
false;
902bool NavObj_dB::UpdateDBTrackAttributes(
Track* track) {
916 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
917 sqlite3_bind_text(stmt, 1, track->GetName().ToStdString().c_str(), -1,
919 sqlite3_bind_text(stmt, 2, track->m_TrackDescription.ToStdString().c_str(),
920 -1, SQLITE_TRANSIENT);
921 sqlite3_bind_int(stmt, 3, track->m_bVisible);
922 sqlite3_bind_text(stmt, 4, track->m_TrackStartString.ToStdString().c_str(),
923 -1, SQLITE_TRANSIENT);
924 sqlite3_bind_text(stmt, 5, track->m_TrackEndString.ToStdString().c_str(),
925 -1, SQLITE_TRANSIENT);
926 sqlite3_bind_int(stmt, 6, track->m_width);
927 sqlite3_bind_int(stmt, 7,
928 (
int)(track->m_style));
929 sqlite3_bind_text(stmt, 8, track->m_Colour.ToStdString().c_str(), -1,
931 sqlite3_bind_text(stmt, 9, track->m_GUID.c_str(), track->m_GUID.size(),
937 if (sqlite3_step(stmt) != SQLITE_DONE) {
938 ReportError(
"UpdateDBTrackAttributesA:step");
939 sqlite3_finalize(stmt);
943 sqlite3_finalize(stmt);
948 DeleteAllCommentsForTrack(m_db, track->m_GUID.ToStdString());
951 int NbrOfLinks = track->m_TrackHyperlinkList->size();
952 if (NbrOfLinks > 0) {
953 auto& list = track->m_TrackHyperlinkList;
954 for (
auto it = list->begin(); it != list->end(); ++it) {
957 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
958 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
959 link->DescrText.ToStdString(), link->Link.ToStdString(),
960 link->LType.ToStdString());
963 "UPDATE track_html_links SET "
965 "html_description = ?, "
969 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
970 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
972 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
974 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
977 if (sqlite3_step(stmt) != SQLITE_DONE) {
978 ReportError(
"UpdateDBTRackAttributesB:step");
979 sqlite3_finalize(stmt);
982 sqlite3_finalize(stmt);
992 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
995 int this_point_index = track->GetnPoints();
998 if (!InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
999 point->m_lon, point->GetTimeString(),
1000 this_point_index - 1))
1006bool NavObj_dB::LoadAllTracks() {
1007 const char* sql = R
"(
1009 description, visibility, start_string, end_string,
1010 width, style, color,
1013 ORDER BY created_at ASC
1017 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1021 while (sqlite3_step(stmt) == SQLITE_ROW) {
1023 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1025 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1026 std::string description =
1027 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1028 int visibility = sqlite3_column_int(stmt, 3);
1029 std::string start_string =
1030 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1031 std::string end_string =
1032 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 5));
1033 int width = sqlite3_column_int(stmt, 6);
1034 int style = sqlite3_column_int(stmt, 7);
1036 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 8));
1037 std::string created =
1038 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1040 Track* new_trk = NULL;
1043 const char* sql = R
"(
1044 SELECT latitude, longitude, timestamp, point_order
1046 WHERE track_guid = ?
1047 ORDER BY point_order ASC
1050 sqlite3_stmt* stmtp;
1051 if (sqlite3_prepare_v2(m_db, sql, -1, &stmtp,
nullptr) != SQLITE_OK) {
1055 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1058 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1060 new_trk =
new Track;
1061 new_trk->m_GUID = guid;
1064 new_trk->SetVisible(visibility == 1);
1065 new_trk->SetName(name.c_str());
1066 new_trk->m_TrackDescription = description.c_str();
1067 new_trk->m_TrackStartString = start_string.c_str();
1068 new_trk->m_TrackEndString = end_string.c_str();
1069 new_trk->m_width = width;
1070 new_trk->m_style = (wxPenStyle)style;
1071 new_trk->m_Colour = color;
1074 double latitude = sqlite3_column_double(stmtp, 0);
1075 double longitude = sqlite3_column_double(stmtp, 1);
1076 std::string timestamp =
1077 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, 2));
1078 int point_order = sqlite3_column_int(stmtp, 3);
1080 auto point =
new TrackPoint(latitude, longitude, timestamp);
1082 point->m_GPXTrkSegNo = GPXTrkSeg;
1083 new_trk->AddPoint(point);
1085 sqlite3_finalize(stmtp);
1088 new_trk->SetCurrentTrackSeg(GPXTrkSeg);
1091 const char* sqlh = R
"(
1092 SELECT guid, html_link, html_description, html_type
1093 FROM track_html_links
1094 WHERE track_guid = ?
1095 ORDER BY html_type ASC
1100 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1101 sqlite3_bind_text(stmt, 1, new_trk->m_GUID.ToStdString().c_str(), -1,
1104 while (sqlite3_step(stmt) == SQLITE_ROW) {
1105 std::string link_guid =
1106 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1107 std::string link_link =
1108 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1109 std::string link_description =
1110 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1111 std::string link_type =
1112 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1115 h->DescrText = link_description;
1116 h->Link = link_link;
1117 h->LType = link_type;
1119 new_trk->m_TrackHyperlinkList->push_back(h);
1123 sqlite3_finalize(stmt);
1132 pSelect->AddAllSelectableTrackSegments(new_trk);
1138bool NavObj_dB::DeleteTrack(
Track* track) {
1139 if (!track)
return false;
1140 std::string track_guid = track->m_GUID.ToStdString();
1141 const char* sql =
"DELETE FROM tracks WHERE guid = ?";
1144 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1145 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
1146 if (sqlite3_step(stmt) != SQLITE_DONE) {
1147 ReportError(
"DeleteTrack:step");
1148 sqlite3_finalize(stmt);
1152 sqlite3_finalize(stmt);
1161bool NavObj_dB::InsertRoute(
Route* route) {
1165 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString())) {
1167 wxString sql = wxString::Format(
"INSERT INTO routes (guid) VALUES ('%s')",
1168 route->
m_GUID.ToStdString().c_str());
1169 if (!executeSQL(m_db, sql)) {
1172 UpdateDBRouteAttributes(route);
1175 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1177 ReportError(
"InsertRoute:BEGIN TRANSACTION");
1182 for (
int i = 0; i < route->GetnPoints(); i++) {
1183 auto point = route->GetPoint(i + 1);
1186 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1187 InsertRoutePointDB(m_db, point);
1188 UpdateDBRoutePointAttributes(point);
1194 for (
int i = 0; i < route->GetnPoints(); i++) {
1195 auto point = route->GetPoint(i + 1);
1198 InsertRoutePointLink(m_db, route, point, i + 1);
1204 if (NbrOfLinks > 0) {
1206 for (
auto it = list.begin(); it != list.end(); ++it) {
1208 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1209 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1210 link->DescrText.ToStdString(), link->Link.ToStdString(),
1211 link->LType.ToStdString());
1216 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1219 ReportError(
"InsertRoute:commit");
1225bool NavObj_dB::UpdateRoute(
Route* route) {
1229 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1231 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1233 ReportError(
"UpdateRoute:BEGIN TRANSACTION");
1237 UpdateDBRouteAttributes(route);
1240 for (
int i = 0; i < route->GetnPoints(); i++) {
1241 auto point = route->GetPoint(i + 1);
1244 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1245 InsertRoutePointDB(m_db, point);
1247 UpdateDBRoutePointAttributes(point);
1252 const char* sql =
"DELETE FROM routepoints_link WHERE route_guid = ?";
1254 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1255 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1258 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1261 if (sqlite3_step(stmt) != SQLITE_DONE) {
1262 ReportError(
"UpdateRoute:step");
1263 sqlite3_finalize(stmt);
1264 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1268 sqlite3_finalize(stmt);
1270 for (
int i = 0; i < route->GetnPoints(); i++) {
1271 auto point = route->GetPoint(i + 1);
1273 InsertRoutePointLink(m_db, route, point, i + 1);
1279 if (NbrOfLinks > 0) {
1281 for (
auto it = list.begin(); it != list.end(); ++it) {
1283 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1284 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1285 link->DescrText.ToStdString(), link->Link.ToStdString(),
1286 link->LType.ToStdString());
1290 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
1293 if (errMsg) rv =
false;
1298bool NavObj_dB::UpdateRouteViz(
Route* route) {
1301 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1303 UpdateDBRouteAttributes(route);
1305 for (
int i = 0; i < route->GetnPoints(); i++) {
1306 auto point = route->GetPoint(i + 1);
1309 UpdateDBRoutePointViz(point);
1313 if (errMsg) rv =
false;
1318bool NavObj_dB::UpdateDBRouteAttributes(
Route* route) {
1320 "UPDATE routes SET "
1323 "start_string = ?, "
1326 "shared_wp_viz = ?, "
1327 "planned_departure = ?, "
1336 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1337 sqlite3_bind_text(stmt, 1, route->GetName().ToStdString().c_str(), -1,
1340 -1, SQLITE_TRANSIENT);
1342 -1, SQLITE_TRANSIENT);
1344 -1, SQLITE_TRANSIENT);
1345 sqlite3_bind_int(stmt, 5, route->IsVisible());
1346 sqlite3_bind_int(stmt, 6, route->GetSharedWPViz());
1351 -1, SQLITE_TRANSIENT);
1352 sqlite3_bind_int(stmt, 10, route->
m_width);
1353 sqlite3_bind_int(stmt, 11,
1355 sqlite3_bind_text(stmt, 12, route->
m_Colour.ToStdString().c_str(), -1,
1357 sqlite3_bind_text(stmt, 13, route->
m_GUID.c_str(), route->
m_GUID.size(),
1363 if (sqlite3_step(stmt) != SQLITE_DONE) {
1364 ReportError(
"UpdateDBRouteAttributesA:step");
1365 sqlite3_finalize(stmt);
1369 sqlite3_finalize(stmt);
1374 DeleteAllCommentsForRoute(m_db, route->
m_GUID.ToStdString());
1378 if (NbrOfLinks > 0) {
1380 for (
auto it = list->begin(); it != list->end(); ++it) {
1382 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1383 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1384 link->DescrText.ToStdString(), link->Link.ToStdString(),
1385 link->LType.ToStdString());
1388 "UPDATE route_html_links SET "
1390 "html_description = ?, "
1394 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1395 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1397 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1399 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1402 if (sqlite3_step(stmt) != SQLITE_DONE) {
1405 if (sqlite3_step(stmt) != SQLITE_DONE) {
1406 ReportError(
"UpdateDBRouteAttributesB:step");
1407 sqlite3_finalize(stmt);
1410 sqlite3_finalize(stmt);
1417bool NavObj_dB::UpdateDBRoutePointAttributes(
RoutePoint* point) {
1419 "UPDATE routepoints SET "
1430 "ArrivalRadius = ?, "
1431 "RangeRingsNumber = ?, "
1432 "RangeRingsStep = ?, "
1433 "RangeRingsStepUnits = ?, "
1434 "RangeRingsVisible = ?, "
1435 "RangeRingsColour = ?, "
1446 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1447 sqlite3_bind_double(stmt, 1, point->GetLatitude());
1448 sqlite3_bind_double(stmt, 2, point->GetLongitude());
1449 sqlite3_bind_text(stmt, 3, point->GetIconName().ToStdString().c_str(), -1,
1451 sqlite3_bind_text(stmt, 4, point->GetName().ToStdString().c_str(), -1,
1453 sqlite3_bind_text(stmt, 5, point->GetDescription().ToStdString().c_str(),
1454 -1, SQLITE_TRANSIENT);
1455 sqlite3_bind_text(stmt, 6, point->
m_TideStation.ToStdString().c_str(), -1,
1460 sqlite3_bind_int(stmt, 8, etd);
1461 sqlite3_bind_text(stmt, 9,
"type", -1, SQLITE_TRANSIENT);
1462 std::string timit = point->
m_timestring.ToStdString().c_str();
1463 sqlite3_bind_text(stmt, 10, point->
m_timestring.ToStdString().c_str(), -1,
1476 -1, SQLITE_TRANSIENT);
1478 sqlite3_bind_int(stmt, 17, point->GetScaMin());
1479 sqlite3_bind_int(stmt, 18, point->GetScaMax());
1480 sqlite3_bind_int(stmt, 19, point->GetUseSca());
1482 sqlite3_bind_int(stmt, 20, point->IsVisible());
1483 sqlite3_bind_int(stmt, 21, point->IsNameShown());
1484 sqlite3_bind_int(stmt, 22, point->IsShared());
1486 sqlite3_bind_int(stmt, 23, iso);
1488 sqlite3_bind_text(stmt, 24, point->
m_GUID.ToStdString().c_str(), -1,
1495 if (sqlite3_step(stmt) != SQLITE_DONE) {
1496 ReportError(
"UpdateDBRoutePointAttributesA:step");
1497 sqlite3_finalize(stmt);
1501 sqlite3_finalize(stmt);
1506 DeleteAllCommentsForRoutePoint(m_db, point->
m_GUID.ToStdString());
1510 if (NbrOfLinks > 0) {
1512 for (
auto it = list->begin(); it != list->end(); ++it) {
1514 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
1515 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
1516 link->DescrText.ToStdString(),
1517 link->Link.ToStdString(),
1518 link->LType.ToStdString());
1521 "UPDATE routepoint_html_links SET "
1523 "html_description = ?, "
1527 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1528 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1530 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1532 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1535 if (sqlite3_step(stmt) != SQLITE_DONE) {
1538 if (sqlite3_step(stmt) != SQLITE_DONE) {
1539 ReportError(
"UpdateDBRoutePointAttributesB:step-h");
1540 sqlite3_finalize(stmt);
1543 sqlite3_finalize(stmt);
1551bool NavObj_dB::UpdateDBRoutePointViz(
RoutePoint* point) {
1553 "UPDATE routepoints SET "
1558 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1559 sqlite3_bind_int(stmt, 1, point->IsVisible());
1560 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
1567 if (sqlite3_step(stmt) != SQLITE_DONE) {
1568 ReportError(
"UpdateDBRoutePointVizA:step");
1569 sqlite3_finalize(stmt);
1573 sqlite3_finalize(stmt);
1578bool NavObj_dB::DeleteRoute(
Route* route) {
1579 if (m_importing)
return false;
1580 if (!route)
return false;
1581 std::string route_guid = route->
m_GUID.ToStdString();
1582 const char* sql =
"DELETE FROM routes WHERE guid = ?";
1585 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1586 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
1587 if (sqlite3_step(stmt) != SQLITE_DONE) {
1588 ReportError(
"DeleteRoute:step");
1589 sqlite3_finalize(stmt);
1592 sqlite3_finalize(stmt);
1599bool NavObj_dB::LoadAllRoutes() {
1609 "planned_departure, "
1616 "ORDER BY created_at ASC";
1618 sqlite3_stmt* stmt_routes;
1619 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt_routes,
nullptr) != SQLITE_OK) {
1623 int errcode0 = SQLITE_OK;
1624 while ((errcode0 = sqlite3_step(stmt_routes)) == SQLITE_ROW) {
1626 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 0));
1628 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 1));
1629 std::string description =
1630 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 2));
1631 std::string start_string =
1632 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 3));
1633 std::string end_string =
1634 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 4));
1635 int visibility = sqlite3_column_int(stmt_routes, 5);
1636 int sharewp_viz = sqlite3_column_int(stmt_routes, 6);
1637 time_t planned_departure_ticks = sqlite3_column_int(stmt_routes, 7);
1638 double plan_speed = sqlite3_column_double(stmt_routes, 8);
1639 std::string time_format =
1640 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 9));
1642 int width = sqlite3_column_int(stmt_routes, 10);
1643 int style = sqlite3_column_int(stmt_routes, 11);
1645 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_routes, 12));
1647 Route* route = NULL;
1650 const char* sql = R
"(
1651 SELECT latitude, longitude, timestamp, point_order
1653 WHERE track_guid = ?
1654 ORDER BY point_order ASC
1670 "p.RangeRingsNumber, "
1671 "p.RangeRingsStep, "
1672 "p.RangeRingsStepUnits, "
1673 "p.RangeRingsVisible, "
1674 "p.RangeRingsColour, "
1683 "FROM routepoints_link tp "
1684 "JOIN routepoints p ON p.guid = tp.point_guid "
1685 "WHERE tp.route_guid = ? "
1686 "ORDER BY tp.point_order ASC";
1688 sqlite3_stmt* stmt_rp;
1689 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmt_rp,
nullptr) != SQLITE_OK) {
1690 ReportError(
"LoadAllRoutes-B:prepare");
1694 sqlite3_bind_text(stmt_rp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1697 int errcode = SQLITE_OK;
1698 while ((errcode = sqlite3_step(stmt_rp)) == SQLITE_ROW) {
1704 route->SetVisible(visibility == 1);
1709 route->SetVisible(visibility == 1);
1710 route->SetSharedWPViz(sharewp_viz == 1);
1716 route->
m_style = (wxPenStyle)style;
1722 std::string point_guid =
1723 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1724 double latitude = sqlite3_column_double(stmt_rp, col++);
1725 double longitude = sqlite3_column_double(stmt_rp, col++);
1726 std::string symbol =
1727 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1729 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1730 std::string description =
1731 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1732 std::string tide_station =
1733 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1734 double plan_speed = sqlite3_column_double(stmt_rp, col++);
1735 time_t etd_epoch = sqlite3_column_int(stmt_rp, col++);
1737 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1739 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1740 double arrival_radius = sqlite3_column_double(stmt_rp, col++);
1742 int range_ring_number = sqlite3_column_int(stmt_rp, col++);
1743 double range_ring_step = sqlite3_column_double(stmt_rp, col++);
1744 int range_ring_units = sqlite3_column_int(stmt_rp, col++);
1745 int range_ring_visible = sqlite3_column_int(stmt_rp, col++);
1746 std::string range_ring_color =
1747 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1749 int scamin = sqlite3_column_int(stmt_rp, col++);
1750 int scamax = sqlite3_column_int(stmt_rp, col++);
1751 int use_scaminmax = sqlite3_column_int(stmt_rp, col++);
1753 int visibility = sqlite3_column_int(stmt_rp, col++);
1754 int viz_name = sqlite3_column_int(stmt_rp, col++);
1755 int shared = sqlite3_column_int(stmt_rp, col++);
1756 int isolated = sqlite3_column_int(stmt_rp, col++);
1757 std::string point_created_at =
1758 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_rp, col++));
1763 auto containing_route =
1764 g_pRouteMan->FindRouteContainingWaypoint(point_guid);
1769 bool b_closed_route =
false;
1770 if (!containing_route) {
1771 RoutePoint* close_point = route->GetPoint(point_guid);
1772 b_closed_route = close_point !=
nullptr;
1773 existing_point = close_point;
1776 if (containing_route) {
1777 existing_point = containing_route->GetPoint(point_guid);
1780 if (!existing_point) {
1781 existing_point = pWayPointMan->FindRoutePointByGUID(point_guid.c_str());
1784 if (existing_point) {
1785 point = existing_point;
1786 if (!b_closed_route) {
1787 point->SetShared(
true);
1792 new RoutePoint(latitude, longitude, symbol, name, point_guid,
true);
1796 point->SetPlannedSpeed(plan_speed);
1799 etd.Set((time_t)etd_epoch);
1800 if (etd.IsValid()) point->
SetETD(etd);
1807 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1811 point->SetScaMin(scamin);
1812 point->SetScaMax(scamax);
1813 point->SetUseSca(use_scaminmax == 1);
1815 point->SetVisible(visibility == 1);
1816 point->SetNameShown(viz_name == 1);
1817 point->SetShared(shared == 1);
1820 if (point_created_at.size()) {
1824 std::istringstream ss(point_created_at);
1825 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
1826 time_t epoch_time = mktime(&tm);
1831 const char* sqlh = R
"(
1832 SELECT guid, html_link, html_description, html_type
1833 FROM routepoint_html_links
1834 WHERE routepoint_guid = ?
1835 ORDER BY html_type ASC
1838 sqlite3_stmt* stmt_point_link;
1840 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt_point_link,
nullptr) ==
1842 sqlite3_bind_text(stmt_point_link, 1,
1843 point->
m_GUID.ToStdString().c_str(), -1,
1846 while (sqlite3_step(stmt_point_link) == SQLITE_ROW) {
1847 std::string link_guid =
reinterpret_cast<const char*
>(
1848 sqlite3_column_text(stmt_point_link, 0));
1849 std::string link_link =
reinterpret_cast<const char*
>(
1850 sqlite3_column_text(stmt_point_link, 1));
1851 std::string link_description =
reinterpret_cast<const char*
>(
1852 sqlite3_column_text(stmt_point_link, 2));
1853 std::string link_type =
reinterpret_cast<const char*
>(
1854 sqlite3_column_text(stmt_point_link, 3));
1857 h->DescrText = link_description;
1858 h->Link = link_link;
1859 h->LType = link_type;
1863 sqlite3_finalize(stmt_point_link);
1867 route->AddPoint(point);
1869 sqlite3_finalize(stmt_rp);
1870 if (errcode != SQLITE_DONE) {
1871 ReportError(
"LoadAllRoutes-A:step");
1878 const char* sqlh = R
"(
1879 SELECT guid, html_link, html_description, html_type
1880 FROM route_html_links
1881 WHERE route_guid = ?
1882 ORDER BY html_type ASC
1885 sqlite3_stmt* stmt_route_links;
1887 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt_route_links,
nullptr) ==
1889 sqlite3_bind_text(stmt_route_links, 1,
1890 route->
m_GUID.ToStdString().c_str(), -1,
1893 int errcode2 = SQLITE_OK;
1894 while ((errcode2 = sqlite3_step(stmt_route_links)) == SQLITE_ROW) {
1895 std::string link_guid =
reinterpret_cast<const char*
>(
1896 sqlite3_column_text(stmt_route_links, 0));
1897 std::string link_link =
reinterpret_cast<const char*
>(
1898 sqlite3_column_text(stmt_route_links, 1));
1899 std::string link_description =
reinterpret_cast<const char*
>(
1900 sqlite3_column_text(stmt_route_links, 2));
1901 std::string link_type =
reinterpret_cast<const char*
>(
1902 sqlite3_column_text(stmt_route_links, 3));
1905 h->DescrText = link_description;
1906 h->Link = link_link;
1907 h->LType = link_type;
1911 if (errcode != SQLITE_DONE) {
1912 ReportError(
"LoadAllRoutes-B:step");
1916 sqlite3_finalize(stmt_route_links);
1919 ReportError(
"LoadAllRoutes-B:prepare");
1930 if (errcode0 != SQLITE_DONE) {
1931 ReportError(
"LoadAllRoutes-C:step");
1938bool NavObj_dB::LoadAllPoints() {
1953 "p.RangeRingsNumber, "
1954 "p.RangeRingsStep, "
1955 "p.RangeRingsStepUnits, "
1956 "p.RangeRingsVisible, "
1957 "p.RangeRingsColour, "
1966 "FROM routepoints p ";
1970 sqlite3_stmt* stmt_point;
1971 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmt_point,
nullptr) != SQLITE_OK) {
1975 while (sqlite3_step(stmt_point) == SQLITE_ROW) {
1978 std::string point_guid =
1979 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1980 double latitude = sqlite3_column_double(stmt_point, col++);
1981 double longitude = sqlite3_column_double(stmt_point, col++);
1982 std::string symbol =
1983 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1985 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1986 std::string description =
1987 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1988 std::string tide_station =
1989 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1990 double plan_speed = sqlite3_column_double(stmt_point, col++);
1991 time_t etd = sqlite3_column_int(stmt_point, col++);
1993 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1994 std::string point_time_string =
1995 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
1996 double arrival_radius = sqlite3_column_double(stmt_point, col++);
1998 int range_ring_number = sqlite3_column_int(stmt_point, col++);
1999 double range_ring_step = sqlite3_column_double(stmt_point, col++);
2000 int range_ring_units = sqlite3_column_int(stmt_point, col++);
2001 int range_ring_visible = sqlite3_column_int(stmt_point, col++);
2002 std::string range_ring_color =
2003 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
2005 int scamin = sqlite3_column_int(stmt_point, col++);
2006 int scamax = sqlite3_column_int(stmt_point, col++);
2007 int use_scaminmax = sqlite3_column_int(stmt_point, col++);
2009 int visibility = sqlite3_column_int(stmt_point, col++);
2010 int viz_name = sqlite3_column_int(stmt_point, col++);
2011 int shared = sqlite3_column_int(stmt_point, col++);
2012 int isolated = sqlite3_column_int(stmt_point, col++);
2013 std::string point_created_at =
2014 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_point, col++));
2018 new RoutePoint(latitude, longitude, symbol, name, point_guid,
false);
2022 point->SetPlannedSpeed(plan_speed);
2028 point->SetShowWaypointRangeRings(range_ring_visible == 1);
2032 point->SetScaMin(scamin);
2033 point->SetScaMax(scamax);
2034 point->SetUseSca(use_scaminmax == 1);
2036 point->SetVisible(visibility == 1);
2037 point->SetNameShown(viz_name == 1);
2038 point->SetShared(shared == 1);
2041 if (point_created_at.size()) {
2045 std::istringstream ss(point_created_at);
2046 ss >> std::get_time(&tm,
"%Y-%m-%d %H:%M:%S");
2047 time_t epoch_time = mktime(&tm);
2053 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
2056 const char* sqlh = R
"(
2057 SELECT guid, html_link, html_description, html_type
2058 FROM routepoint_html_links
2059 WHERE routepoint_guid = ?
2060 ORDER BY html_type ASC
2063 sqlite3_stmt* stmt_links;
2065 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt_links,
nullptr) ==
2067 sqlite3_bind_text(stmt_links, 1, point->
m_GUID.ToStdString().c_str(),
2068 -1, SQLITE_TRANSIENT);
2070 while (sqlite3_step(stmt_links) == SQLITE_ROW) {
2071 std::string link_guid =
2072 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_links, 0));
2073 std::string link_link =
2074 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_links, 1));
2075 std::string link_description =
2076 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_links, 2));
2077 std::string link_type =
2078 reinterpret_cast<const char*
>(sqlite3_column_text(stmt_links, 3));
2081 h->DescrText = link_description;
2082 h->Link = link_link;
2083 h->LType = link_type;
2087 sqlite3_finalize(stmt_links);
2091 sqlite3_finalize(stmt_point);
2095bool NavObj_dB::InsertRoutePoint(
RoutePoint* point) {
2099 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString())) {
2102 wxString::Format(
"INSERT INTO routepoints (guid) VALUES ('%s')",
2103 point->
m_GUID.ToStdString().c_str());
2104 if (!executeSQL(m_db, sql)) {
2109 UpdateDBRoutePointAttributes(point);
2113 if (NbrOfLinks > 0) {
2115 for (
auto it = list->begin(); it != list->end(); ++it) {
2117 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
2118 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
2119 link->DescrText.ToStdString(),
2120 link->Link.ToStdString(),
2121 link->LType.ToStdString());
2129bool NavObj_dB::DeleteRoutePoint(
RoutePoint* point) {
2130 if (m_importing)
return false;
2131 if (!point)
return false;
2133 std::string point_guid = point->
m_GUID.ToStdString();
2137 const char* sql =
"DELETE FROM routepoints WHERE guid = ?";
2140 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
2141 sqlite3_bind_text(stmt, 1, point_guid.c_str(), -1, SQLITE_TRANSIENT);
2142 if (sqlite3_step(stmt) != SQLITE_DONE) {
2143 ReportError(
"DeleteRoutePoint:step");
2144 sqlite3_finalize(stmt);
2148 sqlite3_finalize(stmt);
2155bool NavObj_dB::UpdateRoutePoint(
RoutePoint* point) {
2156 if (m_importing)
return false;
2157 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString()))
return false;
2158 UpdateDBRoutePointAttributes(point);
2162bool NavObj_dB::Backup(wxString fileName) {
2163 sqlite3_backup* pBackup;
2164 sqlite3* backupDatabase;
2166 if (sqlite3_open(fileName.c_str(), &backupDatabase) == SQLITE_OK) {
2167 pBackup = sqlite3_backup_init(backupDatabase,
"main", m_db,
"main");
2169 int result = sqlite3_backup_step(pBackup, -1);
2170 if ((result == SQLITE_OK) || (result == SQLITE_DONE)) {
2171 if (sqlite3_backup_finish(pBackup) == SQLITE_OK) {
2172 sqlite3_close_v2(backupDatabase);
2178 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.
navobj_db_util.h – MySQL support utilities
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.