31#include "model/base_platform.h"
33#include "model/navutil_base.h"
36#include "wx/filename.h"
37#include "model/comm_appmsg_bus.h"
40extern std::shared_ptr<ObservableListener> ack_listener;
41extern RouteList* pRouteList;
43void ReportError(
const std::string zmsg);
45static bool executeSQL(sqlite3* db,
const char* sql) {
46 char* errMsg =
nullptr;
47 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
49 wxString::Format(_(
"navobj database error.") +
" %s", errMsg);
51 auto& noteman = NotificationManager::GetInstance();
52 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
59static bool executeSQL(sqlite3* db, wxString& sql) {
60 return executeSQL(db, sql.ToStdString().c_str());
63bool CreateTables(sqlite3* db) {
65 const char* create_tables_sql = R
"(
66 CREATE TABLE IF NOT EXISTS tracks (
67 guid TEXT PRIMARY KEY NOT NULL,
76 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
79 CREATE TABLE IF NOT EXISTS trk_points (
80 track_guid TEXT NOT NULL,
81 latitude REAL NOT NULL,
82 longitude REAL NOT NULL,
83 timestamp TEXT NOT NULL,
85 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
89 CREATE TABLE IF NOT EXISTS track_html_links (
90 guid TEXT PRIMARY KEY,
91 track_guid TEXT NOT NULL,
93 html_description TEXT,
95 FOREIGN KEY (track_guid) REFERENCES tracks(guid) ON DELETE CASCADE
99 CREATE TABLE IF NOT EXISTS routes (
100 guid TEXT PRIMARY KEY NOT NULL,
105 planned_departure TEXT,
112 shared_wp_viz INTEGER,
113 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
117 CREATE TABLE IF NOT EXISTS routepoints (
118 guid TEXT PRIMARY KEY NOT NULL,
130 RangeRingsNumber INTEGER,
132 RangeRingsStepUnits INTEGER,
133 RangeRingsVisible INTEGER,
134 RangeRingsColour TEXT,
142 created_at DATETIME DEFAULT CURRENT_TIMESTAMP
145 CREATE TABLE IF NOT EXISTS routepoints_link (
149 PRIMARY KEY (route_guid, point_order),
150 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
153 CREATE TABLE IF NOT EXISTS route_html_links (
154 guid TEXT PRIMARY KEY,
155 route_guid TEXT NOT NULL,
157 html_description TEXT,
159 FOREIGN KEY (route_guid) REFERENCES routes(guid) ON DELETE CASCADE
162 CREATE TABLE IF NOT EXISTS routepoint_html_links (
163 guid TEXT PRIMARY KEY,
164 routepoint_guid TEXT NOT NULL,
166 html_description TEXT,
168 FOREIGN KEY (routepoint_guid) REFERENCES routepoints(guid) ON DELETE CASCADE
173 if (!executeSQL(db, create_tables_sql))
return false;
178bool TrackExists(sqlite3* db,
const std::string& track_guid) {
179 const char* sql =
"SELECT 1 FROM tracks WHERE guid = ? LIMIT 1";
183 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
184 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
186 if (sqlite3_step(stmt) == SQLITE_ROW) {
190 sqlite3_finalize(stmt);
192 ReportError(
"TrackExists:prepare");
198bool TrackHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
199 const char* sql =
"SELECT 1 FROM track_html_links WHERE guid = ? LIMIT 1";
203 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
204 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
206 if (sqlite3_step(stmt) == SQLITE_ROW) {
210 sqlite3_finalize(stmt);
212 ReportError(
"TrackHtmlLinkExists:prepare");
218bool DeleteAllCommentsForTrack(sqlite3* db,
const std::string& track_guid) {
219 const char* sql =
"DELETE FROM track_html_links WHERE track_guid = ?";
222 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
223 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
224 if (sqlite3_step(stmt) != SQLITE_DONE) {
225 ReportError(
"DeleteAllCommentsForTrack:step");
229 sqlite3_finalize(stmt);
231 ReportError(
"DeleteAllCommentsForTrack:prepare");
237bool InsertTrackPoint(sqlite3* db,
const std::string& track_guid,
double lat,
238 double lon,
const std::string& timestamp,
int i_point) {
239 const char* sql = R
"(
240 INSERT INTO trk_points (track_guid, latitude, longitude, timestamp, point_order)
241 VALUES (?, ?, ?, ?, ?)
245 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
246 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
247 sqlite3_bind_double(stmt, 2, lat);
248 sqlite3_bind_double(stmt, 3, lon);
249 sqlite3_bind_text(stmt, 4, timestamp.c_str(), -1, SQLITE_TRANSIENT);
250 sqlite3_bind_int(stmt, 5, i_point);
251 if (sqlite3_step(stmt) != SQLITE_DONE) {
252 ReportError(
"InsertTrackPoint:step");
253 sqlite3_finalize(stmt);
256 sqlite3_finalize(stmt);
263bool InsertTrackHTML(sqlite3* db,
const std::string& track_guid,
264 const std::string& link_guid,
const std::string& descrText,
265 const std::string& link,
const std::string& ltype) {
266 const char* sql = R
"(
267 INSERT INTO track_html_links (guid, track_guid, html_link, html_description, html_type)
268 VALUES (?, ?, ?, ?, ?)
272 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
273 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
274 sqlite3_bind_text(stmt, 2, track_guid.c_str(), -1, SQLITE_TRANSIENT);
275 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
276 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
277 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
278 if (sqlite3_step(stmt) != SQLITE_DONE) {
279 ReportError(
"InsertTrackHTML:step");
280 sqlite3_finalize(stmt);
283 sqlite3_finalize(stmt);
292bool DeleteAllCommentsForRoute(sqlite3* db,
const std::string& route_guid) {
293 const char* sql = R
"(
294 DELETE FROM route_html_links WHERE route_guid = ?
297 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
298 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
299 if (sqlite3_step(stmt) != SQLITE_DONE) {
300 ReportError(
"DeleteAllCommentsForRoute:step");
301 sqlite3_finalize(stmt);
304 sqlite3_finalize(stmt);
311bool RouteHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
312 const char* sql =
"SELECT 1 FROM route_html_links WHERE guid = ? LIMIT 1";
316 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
317 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
319 if (sqlite3_step(stmt) == SQLITE_ROW) {
323 sqlite3_finalize(stmt);
330bool RoutePointHtmlLinkExists(sqlite3* db,
const std::string& link_guid) {
332 "SELECT 1 FROM routepoint_html_links WHERE guid = ? LIMIT 1";
336 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
337 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
339 if (sqlite3_step(stmt) == SQLITE_ROW) {
343 sqlite3_finalize(stmt);
350bool RouteExistsDB(sqlite3* db,
const std::string& route_guid) {
351 const char* sql =
"SELECT 1 FROM routes WHERE guid = ? LIMIT 1";
355 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
356 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
358 if (sqlite3_step(stmt) == SQLITE_ROW) {
362 sqlite3_finalize(stmt);
369bool InsertRouteHTML(sqlite3* db,
const std::string& route_guid,
370 const std::string& link_guid,
const std::string& descrText,
371 const std::string& link,
const std::string& ltype) {
372 const char* sql = R
"(
373 INSERT INTO route_html_links (guid, route_guid, html_link, html_description, html_type)
374 VALUES (?, ?, ?, ?, ?)
378 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
379 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
380 sqlite3_bind_text(stmt, 2, route_guid.c_str(), -1, SQLITE_TRANSIENT);
381 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
382 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
383 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
384 if (sqlite3_step(stmt) != SQLITE_DONE) {
385 ReportError(
"InsertRouteHTML:step");
386 sqlite3_finalize(stmt);
389 sqlite3_finalize(stmt);
396bool RoutePointExists(sqlite3* db,
const std::string& routepoint_guid) {
397 const char* sql =
"SELECT 1 FROM routepoints WHERE guid = ? LIMIT 1";
401 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
402 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
404 if (sqlite3_step(stmt) == SQLITE_ROW) {
408 sqlite3_finalize(stmt);
415bool InsertRoutePointHTML(sqlite3* db,
const std::string& point_guid,
416 const std::string& link_guid,
417 const std::string& descrText,
const std::string& link,
418 const std::string& ltype) {
419 const char* sql = R
"(
420 INSERT INTO routepoint_html_links (guid, routepoint_guid, html_link, html_description, html_type)
421 VALUES (?, ?, ?, ?, ?)
425 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
426 sqlite3_bind_text(stmt, 1, link_guid.c_str(), -1, SQLITE_TRANSIENT);
427 sqlite3_bind_text(stmt, 2, point_guid.c_str(), -1, SQLITE_TRANSIENT);
428 sqlite3_bind_text(stmt, 3, link.c_str(), -1, SQLITE_TRANSIENT);
429 sqlite3_bind_text(stmt, 4, descrText.c_str(), -1, SQLITE_TRANSIENT);
430 sqlite3_bind_text(stmt, 5, ltype.c_str(), -1, SQLITE_TRANSIENT);
431 if (sqlite3_step(stmt) != SQLITE_DONE) {
432 ReportError(
"InsertRoutePointHTML:step");
433 sqlite3_finalize(stmt);
436 sqlite3_finalize(stmt);
442bool DeleteAllCommentsForRoutePoint(sqlite3* db,
443 const std::string& routepoint_guid) {
445 "DELETE FROM routepoint_html_links WHERE routepoint_guid = ?";
448 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
449 sqlite3_bind_text(stmt, 1, routepoint_guid.c_str(), -1, SQLITE_TRANSIENT);
450 if (sqlite3_step(stmt) != SQLITE_DONE) {
451 ReportError(
"DeleteAllCommentsForRoutepoint:step");
455 sqlite3_finalize(stmt);
457 ReportError(
"DeleteAllCommentsForRoutepoint:prepare");
463bool InsertRoutePointDB(sqlite3* db,
RoutePoint* point) {
464 const char* sql = R
"(
465 INSERT or REPLACE INTO routepoints(guid)
470 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
471 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
473 if (sqlite3_step(stmt) != SQLITE_DONE) {
474 ReportError(
"InsertRoutePointDB:step");
475 sqlite3_finalize(stmt);
478 sqlite3_finalize(stmt);
487 const char* sql = R
"(
488 INSERT or IGNORE INTO routepoints_link (route_guid, point_guid, point_order)
494 if (sqlite3_prepare_v2(db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
495 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
497 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
499 sqlite3_bind_int(stmt, 3, point_order);
500 if (sqlite3_step(stmt) != SQLITE_DONE) {
501 ReportError(
"InsertTrackPointLink:step");
502 sqlite3_finalize(stmt);
505 sqlite3_finalize(stmt);
512void DeleteOrphanedRoutepoint(sqlite3* db) {
513 const char* sql = R
"(
514 DELETE FROM routepoints
515 WHERE guid NOT IN (SELECT point_guid FROM routepoints_link)
517 char* errMsg =
nullptr;
519 if (sqlite3_exec(db, sql,
nullptr,
nullptr, &errMsg) != SQLITE_OK) {
524void errorLogCallback(
void* pArg,
int iErrCode,
const char* zMsg) {
526 wxString::Format(_(
"navobj database error.") +
" %d: %s", iErrCode, zMsg);
528 auto& noteman = NotificationManager::GetInstance();
529 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
532void ReportError(
const std::string zmsg) {
534 wxString::Format(_(
"navobj database error.") +
" %s", zmsg.c_str());
536 auto& noteman = NotificationManager::GetInstance();
537 noteman.AddNotification(NotificationSeverity::kWarning, msg.ToStdString());
545NavObj_dB::NavObj_dB() {
546 m_pImportProgress =
nullptr;
549 int ie = sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback,
nullptr);
553 wxFileName::GetPathSeparator() +
"navobj.db";
554 if (!wxFileExists(db_filename)) {
557 wxFileName::GetPathSeparator() +
"navobj.xml";
558 if (wxFileExists(xml_filename)) {
559 wxCopyFile(xml_filename, xml_filename +
".backup");
563 wxFileName::GetPathSeparator() +
564 "navobj.xml.import_backup";
565 if (!wxFileExists(deep_backup_filename)) {
566 wxCopyFile(xml_filename, deep_backup_filename);
572 int create_result = sqlite3_open_v2(
573 db_filename.ToStdString().c_str(),
575 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE,
578 if (create_result != SQLITE_OK) {
579 wxLogMessage(
"Cannot create new navobj.db database file");
588 int close_result = sqlite3_close_v2(m_db);
589 if (close_result != SQLITE_OK) {
595 int m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
596 SQLITE_OPEN_READWRITE, NULL);
597 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
601 sqlite3_close_v2(m_db);
603 m_open_result = sqlite3_open_v2(db_filename.ToStdString().c_str(), &m_db,
604 SQLITE_OPEN_READWRITE, NULL);
605 sqlite3_exec(m_db,
"PRAGMA foreign_keys = ON;",
nullptr,
nullptr,
nullptr);
611NavObj_dB::~NavObj_dB() { sqlite3_close_v2(m_db); }
613void NavObj_dB::Close() {
614 sqlite3_close_v2(m_db);
618bool NavObj_dB::ImportLegacyNavobj(wxFrame* frame) {
620 wxFileName::GetPathSeparator() +
"navobj.xml";
622 if (::wxFileExists(navobj_filename)) {
624 CountImportNavObjects();
625 m_pImportProgress =
new wxProgressDialog(_(
"Importing Navobj database"),
"",
626 m_nImportObjects, frame);
627 m_import_progesscount = 0;
629 rv = ImportLegacyPoints();
630 rv |= ImportLegacyRoutes();
631 rv |= ImportLegacyTracks();
633 m_pImportProgress->Destroy();
637 if (::wxFileExists(navobj_filename)) ::wxRemoveFile(navobj_filename);
642void NavObj_dB::CountImportNavObjects() {
643 m_nImportObjects = 0;
650 wxFileName::GetPathSeparator() +
"navobj.xml";
652 if (::wxFileExists(navobj_filename) &&
653 input_set->load_file(navobj_filename.ToStdString().c_str()).status ==
654 pugi::xml_parse_status::status_ok) {
655 input_set->LoadAllGPXPointObjects();
656 auto pointlist = pWayPointMan->GetWaypointList();
657 wxRoutePointListNode* prpnode = pointlist->GetFirst();
664 prpnode = prpnode->GetNext();
667 input_set->LoadAllGPXRouteObjects();
668 for (wxRouteListNode* node = pRouteList->GetFirst(); node;
669 node = node->GetNext()) {
670 Route* route_import = node->GetData();
673 m_nImportObjects += route_import->GetnPoints();
676 input_set->LoadAllGPXTrackObjects();
677 m_nImportObjects += g_TrackList.size();
678 m_nimportTracks = g_TrackList.size();
680 for (
Track* track_import : g_TrackList) {
681 m_nImportObjects += track_import->GetnPoints();
687bool NavObj_dB::ImportLegacyTracks() {
688 std::vector<Track*> tracks_added;
691 for (
Track* track_import : g_TrackList) {
692 if (InsertTrack(track_import)) {
693 tracks_added.push_back(track_import);
696 m_import_progesscount += track_import->GetnPoints() + 1;
697 wxString msg = wxString::Format(
"Tracks %d/%d", ntrack, m_nimportTracks);
698 m_pImportProgress->Update(m_import_progesscount, msg);
699 m_pImportProgress->Show();
703 for (
Track* ptrack : tracks_added) {
704 if (ptrack->m_bIsInLayer)
continue;
705 g_pRouteMan->DeleteTrack(ptrack);
711bool NavObj_dB::ImportLegacyRoutes() {
712 std::vector<Route*> routes_added;
715 for (wxRouteListNode* node = pRouteList->GetFirst(); node;
716 node = node->GetNext()) {
717 Route* route_import = node->GetData();
718 if (InsertRoute(route_import)) {
719 routes_added.push_back(route_import);
722 m_import_progesscount += route_import->GetnPoints() + 1;
723 wxString msg = wxString::Format(
"Routes %d/%d", nroute, m_nimportRoutes);
724 m_pImportProgress->Update(m_import_progesscount, msg);
725 m_pImportProgress->Show();
729 for (
Route* route : routes_added) {
735 pWayPointMan->DeleteAllWaypoints(
true);
740bool NavObj_dB::ImportLegacyPoints() {
741 std::vector<RoutePoint*> points_added;
745 if (m_nimportPoints > 1000) nmod = 10;
746 if (m_nimportPoints > 10000) nmod = 100;
748 auto pointlist = pWayPointMan->GetWaypointList();
749 wxRoutePointListNode* prpnode = pointlist->GetFirst();
753 if (InsertRoutePointDB(m_db, point)) {
754 points_added.push_back(point);
757 UpdateDBRoutePointAttributes(point);
758 m_import_progesscount += 1;
759 if ((npoint % nmod) == 0) {
761 wxString::Format(
"Points %d/%d", npoint, m_nimportPoints);
762 m_pImportProgress->Update(m_import_progesscount, msg);
763 m_pImportProgress->Show();
767 prpnode = prpnode->GetNext();
779void NavObj_dB::LoadNavObjects() {
785bool NavObj_dB::InsertTrack(
Track* track) {
786 if (TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
790 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
792 ReportError(
"InsertTrack:BEGIN TRANSACTION");
797 wxString sql = wxString::Format(
"INSERT INTO tracks (guid) VALUES ('%s')",
798 track->m_GUID.ToStdString().c_str());
799 if (!executeSQL(m_db, sql)) {
800 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
804 UpdateDBTrackAttributes(track);
807 for (
int i = 0; i < track->GetnPoints(); i++) {
808 auto point = track->GetPoint(i);
810 InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
811 point->m_lon, point->GetTimeString(), i);
815 int NbrOfLinks = track->m_TrackHyperlinkList->GetCount();
816 if (NbrOfLinks > 0) {
817 wxHyperlinkListNode* linknode = track->m_TrackHyperlinkList->GetFirst();
821 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
822 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
823 link->DescrText.ToStdString(), link->Link.ToStdString(),
824 link->LType.ToStdString());
826 linknode = linknode->GetNext();
829 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
831 if (errMsg) rv =
false;
836bool NavObj_dB::UpdateDBTrackAttributes(
Track* track) {
850 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
851 sqlite3_bind_text(stmt, 1, track->GetName().ToStdString().c_str(), -1,
853 sqlite3_bind_text(stmt, 2, track->m_TrackDescription.ToStdString().c_str(),
854 -1, SQLITE_TRANSIENT);
855 sqlite3_bind_int(stmt, 3, track->m_bVisible);
856 sqlite3_bind_text(stmt, 4, track->m_TrackStartString.ToStdString().c_str(),
857 -1, SQLITE_TRANSIENT);
858 sqlite3_bind_text(stmt, 5, track->m_TrackEndString.ToStdString().c_str(),
859 -1, SQLITE_TRANSIENT);
860 sqlite3_bind_int(stmt, 6, track->m_width);
861 sqlite3_bind_int(stmt, 7,
862 (
int)(track->m_style));
863 sqlite3_bind_text(stmt, 8, track->m_Colour.ToStdString().c_str(), -1,
865 sqlite3_bind_text(stmt, 9, track->m_GUID.c_str(), track->m_GUID.size(),
871 if (sqlite3_step(stmt) != SQLITE_DONE) {
872 ReportError(
"UpdateDBTrackAttributesA:step");
873 sqlite3_finalize(stmt);
877 sqlite3_finalize(stmt);
882 DeleteAllCommentsForTrack(m_db, track->m_GUID.ToStdString());
885 int NbrOfLinks = track->m_TrackHyperlinkList->GetCount();
886 if (NbrOfLinks > 0) {
887 wxHyperlinkListNode* linknode = track->m_TrackHyperlinkList->GetFirst();
891 if (!TrackHtmlLinkExists(m_db, link->GUID)) {
892 InsertTrackHTML(m_db, track->m_GUID.ToStdString(), link->GUID,
893 link->DescrText.ToStdString(), link->Link.ToStdString(),
894 link->LType.ToStdString());
897 "UPDATE track_html_links SET "
899 "html_description = ?, "
903 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
904 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
906 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
908 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
911 if (sqlite3_step(stmt) != SQLITE_DONE) {
912 ReportError(
"UpdateDBTRackAttributesB:step");
913 sqlite3_finalize(stmt);
917 sqlite3_finalize(stmt);
920 linknode = linknode->GetNext();
929 if (!TrackExists(m_db, track->m_GUID.ToStdString()))
return false;
932 int this_point_index = track->GetnPoints();
935 if (!InsertTrackPoint(m_db, track->m_GUID.ToStdString(), point->m_lat,
936 point->m_lon, point->GetTimeString(),
937 this_point_index - 1))
943bool NavObj_dB::LoadAllTracks() {
944 const char* sql = R
"(
946 description, visibility, start_string, end_string,
950 ORDER BY created_at ASC
954 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
958 while (sqlite3_step(stmt) == SQLITE_ROW) {
960 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
962 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
963 std::string description =
964 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
965 int visibility = sqlite3_column_int(stmt, 3);
966 std::string start_string =
967 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
968 std::string end_string =
969 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 5));
970 int width = sqlite3_column_int(stmt, 6);
971 int style = sqlite3_column_int(stmt, 7);
973 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 8));
974 std::string created =
975 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
977 Track* new_trk = NULL;
980 const char* sql = R
"(
981 SELECT latitude, longitude, timestamp, point_order
984 ORDER BY point_order ASC
988 if (sqlite3_prepare_v2(m_db, sql, -1, &stmtp,
nullptr) != SQLITE_OK) {
992 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
995 while (sqlite3_step(stmtp) == SQLITE_ROW) {
998 new_trk->m_GUID = guid;
1001 new_trk->SetVisible(visibility == 1);
1002 new_trk->SetName(name.c_str());
1003 new_trk->m_TrackStartString = start_string.c_str();
1004 new_trk->m_TrackEndString = end_string.c_str();
1005 new_trk->m_width = width;
1006 new_trk->m_style = (wxPenStyle)style;
1007 new_trk->m_Colour = color;
1012 double latitude = sqlite3_column_double(stmtp, 0);
1013 double longitude = sqlite3_column_double(stmtp, 1);
1014 std::string timestamp =
1015 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, 2));
1016 int point_order = sqlite3_column_int(stmtp, 3);
1018 auto point =
new TrackPoint(latitude, longitude, timestamp);
1020 point->m_GPXTrkSegNo = GPXSeg;
1021 new_trk->AddPoint(point);
1023 sqlite3_finalize(stmtp);
1026 new_trk->SetCurrentTrackSeg(GPXSeg);
1029 const char* sqlh = R
"(
1030 SELECT guid, html_link, html_description, html_type
1031 FROM track_html_links
1032 WHERE track_guid = ?
1033 ORDER BY html_type ASC
1038 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1039 sqlite3_bind_text(stmt, 1, new_trk->m_GUID.ToStdString().c_str(), -1,
1042 while (sqlite3_step(stmt) == SQLITE_ROW) {
1043 std::string link_guid =
1044 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1045 std::string link_link =
1046 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1047 std::string link_description =
1048 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1049 std::string link_type =
1050 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1053 h->DescrText = link_description;
1054 h->Link = link_link;
1055 h->LType = link_type;
1057 new_trk->m_TrackHyperlinkList->Append(h);
1061 sqlite3_finalize(stmt);
1068 g_TrackList.push_back(new_trk);
1070 pSelect->AddAllSelectableTrackSegments(new_trk);
1076bool NavObj_dB::DeleteTrack(
Track* track) {
1077 if (!track)
return false;
1078 std::string track_guid = track->m_GUID.ToStdString();
1079 const char* sql =
"DELETE FROM tracks WHERE guid = ?";
1082 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1083 sqlite3_bind_text(stmt, 1, track_guid.c_str(), -1, SQLITE_TRANSIENT);
1084 if (sqlite3_step(stmt) != SQLITE_DONE) {
1085 ReportError(
"DeleteTrack:step");
1086 sqlite3_finalize(stmt);
1090 sqlite3_finalize(stmt);
1099bool NavObj_dB::InsertRoute(
Route* route) {
1103 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString())) {
1105 wxString sql = wxString::Format(
"INSERT INTO routes (guid) VALUES ('%s')",
1106 route->
m_GUID.ToStdString().c_str());
1107 if (!executeSQL(m_db, sql)) {
1110 UpdateDBRouteAttributes(route);
1113 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1115 ReportError(
"InsertRoute:BEGIN TRANSACTION");
1120 for (
int i = 0; i < route->GetnPoints(); i++) {
1121 auto point = route->GetPoint(i + 1);
1124 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1125 InsertRoutePointDB(m_db, point);
1126 UpdateDBRoutePointAttributes(point);
1132 for (
int i = 0; i < route->GetnPoints(); i++) {
1133 auto point = route->GetPoint(i + 1);
1136 InsertRoutePointLink(m_db, route, point, i + 1);
1142 if (NbrOfLinks > 0) {
1147 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1148 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1149 link->DescrText.ToStdString(), link->Link.ToStdString(),
1150 link->LType.ToStdString());
1152 linknode = linknode->GetNext();
1156 sqlite3_exec(m_db,
"COMMIT", 0, 0, &errMsg);
1159 ReportError(
"InsertRoute:commit");
1165bool NavObj_dB::UpdateRoute(
Route* route) {
1169 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1171 sqlite3_exec(m_db,
"BEGIN TRANSACTION", 0, 0, &errMsg);
1173 ReportError(
"UpdateRoute:BEGIN TRANSACTION");
1177 UpdateDBRouteAttributes(route);
1180 for (
int i = 0; i < route->GetnPoints(); i++) {
1181 auto point = route->GetPoint(i + 1);
1184 if (!RoutePointExists(m_db, point->m_GUID.ToStdString())) {
1185 InsertRoutePointDB(m_db, point);
1187 UpdateDBRoutePointAttributes(point);
1192 const char* sql =
"DELETE FROM routepoints_link WHERE route_guid = ?";
1194 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1195 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1200 if (sqlite3_step(stmt) != SQLITE_DONE) {
1201 ReportError(
"UpdateRoute:step");
1202 sqlite3_finalize(stmt);
1206 sqlite3_finalize(stmt);
1208 for (
int i = 0; i < route->GetnPoints(); i++) {
1209 auto point = route->GetPoint(i + 1);
1211 InsertRoutePointLink(m_db, route, point, i + 1);
1217 if (NbrOfLinks > 0) {
1222 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1223 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1224 link->DescrText.ToStdString(), link->Link.ToStdString(),
1225 link->LType.ToStdString());
1227 linknode = linknode->GetNext();
1230 sqlite3_exec(m_db,
"COMMIT", 0, 0,
nullptr);
1233 if (errMsg) rv =
false;
1238bool NavObj_dB::UpdateRouteViz(
Route* route) {
1241 if (!RouteExistsDB(m_db, route->
m_GUID.ToStdString()))
return false;
1243 UpdateDBRouteAttributes(route);
1245 for (
int i = 0; i < route->GetnPoints(); i++) {
1246 auto point = route->GetPoint(i + 1);
1249 UpdateDBRoutePointViz(point);
1253 if (errMsg) rv =
false;
1258bool NavObj_dB::UpdateDBRouteAttributes(
Route* route) {
1260 "UPDATE routes SET "
1263 "start_string = ?, "
1266 "shared_wp_viz = ?, "
1267 "planned_departure = ?, "
1276 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1277 sqlite3_bind_text(stmt, 1, route->GetName().ToStdString().c_str(), -1,
1280 -1, SQLITE_TRANSIENT);
1282 -1, SQLITE_TRANSIENT);
1284 -1, SQLITE_TRANSIENT);
1285 sqlite3_bind_int(stmt, 5, route->IsVisible());
1286 sqlite3_bind_int(stmt, 6, route->GetSharedWPViz());
1290 -1, SQLITE_TRANSIENT);
1291 sqlite3_bind_int(stmt, 10, route->
m_width);
1292 sqlite3_bind_int(stmt, 11,
1294 sqlite3_bind_text(stmt, 12, route->
m_Colour.ToStdString().c_str(), -1,
1296 sqlite3_bind_text(stmt, 13, route->
m_GUID.c_str(), route->
m_GUID.size(),
1302 if (sqlite3_step(stmt) != SQLITE_DONE) {
1303 ReportError(
"UpdateDBRouteAttributesA:step");
1304 sqlite3_finalize(stmt);
1308 sqlite3_finalize(stmt);
1313 DeleteAllCommentsForRoute(m_db, route->
m_GUID.ToStdString());
1317 if (NbrOfLinks > 0) {
1322 if (!RouteHtmlLinkExists(m_db, link->GUID)) {
1323 InsertRouteHTML(m_db, route->
m_GUID.ToStdString(), link->GUID,
1324 link->DescrText.ToStdString(), link->Link.ToStdString(),
1325 link->LType.ToStdString());
1328 "UPDATE route_html_links SET "
1330 "html_description = ?, "
1334 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1335 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1337 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1339 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1342 if (sqlite3_step(stmt) != SQLITE_DONE) {
1345 if (sqlite3_step(stmt) != SQLITE_DONE) {
1346 ReportError(
"UpdateDBRouteAttributesB:step");
1347 sqlite3_finalize(stmt);
1351 sqlite3_finalize(stmt);
1354 linknode = linknode->GetNext();
1360bool NavObj_dB::UpdateDBRoutePointAttributes(
RoutePoint* point) {
1362 "UPDATE routepoints SET "
1373 "ArrivalRadius = ?, "
1374 "RangeRingsNumber = ?, "
1375 "RangeRingsStep = ?, "
1376 "RangeRingsStepUnits = ?, "
1377 "RangeRingsVisible = ?, "
1378 "RangeRingsColour = ?, "
1389 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1390 sqlite3_bind_double(stmt, 1, point->GetLatitude());
1391 sqlite3_bind_double(stmt, 2, point->GetLongitude());
1392 sqlite3_bind_text(stmt, 3, point->GetIconName().ToStdString().c_str(), -1,
1394 sqlite3_bind_text(stmt, 4, point->GetName().ToStdString().c_str(), -1,
1396 sqlite3_bind_text(stmt, 5, point->GetDescription().ToStdString().c_str(),
1397 -1, SQLITE_TRANSIENT);
1398 sqlite3_bind_text(stmt, 6, point->
m_TideStation.ToStdString().c_str(), -1,
1403 sqlite3_bind_int(stmt, 8, etd);
1404 sqlite3_bind_text(stmt, 9,
"type", -1, SQLITE_TRANSIENT);
1405 sqlite3_bind_text(stmt, 10, point->
m_timestring.ToStdString().c_str(), -1,
1418 -1, SQLITE_TRANSIENT);
1420 sqlite3_bind_int(stmt, 17, point->GetScaMin());
1421 sqlite3_bind_int(stmt, 18, point->GetScaMax());
1422 sqlite3_bind_int(stmt, 19, point->GetUseSca());
1424 sqlite3_bind_int(stmt, 20, point->IsVisible());
1425 sqlite3_bind_int(stmt, 21, point->IsNameShown());
1426 sqlite3_bind_int(stmt, 22, point->IsShared());
1428 sqlite3_bind_int(stmt, 23, iso);
1430 sqlite3_bind_text(stmt, 24, point->
m_GUID.ToStdString().c_str(), -1,
1437 if (sqlite3_step(stmt) != SQLITE_DONE) {
1438 ReportError(
"UpdateDBRoutePointAttributesA:step");
1439 sqlite3_finalize(stmt);
1443 sqlite3_finalize(stmt);
1448 DeleteAllCommentsForRoutePoint(m_db, point->
m_GUID.ToStdString());
1452 if (NbrOfLinks > 0) {
1457 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
1458 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
1459 link->DescrText.ToStdString(),
1460 link->Link.ToStdString(),
1461 link->LType.ToStdString());
1464 "UPDATE routepoint_html_links SET "
1466 "html_description = ?, "
1470 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1471 sqlite3_bind_text(stmt, 3, link->Link.ToStdString().c_str(), -1,
1473 sqlite3_bind_text(stmt, 4, link->DescrText.ToStdString().c_str(), -1,
1475 sqlite3_bind_text(stmt, 5, link->LType.ToStdString().c_str(), -1,
1478 if (sqlite3_step(stmt) != SQLITE_DONE) {
1481 if (sqlite3_step(stmt) != SQLITE_DONE) {
1482 ReportError(
"UpdateDBRoutePointAttributesB:step-h");
1483 sqlite3_finalize(stmt);
1487 sqlite3_finalize(stmt);
1490 linknode = linknode->GetNext();
1497bool NavObj_dB::UpdateDBRoutePointViz(
RoutePoint* point) {
1499 "UPDATE routepoints SET "
1504 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1505 sqlite3_bind_int(stmt, 1, point->IsVisible());
1506 sqlite3_bind_text(stmt, 2, point->
m_GUID.ToStdString().c_str(), -1,
1513 if (sqlite3_step(stmt) != SQLITE_DONE) {
1514 ReportError(
"UpdateDBRoutePointVizA:step");
1515 sqlite3_finalize(stmt);
1519 sqlite3_finalize(stmt);
1524bool NavObj_dB::DeleteRoute(
Route* route) {
1525 if (m_importing)
return false;
1526 if (!route)
return false;
1527 std::string route_guid = route->
m_GUID.ToStdString();
1528 const char* sql =
"DELETE FROM routes WHERE guid = ?";
1531 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
1532 sqlite3_bind_text(stmt, 1, route_guid.c_str(), -1, SQLITE_TRANSIENT);
1533 if (sqlite3_step(stmt) != SQLITE_DONE) {
1534 ReportError(
"DeleteRoute:step");
1535 sqlite3_finalize(stmt);
1538 sqlite3_finalize(stmt);
1545bool NavObj_dB::LoadAllRoutes() {
1555 "planned_departure, "
1562 "ORDER BY created_at ASC";
1565 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) != SQLITE_OK) {
1569 int errcode0 = SQLITE_OK;
1570 while ((errcode0 = sqlite3_step(stmt)) == SQLITE_ROW) {
1572 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1574 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1575 std::string description =
1576 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1577 std::string start_string =
1578 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1579 std::string end_string =
1580 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 4));
1581 int visibility = sqlite3_column_int(stmt, 5);
1582 int sharewp_viz = sqlite3_column_int(stmt, 6);
1583 time_t planned_departure_ticks = sqlite3_column_int(stmt, 7);
1584 double plan_speed = sqlite3_column_double(stmt, 8);
1585 std::string time_format =
1586 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 9));
1588 int width = sqlite3_column_int(stmt, 10);
1589 int style = sqlite3_column_int(stmt, 11);
1591 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 12));
1593 Route* route = NULL;
1596 const char* sql = R
"(
1597 SELECT latitude, longitude, timestamp, point_order
1599 WHERE track_guid = ?
1600 ORDER BY point_order ASC
1616 "p.RangeRingsNumber, "
1617 "p.RangeRingsStep, "
1618 "p.RangeRingsStepUnits, "
1619 "p.RangeRingsVisible, "
1620 "p.RangeRingsColour, "
1628 "FROM routepoints_link tp "
1629 "JOIN routepoints p ON p.guid = tp.point_guid "
1630 "WHERE tp.route_guid = ? "
1631 "ORDER BY tp.point_order ASC";
1633 sqlite3_stmt* stmtp;
1634 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1635 ReportError(
"LoadAllRoutes-B:prepare");
1639 sqlite3_bind_text(stmtp, 1, guid.c_str(), -1, SQLITE_TRANSIENT);
1642 int errcode = SQLITE_OK;
1643 while ((errcode = sqlite3_step(stmtp)) == SQLITE_ROW) {
1649 route->SetVisible(visibility == 1);
1654 route->SetVisible(visibility == 1);
1655 route->SetSharedWPViz(sharewp_viz == 1);
1661 route->
m_style = (wxPenStyle)style;
1667 std::string point_guid =
1668 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1669 double latitude = sqlite3_column_double(stmtp, col++);
1670 double longitude = sqlite3_column_double(stmtp, col++);
1671 std::string symbol =
1672 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1674 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1675 std::string description =
1676 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1677 std::string tide_station =
1678 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1679 double plan_speed = sqlite3_column_double(stmtp, col++);
1680 time_t etd_epoch = sqlite3_column_int(stmtp, col++);
1682 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1684 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1685 double arrival_radius = sqlite3_column_double(stmtp, col++);
1687 int range_ring_number = sqlite3_column_int(stmtp, col++);
1688 double range_ring_step = sqlite3_column_double(stmtp, col++);
1689 int range_ring_units = sqlite3_column_int(stmtp, col++);
1690 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1691 std::string range_ring_color =
1692 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1694 int scamin = sqlite3_column_int(stmtp, col++);
1695 int scamax = sqlite3_column_int(stmtp, col++);
1696 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1698 int visibility = sqlite3_column_int(stmtp, col++);
1699 int viz_name = sqlite3_column_int(stmtp, col++);
1700 int shared = sqlite3_column_int(stmtp, col++);
1701 int isolated = sqlite3_column_int(stmtp, col++);
1705 auto containing_route =
1706 g_pRouteMan->FindRouteContainingWaypoint(point_guid);
1708 if (containing_route) {
1709 point = containing_route->GetPoint(point_guid);
1712 new RoutePoint(latitude, longitude, symbol, name, point_guid,
true);
1716 point->SetPlannedSpeed(plan_speed);
1719 etd.Set((time_t)etd_epoch);
1720 if (etd.IsValid()) point->
SetETD(etd);
1727 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1731 point->SetScaMin(scamin);
1732 point->SetScaMax(scamax);
1733 point->SetUseSca(use_scaminmax == 1);
1735 point->SetVisible(visibility == 1);
1736 point->SetNameShown(viz_name == 1);
1737 point->SetShared(shared == 1);
1741 const char* sqlh = R
"(
1742 SELECT guid, html_link, html_description, html_type
1743 FROM routepoint_html_links
1744 WHERE routepoint_guid = ?
1745 ORDER BY html_type ASC
1750 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1751 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
1754 while (sqlite3_step(stmt) == SQLITE_ROW) {
1755 std::string link_guid =
1756 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1757 std::string link_link =
1758 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1759 std::string link_description =
1760 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1761 std::string link_type =
1762 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1765 h->DescrText = link_description;
1766 h->Link = link_link;
1767 h->LType = link_type;
1774 route->AddPoint(point);
1776 sqlite3_finalize(stmtp);
1777 if (errcode != SQLITE_DONE) {
1778 ReportError(
"LoadAllRoutes-A:step");
1785 const char* sqlh = R
"(
1786 SELECT guid, html_link, html_description, html_type
1787 FROM route_html_links
1788 WHERE route_guid = ?
1789 ORDER BY html_type ASC
1794 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1795 sqlite3_bind_text(stmt, 1, route->
m_GUID.ToStdString().c_str(), -1,
1798 int errcode2 = SQLITE_OK;
1799 while ((errcode2 = sqlite3_step(stmt)) == SQLITE_ROW) {
1800 std::string link_guid =
1801 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1802 std::string link_link =
1803 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1804 std::string link_description =
1805 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1806 std::string link_type =
1807 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1810 h->DescrText = link_description;
1811 h->Link = link_link;
1812 h->LType = link_type;
1816 if (errcode != SQLITE_DONE) {
1817 ReportError(
"LoadAllRoutes-B:step");
1821 sqlite3_finalize(stmt);
1824 ReportError(
"LoadAllRoutes-B:prepare");
1835 if (errcode0 != SQLITE_DONE) {
1836 ReportError(
"LoadAllRoutes-C:step");
1843bool NavObj_dB::LoadAllPoints() {
1858 "p.RangeRingsNumber, "
1859 "p.RangeRingsStep, "
1860 "p.RangeRingsStepUnits, "
1861 "p.RangeRingsVisible, "
1862 "p.RangeRingsColour, "
1870 "FROM routepoints p ";
1874 sqlite3_stmt* stmtp;
1875 if (sqlite3_prepare_v2(m_db, sqlp, -1, &stmtp,
nullptr) != SQLITE_OK) {
1879 while (sqlite3_step(stmtp) == SQLITE_ROW) {
1882 std::string point_guid =
1883 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1884 double latitude = sqlite3_column_double(stmtp, col++);
1885 double longitude = sqlite3_column_double(stmtp, col++);
1886 std::string symbol =
1887 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1889 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1890 std::string description =
1891 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1892 std::string tide_station =
1893 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1894 double plan_speed = sqlite3_column_double(stmtp, col++);
1895 time_t etd = sqlite3_column_int(stmtp, col++);
1897 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1898 std::string point_time_string =
1899 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1900 double arrival_radius = sqlite3_column_double(stmtp, col++);
1902 int range_ring_number = sqlite3_column_int(stmtp, col++);
1903 double range_ring_step = sqlite3_column_double(stmtp, col++);
1904 int range_ring_units = sqlite3_column_int(stmtp, col++);
1905 int range_ring_visible = sqlite3_column_int(stmtp, col++);
1906 std::string range_ring_color =
1907 reinterpret_cast<const char*
>(sqlite3_column_text(stmtp, col++));
1909 int scamin = sqlite3_column_int(stmtp, col++);
1910 int scamax = sqlite3_column_int(stmtp, col++);
1911 int use_scaminmax = sqlite3_column_int(stmtp, col++);
1913 int visibility = sqlite3_column_int(stmtp, col++);
1914 int viz_name = sqlite3_column_int(stmtp, col++);
1915 int shared = sqlite3_column_int(stmtp, col++);
1916 int isolated = sqlite3_column_int(stmtp, col++);
1920 new RoutePoint(latitude, longitude, symbol, name, point_guid,
false);
1924 point->SetPlannedSpeed(plan_speed);
1930 point->SetShowWaypointRangeRings(range_ring_visible == 1);
1934 point->SetScaMin(scamin);
1935 point->SetScaMax(scamax);
1936 point->SetUseSca(use_scaminmax == 1);
1938 point->SetVisible(visibility == 1);
1939 point->SetNameShown(viz_name == 1);
1940 point->SetShared(shared == 1);
1943 if (point_time_string.size()) {
1944 wxString sdt(point_time_string.c_str());
1950 pSelect->AddSelectableRoutePoint(point->m_lat, point->m_lon, point);
1953 sqlite3_finalize(stmtp);
1957 const char* sqlh = R
"(
1958 SELECT guid, html_link, html_description, html_type
1959 FROM routepoint_html_links
1960 WHERE routepoint_guid = ?
1961 ORDER BY html_type ASC
1966 if (sqlite3_prepare_v2(m_db, sqlh, -1, &stmt,
nullptr) == SQLITE_OK) {
1967 sqlite3_bind_text(stmt, 1, point->
m_GUID.ToStdString().c_str(), -1,
1970 while (sqlite3_step(stmt) == SQLITE_ROW) {
1971 std::string link_guid =
1972 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 0));
1973 std::string link_link =
1974 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 1));
1975 std::string link_description =
1976 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 2));
1977 std::string link_type =
1978 reinterpret_cast<const char*
>(sqlite3_column_text(stmt, 3));
1981 h->DescrText = link_description;
1982 h->Link = link_link;
1983 h->LType = link_type;
1988 sqlite3_finalize(stmt);
1996bool NavObj_dB::InsertRoutePoint(
RoutePoint* point) {
2000 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString())) {
2003 wxString::Format(
"INSERT INTO routepoints (guid) VALUES ('%s')",
2004 point->
m_GUID.ToStdString().c_str());
2005 if (!executeSQL(m_db, sql)) {
2010 UpdateDBRoutePointAttributes(point);
2014 if (NbrOfLinks > 0) {
2019 if (!RoutePointHtmlLinkExists(m_db, link->GUID)) {
2020 InsertRoutePointHTML(m_db, point->
m_GUID.ToStdString(), link->GUID,
2021 link->DescrText.ToStdString(),
2022 link->Link.ToStdString(),
2023 link->LType.ToStdString());
2025 linknode = linknode->GetNext();
2032bool NavObj_dB::DeleteRoutePoint(
RoutePoint* point) {
2033 if (m_importing)
return false;
2034 if (!point)
return false;
2036 std::string point_guid = point->
m_GUID.ToStdString();
2040 const char* sql =
"DELETE FROM routepoints WHERE guid = ?";
2043 if (sqlite3_prepare_v2(m_db, sql, -1, &stmt,
nullptr) == SQLITE_OK) {
2044 sqlite3_bind_text(stmt, 1, point_guid.c_str(), -1, SQLITE_TRANSIENT);
2045 if (sqlite3_step(stmt) != SQLITE_DONE) {
2046 ReportError(
"DeleteRoutePoint:step");
2047 sqlite3_finalize(stmt);
2051 sqlite3_finalize(stmt);
2058bool NavObj_dB::UpdateRoutePoint(
RoutePoint* point) {
2059 if (m_importing)
return false;
2060 if (!RoutePointExists(m_db, point->
m_GUID.ToStdString()))
return false;
2061 UpdateDBRoutePointAttributes(point);
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.