1 /*
2     SPDX-FileCopyrightText: 2012 Rishab Arora <ra.rishab@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "ksuserdb.h"
8 
9 #include "artificialhorizoncomponent.h"
10 #include "kspaths.h"
11 #include "kstarsdata.h"
12 #include "linelist.h"
13 #include "version.h"
14 
15 #include <QSqlQuery>
16 #include <QSqlRecord>
17 #include <QSqlTableModel>
18 
19 #include <kstars_debug.h>
20 
21 /*
22  * TODO (spacetime):
23  * The database supports storing logs. But it needs to be implemented.
24  *
25  * One of the unresolved problems was the creation of a unique identifier
26  * for each object (DSO,planet,star etc) for use in the database.
27 */
28 
~KSUserDB()29 KSUserDB::~KSUserDB()
30 {
31     m_UserDB.close();
32 
33     // Backup
34     QString current_dbfile = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("userdb.sqlite");
35     QString backup_dbfile = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("userdb.sqlite.backup");
36     QFile::remove(backup_dbfile);
37     QFile::copy(current_dbfile, backup_dbfile);
38 }
39 
Initialize()40 bool KSUserDB::Initialize()
41 {
42     // Every logged in user has their own db.
43     m_UserDB = QSqlDatabase::addDatabase("QSQLITE", "userdb");
44     if (!m_UserDB.isValid())
45     {
46         qCCritical(KSTARS) << "Unable to prepare database of type sqlite!";
47         return false;
48     }
49 
50     // If the database file does not exist, look for a backup
51     // If the database file exists and is empty, look for a backup
52     // If the database file exists and has data, use it.
53     // If the backup file does not exist, start fresh.
54     // If the backup file exists and has data, replace and use it.
55     // If the database file exists and has no data and the backup file exists, use it.
56     // If the database file exists and has no data and no backup file exists, start fresh.
57 
58     QFileInfo dbfile(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("userdb.sqlite"));
59     QFileInfo backup_file(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("userdb.sqlite.backup"));
60 
61     bool const first_run = !dbfile.exists() && !backup_file.exists();
62 
63     m_UserDB.setDatabaseName(dbfile.filePath());
64 
65     // If main fails to open and we have no backup, fail
66     if (!m_UserDB.open())
67     {
68         if (!backup_file.exists())
69         {
70             qCCritical(KSTARS) << QString("Failed opening user database '%1'.").arg(dbfile.filePath());
71             qCCritical(KSTARS) << LastError();
72             return false;
73         }
74     }
75 
76     // If no main nor backup existed before opening, rebuild
77     if (m_UserDB.isOpen() && first_run)
78     {
79         qCInfo(KSTARS) << "User DB does not exist. New User DB will be created.";
80         FirstRun();
81     }
82 
83     // If main appears empty/corrupted, restore if possible or rebuild
84     if (m_UserDB.tables().empty())
85     {
86         if (backup_file.exists())
87         {
88             m_UserDB.close();
89             qCWarning(KSTARS) << "Detected corrupted database. Attempting to recover from backup...";
90             QFile::remove(dbfile.filePath());
91             QFile::copy(backup_file.filePath(), dbfile.filePath());
92             QFile::remove(backup_file.filePath());
93             return Initialize();
94         }
95         else if (!FirstRun())
96         {
97             qCCritical(KSTARS) << QString("Failed initializing user database '%1.").arg(dbfile.filePath());
98             return false;
99         }
100     }
101 
102     qCDebug(KSTARS) << "Opened the User DB. Ready.";
103 
104     // Update table if previous version exists
105     QSqlTableModel version(nullptr, m_UserDB);
106     version.setTable("Version");
107     version.select();
108     QSqlRecord record = version.record(0);
109     version.clear();
110 
111     // Old version had 2.9.5 ..etc, so we remove them
112     // Starting with 2.9.7, we are using SCHEMA_VERSION which now decoupled from KStars Version and starts at 300
113     int currentDBVersion = record.value("Version").toString().remove(".").toInt();
114 
115     // Update database version to current KStars version
116     if (currentDBVersion != SCHEMA_VERSION)
117     {
118         QSqlQuery query(m_UserDB);
119         QString versionQuery = QString("UPDATE Version SET Version=%1").arg(SCHEMA_VERSION);
120         if (!query.exec(versionQuery))
121             qCWarning(KSTARS) << query.lastError();
122     }
123 
124     // If prior to 2.9.4 extend filters table
125     if (currentDBVersion < 294)
126     {
127         QSqlQuery query(m_UserDB);
128 
129         qCWarning(KSTARS) << "Detected old format filter table, re-creating...";
130         if (!query.exec("DROP table filter"))
131             qCWarning(KSTARS) << query.lastError();
132         if (!query.exec("CREATE TABLE filter ( "
133                         "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
134                         "Vendor TEXT DEFAULT NULL, "
135                         "Model TEXT DEFAULT NULL, "
136                         "Type TEXT DEFAULT NULL, "
137                         "Color TEXT DEFAULT NULL,"
138                         "Exposure REAL DEFAULT 1.0,"
139                         "Offset INTEGER DEFAULT 0,"
140                         "UseAutoFocus INTEGER DEFAULT 0,"
141                         "LockedFilter TEXT DEFAULT '--',"
142                         "AbsoluteFocusPosition INTEGER DEFAULT 0)"))
143             qCWarning(KSTARS) << query.lastError();
144     }
145 
146     // If prior to 2.9.5 create fov table
147     if (currentDBVersion < 295)
148     {
149         QSqlQuery query(m_UserDB);
150 
151         if (!query.exec("CREATE TABLE effectivefov ( "
152                         "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
153                         "Profile TEXT DEFAULT NULL, "
154                         "Width INTEGER DEFAULT NULL, "
155                         "Height INTEGER DEFAULT NULL, "
156                         "PixelW REAL DEFAULT 5.0,"
157                         "PixelH REAL DEFAULT 5.0,"
158                         "FocalLength REAL DEFAULT 0.0,"
159                         "FovW REAL DEFAULT 0.0,"
160                         "FovH REAL DEFAULT 0.0)"))
161             qCWarning(KSTARS) << query.lastError();
162     }
163 
164     if (currentDBVersion < 300)
165     {
166         QSqlQuery query(m_UserDB);
167         QString columnQuery = QString("ALTER TABLE profile ADD COLUMN remotedrivers TEXT DEFAULT NULL");
168         if (!query.exec(columnQuery))
169             qCWarning(KSTARS) << query.lastError();
170 
171         if (m_UserDB.tables().contains("customdrivers") == false)
172         {
173             QSqlQuery query(m_UserDB);
174 
175             if (!query.exec("CREATE TABLE customdrivers ( "
176                             "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
177                             "Name TEXT DEFAULT NULL, "
178                             "Label TEXT DEFAULT NULL UNIQUE, "
179                             "Manufacturer TEXT DEFAULT NULL, "
180                             "Family TEXT DEFAULT NULL, "
181                             "Exec TEXT DEFAULT NULL, "
182                             "Version TEXT DEFAULT 1.0)"))
183                 qCWarning(KSTARS) << query.lastError();
184         }
185     }
186 
187     // Add manufacturer
188     if (currentDBVersion < 305)
189     {
190         QSqlQuery query(m_UserDB);
191         QString columnQuery = QString("ALTER TABLE customdrivers ADD COLUMN Manufacturer TEXT DEFAULT NULL");
192         if (!query.exec(columnQuery))
193             qCWarning(KSTARS) << query.lastError();
194     }
195 
196     // Add indihub
197     if (currentDBVersion < 306)
198     {
199         QSqlQuery query(m_UserDB);
200         QString columnQuery = QString("ALTER TABLE profile ADD COLUMN indihub INTEGER DEFAULT 0");
201         if (!query.exec(columnQuery))
202             qCWarning(KSTARS) << query.lastError();
203     }
204 
205     // Add Defect Map
206     if (currentDBVersion < 307)
207     {
208         QSqlQuery query(m_UserDB);
209         // If we are upgrading, remove all previous entries.
210         QString clearQuery = QString("DELETE FROM darkframe");
211         if (!query.exec(clearQuery))
212             qCWarning(KSTARS) << query.lastError();
213         QString columnQuery = QString("ALTER TABLE darkframe ADD COLUMN defectmap TEXT DEFAULT NULL");
214         if (!query.exec(columnQuery))
215             qCWarning(KSTARS) << query.lastError();
216     }
217 
218     // Add port selector
219     if (currentDBVersion < 308)
220     {
221         QSqlQuery query(m_UserDB);
222         QString columnQuery = QString("ALTER TABLE profile ADD COLUMN portselector INTEGER DEFAULT 0");
223         if (!query.exec(columnQuery))
224             qCWarning(KSTARS) << query.lastError();
225     }
226 
227     m_UserDB.close();
228     return true;
229 }
230 
LastError()231 QSqlError KSUserDB::LastError()
232 {
233     // error description is in QSqlError::text()
234     return m_UserDB.lastError();
235 }
236 
FirstRun()237 bool KSUserDB::FirstRun()
238 {
239     if (!RebuildDB())
240         return false;
241 
242     /*ImportFlags();
243     ImportUsers();
244     ImportEquipment();*/
245 
246     return true;
247 }
248 
RebuildDB()249 bool KSUserDB::RebuildDB()
250 {
251     qCInfo(KSTARS) << "Rebuilding User Database";
252 
253     QVector<QString> tables;
254     tables.append("CREATE TABLE Version ("
255                   "Version CHAR DEFAULT NULL)");
256     tables.append("INSERT INTO Version VALUES (\"" KSTARS_VERSION "\")");
257     tables.append("CREATE TABLE user ( "
258                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
259                   "Name TEXT NOT NULL  DEFAULT 'NULL', "
260                   "Surname TEXT NOT NULL  DEFAULT 'NULL', "
261                   "Contact TEXT DEFAULT NULL)");
262 
263     tables.append("CREATE TABLE telescope ( "
264                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
265                   "Vendor TEXT DEFAULT NULL, "
266                   "Aperture REAL NOT NULL  DEFAULT NULL, "
267                   "Model TEXT DEFAULT NULL, "
268                   "Driver TEXT DEFAULT NULL, "
269                   "Type TEXT DEFAULT NULL, "
270                   "FocalLength REAL DEFAULT NULL)");
271 
272     tables.append("CREATE TABLE flags ( "
273                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
274                   "RA TEXT NOT NULL  DEFAULT NULL, "
275                   "Dec TEXT NOT NULL  DEFAULT NULL, "
276                   "Icon TEXT NOT NULL  DEFAULT 'NULL', "
277                   "Label TEXT NOT NULL  DEFAULT 'NULL', "
278                   "Color TEXT DEFAULT NULL, "
279                   "Epoch TEXT DEFAULT NULL)");
280 
281     tables.append("CREATE TABLE lens ( "
282                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
283                   "Vendor TEXT NOT NULL  DEFAULT 'NULL', "
284                   "Model TEXT DEFAULT NULL, "
285                   "Factor REAL NOT NULL  DEFAULT NULL)");
286 
287     tables.append("CREATE TABLE eyepiece ( "
288                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
289                   "Vendor TEXT DEFAULT NULL, "
290                   "Model TEXT DEFAULT NULL, "
291                   "FocalLength REAL NOT NULL  DEFAULT NULL, "
292                   "ApparentFOV REAL NOT NULL  DEFAULT NULL, "
293                   "FOVUnit TEXT NOT NULL  DEFAULT NULL)");
294 
295     tables.append("CREATE TABLE filter ( "
296                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
297                   "Vendor TEXT DEFAULT NULL, "
298                   "Model TEXT DEFAULT NULL, "
299                   "Type TEXT DEFAULT NULL, "
300                   "Color TEXT DEFAULT NULL,"
301                   "Exposure REAL DEFAULT 1.0,"
302                   "Offset INTEGER DEFAULT 0,"
303                   "UseAutoFocus INTEGER DEFAULT 0,"
304                   "LockedFilter TEXT DEFAULT '--',"
305                   "AbsoluteFocusPosition INTEGER DEFAULT 0)");
306 
307     tables.append("CREATE TABLE wishlist ( "
308                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
309                   "Date NUMERIC NOT NULL  DEFAULT NULL, "
310                   "Type TEXT DEFAULT NULL, "
311                   "UIUD TEXT DEFAULT NULL)");
312 
313     tables.append("CREATE TABLE fov ( "
314                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
315                   "name TEXT NOT NULL  DEFAULT 'NULL', "
316                   "color TEXT DEFAULT NULL, "
317                   "sizeX NUMERIC DEFAULT NULL, "
318                   "sizeY NUMERIC DEFAULT NULL, "
319                   "shape TEXT DEFAULT NULL)");
320 
321     tables.append("CREATE TABLE logentry ( "
322                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
323                   "content TEXT NOT NULL  DEFAULT 'NULL', "
324                   "UIUD TEXT DEFAULT NULL, "
325                   "DateTime NUMERIC NOT NULL  DEFAULT NULL, "
326                   "User INTEGER DEFAULT NULL REFERENCES user (id), "
327                   "Location TEXT DEFAULT NULL, "
328                   "Telescope INTEGER DEFAULT NULL REFERENCES telescope (id),"
329                   "Filter INTEGER DEFAULT NULL REFERENCES filter (id), "
330                   "lens INTEGER DEFAULT NULL REFERENCES lens (id), "
331                   "Eyepiece INTEGER DEFAULT NULL REFERENCES eyepiece (id), "
332                   "FOV INTEGER DEFAULT NULL REFERENCES fov (id))");
333 
334     // Note: enabled now encodes both a bool enabled value as well
335     // as another bool indicating if this is a horizon line or a ceiling line.
336     tables.append("CREATE TABLE horizons ( "
337                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
338                   "name TEXT NOT NULL,"
339                   "label TEXT NOT NULL,"
340                   "enabled INTEGER NOT NULL)");
341 
342     tables.append("CREATE TABLE profile (id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, host "
343                   "TEXT, port INTEGER, city TEXT, province TEXT, country TEXT, indiwebmanagerport INTEGER DEFAULT "
344                   "NULL, autoconnect INTEGER DEFAULT 1, guidertype INTEGER DEFAULT 0, guiderhost TEXT, guiderport INTEGER,"
345                   "primaryscope INTEGER DEFAULT 0, guidescope INTEGER DEFAULT 0, indihub INTEGER DEFAULT 0,"
346                   "portselector INTEGER DEFAULT 1, remotedrivers TEXT DEFAULT NULL)");
347     tables.append("CREATE TABLE driver (id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, label TEXT NOT NULL, role "
348                   "TEXT NOT NULL, profile INTEGER NOT NULL, FOREIGN KEY(profile) REFERENCES profile(id))");
349     //tables.append("CREATE TABLE custom_driver (id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, drivers TEXT NOT NULL, profile INTEGER NOT NULL, FOREIGN KEY(profile) REFERENCES profile(id))");
350 
351 #ifdef Q_OS_WIN
352     tables.append("INSERT INTO profile (name, host, port) VALUES ('Simulators', 'localhost', 7624)");
353 #else
354     tables.append("INSERT INTO profile (name, portselector) VALUES ('Simulators', 0)");
355 #endif
356 
357     tables.append("INSERT INTO driver (label, role, profile) VALUES ('Telescope Simulator', 'Mount', 1)");
358     tables.append("INSERT INTO driver (label, role, profile) VALUES ('CCD Simulator', 'CCD', 1)");
359     tables.append("INSERT INTO driver (label, role, profile) VALUES ('Focuser Simulator', 'Focuser', 1)");
360 
361     tables.append("CREATE TABLE IF NOT EXISTS darkframe (id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, ccd TEXT "
362                   "NOT NULL, chip INTEGER DEFAULT 0, binX INTEGER, binY INTEGER, temperature REAL, duration REAL, "
363                   "filename TEXT NOT NULL, defectmap TEXT DEFAULT NULL, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)");
364 
365     tables.append("CREATE TABLE IF NOT EXISTS hips (ID TEXT NOT NULL UNIQUE,"
366                   "obs_title TEXT NOT NULL, obs_description TEXT NOT NULL, hips_order TEXT NOT NULL,"
367                   "hips_frame TEXT NOT NULL, hips_tile_width TEXT NOT NULL, hips_tile_format TEXT NOT NULL,"
368                   "hips_service_url TEXT NOT NULL, moc_sky_fraction TEXT NOT NULL)");
369 
370     tables.append("INSERT INTO hips (ID, obs_title, obs_description, hips_order, hips_frame, hips_tile_width, hips_tile_format, hips_service_url, moc_sky_fraction)"
371                   "VALUES ('CDS/P/DSS2/color', 'DSS Colored', 'Color composition generated by CDS. This HiPS survey is based on 2 others HiPS surveys,"
372                   " respectively DSS2-red and DSS2-blue HiPS, both of them directly generated from original scanned plates downloaded"
373                   " from STScI site. The red component has been built from POSS-II F, AAO-SES,SR and SERC-ER plates. The blue component"
374                   " has been build from POSS-II J and SERC-J,EJ. The green component is based on the mean of other components. Three"
375                   " missing plates from red survey (253, 260, 359) has been replaced by pixels from the DSSColor STScI jpeg survey."
376                   " The 11 missing blue plates (mainly in galactic plane) have not been replaced (only red component).',"
377                   "'9', 'equatorial', '512', 'jpeg fits', 'http://alasky.u-strasbg.fr/DSS/DSSColor','1')");
378 
379     tables.append("INSERT INTO hips (ID, obs_title, obs_description, hips_order, hips_frame, hips_tile_width, hips_tile_format, hips_service_url, moc_sky_fraction)"
380                   "VALUES ('CDS/P/2MASS/color', '2MASS Color J (1.23 microns), H (1.66 microns), K (2.16 microns)',"
381                   "'2MASS has uniformly scanned the entire sky in three near-infrared bands to detect and characterize point sources"
382                   " brighter than about 1 mJy in each band, with signal-to-noise ratio (SNR) greater than 10, using a pixel size of"
383                   " 2.0\". This has achieved an 80,000-fold improvement in sensitivity relative to earlier surveys. 2MASS used two"
384                   " highly-automated 1.3-m telescopes, one at Mt. Hopkins, AZ, and one at CTIO, Chile. Each telescope was equipped with"
385                   " a three-channel camera, each channel consisting of a 256x256 array of HgCdTe detectors, capable of observing the"
386                   " sky simultaneously at J (1.25 microns), H (1.65 microns), and Ks (2.17 microns). The University of Massachusetts"
387                   " (UMass) was responsible for the overall management of the project, and for developing the infrared cameras and"
388                   " on-site computing systems at both facilities. The Infrared Processing and Analysis Center (IPAC) is responsible"
389                   " for all data processing through the Production Pipeline, and construction and distribution of the data products."
390                   " Funding is provided primarily by NASA and the NSF',"
391                   "'9', 'equatorial', '512', 'jpeg fits', 'http://alaskybis.u-strasbg.fr/2MASS/Color', '1')");
392 
393     tables.append("INSERT INTO hips (ID, obs_title, obs_description, hips_order, hips_frame, hips_tile_width, hips_tile_format, hips_service_url, moc_sky_fraction)"
394                   "VALUES ('CDS/P/Fermi/color', 'Fermi Color HEALPix Survey', 'Launched on June 11, 2008, the Fermi Gamma-ray Space Telescope observes the cosmos using the"
395                   " highest-energy form of light. This survey sums all data observed by the Fermi mission up to week 396. This version"
396                   " of the Fermi survey are intensity maps where the summed counts maps are divided by the exposure for each pixel"
397                   ". We anticipate using the HEASARC Hera capabilities to update this survey on a roughly quarterly basis. Data is"
398                   " broken into 5 energy bands : 30-100 MeV Band 1, 100-300 MeV Band 2, 300-1000 MeV Band 3, 1-3 GeV Band 4 ,"
399                   " 3-300 GeV Band 5. The SkyView data are based upon a Cartesian projection of the counts divided by the exposure maps."
400                   " In the Cartesian projection pixels near the pole have a much smaller area than pixels on the equator, so these"
401                   " pixels have smaller integrated flux. When creating large scale images in other projections users may wish to make"
402                   " sure to compensate for this effect the flux conserving clip-resampling option.', '9', 'equatorial', '512', 'jpeg fits',"
403                   "'http://alaskybis.u-strasbg.fr/Fermi/Color', '1')");
404 
405 
406     tables.append("CREATE TABLE dslr (id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
407                   "Model TEXT DEFAULT NULL, "
408                   "Width INTEGER DEFAULT NULL, "
409                   "Height INTEGER DEFAULT NULL, "
410                   "PixelW REAL DEFAULT 5.0,"
411                   "PixelH REAL DEFAULT 5.0)");
412 
413 
414     tables.append("CREATE TABLE effectivefov ( "
415                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
416                   "Profile TEXT DEFAULT NULL, "
417                   "Width INTEGER DEFAULT NULL, "
418                   "Height INTEGER DEFAULT NULL, "
419                   "PixelW REAL DEFAULT 5.0,"
420                   "PixelH REAL DEFAULT 5.0,"
421                   "FocalLength REAL DEFAULT 0.0,"
422                   "FovW REAL DEFAULT 0.0,"
423                   "FovH REAL DEFAULT 0.0)");
424 
425     tables.append("CREATE TABLE customdrivers ( "
426                   "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
427                   "Name TEXT DEFAULT NULL, "
428                   "Label TEXT DEFAULT NULL UNIQUE, "
429                   "Manufacturer TEXT DEFAULT NULL, "
430                   "Family TEXT DEFAULT NULL, "
431                   "Exec TEXT DEFAULT NULL, "
432                   "Version TEXT DEFAULT 1.0)");
433 
434     for (int i = 0; i < tables.count(); ++i)
435     {
436         QSqlQuery query(m_UserDB);
437         if (!query.exec(tables[i]))
438         {
439             qCDebug(KSTARS) << query.lastError();
440             qCDebug(KSTARS) << query.executedQuery();
441         }
442     }
443 
444     return true;
445 }
446 
447 /*
448  * Observer Section
449 */
AddObserver(const QString & name,const QString & surname,const QString & contact)450 void KSUserDB::AddObserver(const QString &name, const QString &surname, const QString &contact)
451 {
452     m_UserDB.open();
453     QSqlTableModel users(nullptr, m_UserDB);
454     users.setTable("user");
455     users.setFilter("Name LIKE \'" + name + "\' AND Surname LIKE \'" + surname + "\'");
456     users.select();
457 
458     if (users.rowCount() > 0)
459     {
460         QSqlRecord record = users.record(0);
461         record.setValue("Name", name);
462         record.setValue("Surname", surname);
463         record.setValue("Contact", contact);
464         users.setRecord(0, record);
465         users.submitAll();
466     }
467     else
468     {
469         int row = 0;
470         users.insertRows(row, 1);
471         users.setData(users.index(row, 1), name); // row0 is autoincerement ID
472         users.setData(users.index(row, 2), surname);
473         users.setData(users.index(row, 3), contact);
474         users.submitAll();
475     }
476 
477     m_UserDB.close();
478 }
479 
FindObserver(const QString & name,const QString & surname)480 bool KSUserDB::FindObserver(const QString &name, const QString &surname)
481 {
482     m_UserDB.open();
483     QSqlTableModel users(nullptr, m_UserDB);
484     users.setTable("user");
485     users.setFilter("Name LIKE \'" + name + "\' AND Surname LIKE \'" + surname + "\'");
486     users.select();
487 
488     int observer_count = users.rowCount();
489 
490     users.clear();
491     m_UserDB.close();
492     return (observer_count > 0);
493 }
494 
495 // TODO(spacetime): This method is currently unused.
DeleteObserver(const QString & id)496 bool KSUserDB::DeleteObserver(const QString &id)
497 {
498     m_UserDB.open();
499     QSqlTableModel users(nullptr, m_UserDB);
500     users.setTable("user");
501     users.setFilter("id = \'" + id + "\'");
502     users.select();
503 
504     users.removeRows(0, 1);
505     users.submitAll();
506 
507     int observer_count = users.rowCount();
508 
509     users.clear();
510     m_UserDB.close();
511     return (observer_count > 0);
512 }
GetDatabase()513 QSqlDatabase KSUserDB::GetDatabase()
514 {
515     m_UserDB.open();
516     return m_UserDB;
517 }
518 #ifndef KSTARS_LITE
GetAllObservers(QList<Observer * > & observer_list)519 void KSUserDB::GetAllObservers(QList<Observer *> &observer_list)
520 {
521     m_UserDB.open();
522     observer_list.clear();
523     QSqlTableModel users(nullptr, m_UserDB);
524     users.setTable("user");
525     users.select();
526 
527     for (int i = 0; i < users.rowCount(); ++i)
528     {
529         QSqlRecord record = users.record(i);
530         QString id        = record.value("id").toString();
531         QString name      = record.value("Name").toString();
532         QString surname   = record.value("Surname").toString();
533         QString contact   = record.value("Contact").toString();
534         OAL::Observer *o  = new OAL::Observer(id, name, surname, contact);
535         observer_list.append(o);
536     }
537 
538     users.clear();
539     m_UserDB.close();
540 }
541 #endif
542 
543 /* Dark Library Section */
544 
545 /**
546  * @brief KSUserDB::AddDarkFrame Saves a new dark frame data to the database
547  * @param oneFrame Map that contains 1 to 1 correspondence with the database table, except for primary key and timestamp.
548  */
AddDarkFrame(const QVariantMap & oneFrame)549 void KSUserDB::AddDarkFrame(const QVariantMap &oneFrame)
550 {
551     m_UserDB.open();
552     QSqlTableModel darkframe(nullptr, m_UserDB);
553     darkframe.setTable("darkframe");
554     darkframe.select();
555 
556     QSqlRecord record = darkframe.record();
557     // Remove PK so that it gets auto-incremented later
558     record.remove(0);
559     // Remove timestamp so that it gets auto-generated
560     record.remove(7);
561 
562     for (QVariantMap::const_iterator iter = oneFrame.begin(); iter != oneFrame.end(); ++iter)
563         record.setValue(iter.key(), iter.value());
564 
565     darkframe.insertRecord(-1, record);
566     darkframe.submitAll();
567 
568     m_UserDB.close();
569 }
570 
571 /**
572  * @brief KSUserDB::UpdateDarkFrame Updates an existing dark frame record in the data, replace all values matching the supplied ID
573  * @param oneFrame dark frame to update. The ID should already exist in the database.
574  */
UpdateDarkFrame(const QVariantMap & oneFrame)575 void KSUserDB::UpdateDarkFrame(const QVariantMap &oneFrame)
576 {
577     m_UserDB.open();
578     QSqlTableModel darkframe(nullptr, m_UserDB);
579     darkframe.setTable("darkframe");
580     darkframe.setFilter(QString("id=%1").arg(oneFrame["id"].toInt()));
581     darkframe.select();
582 
583     QSqlRecord record = darkframe.record(0);
584     for (QVariantMap::const_iterator iter = oneFrame.begin(); iter != oneFrame.end(); ++iter)
585         record.setValue(iter.key(), iter.value());
586 
587     darkframe.setRecord(0, record);
588     darkframe.submitAll();
589     m_UserDB.close();
590 }
591 
592 /**
593  * @brief KSUserDB::DeleteDarkFrame Delete from database a dark frame record that matches the filename field.
594  * @param filename filename of dark frame to delete from database.
595  */
DeleteDarkFrame(const QString & filename)596 void KSUserDB::DeleteDarkFrame(const QString &filename)
597 {
598     m_UserDB.open();
599     QSqlTableModel darkframe(nullptr, m_UserDB);
600     darkframe.setTable("darkframe");
601     darkframe.setFilter("filename = \'" + filename + "\'");
602 
603     darkframe.select();
604 
605     darkframe.removeRows(0, 1);
606     darkframe.submitAll();
607 
608     m_UserDB.close();
609 }
610 
GetAllDarkFrames(QList<QVariantMap> & darkFrames)611 void KSUserDB::GetAllDarkFrames(QList<QVariantMap> &darkFrames)
612 {
613     darkFrames.clear();
614 
615     m_UserDB.open();
616     QSqlTableModel darkframe(nullptr, m_UserDB);
617     darkframe.setTable("darkframe");
618     darkframe.select();
619 
620     for (int i = 0; i < darkframe.rowCount(); ++i)
621     {
622         QVariantMap recordMap;
623         QSqlRecord record = darkframe.record(i);
624         for (int j = 0; j < record.count(); j++)
625             recordMap[record.fieldName(j)] = record.value(j);
626 
627         darkFrames.append(recordMap);
628     }
629 
630     m_UserDB.close();
631 }
632 
633 
634 /* Effective FOV Section */
635 
AddEffectiveFOV(const QVariantMap & oneFOV)636 void KSUserDB::AddEffectiveFOV(const QVariantMap &oneFOV)
637 {
638     m_UserDB.open();
639     QSqlTableModel effectivefov(nullptr, m_UserDB);
640     effectivefov.setTable("effectivefov");
641     effectivefov.select();
642 
643     QSqlRecord record = effectivefov.record();
644 
645     // Remove PK so that it gets auto-incremented later
646     record.remove(0);
647 
648     for (QVariantMap::const_iterator iter = oneFOV.begin(); iter != oneFOV.end(); ++iter)
649         record.setValue(iter.key(), iter.value());
650 
651     effectivefov.insertRecord(-1, record);
652 
653     effectivefov.submitAll();
654 
655     m_UserDB.close();
656 }
657 
DeleteEffectiveFOV(const QString & id)658 bool KSUserDB::DeleteEffectiveFOV(const QString &id)
659 {
660     m_UserDB.open();
661     QSqlTableModel effectivefov(nullptr, m_UserDB);
662     effectivefov.setTable("effectivefov");
663     effectivefov.setFilter("id = \'" + id + "\'");
664 
665     effectivefov.select();
666 
667     effectivefov.removeRows(0, 1);
668     effectivefov.submitAll();
669 
670     m_UserDB.close();
671 
672     return true;
673 }
674 
GetAllEffectiveFOVs(QList<QVariantMap> & effectiveFOVs)675 void KSUserDB::GetAllEffectiveFOVs(QList<QVariantMap> &effectiveFOVs)
676 {
677     effectiveFOVs.clear();
678 
679     m_UserDB.open();
680     QSqlTableModel effectivefov(nullptr, m_UserDB);
681     effectivefov.setTable("effectivefov");
682     effectivefov.select();
683 
684     for (int i = 0; i < effectivefov.rowCount(); ++i)
685     {
686         QVariantMap recordMap;
687         QSqlRecord record = effectivefov.record(i);
688         for (int j = 0; j < record.count(); j++)
689             recordMap[record.fieldName(j)] = record.value(j);
690 
691         effectiveFOVs.append(recordMap);
692     }
693 
694     m_UserDB.close();
695 }
696 
697 /* Driver Alias Section */
698 
AddCustomDriver(const QVariantMap & oneDriver)699 bool KSUserDB::AddCustomDriver(const QVariantMap &oneDriver)
700 {
701     m_UserDB.open();
702     QSqlTableModel CustomDriver(nullptr, m_UserDB);
703     CustomDriver.setTable("customdrivers");
704     CustomDriver.select();
705 
706     QSqlRecord record = CustomDriver.record();
707 
708     // Remove PK so that it gets auto-incremented later
709     record.remove(0);
710 
711     for (QVariantMap::const_iterator iter = oneDriver.begin(); iter != oneDriver.end(); ++iter)
712         record.setValue(iter.key(), iter.value());
713 
714     bool rc = CustomDriver.insertRecord(-1, record);
715     if (rc == false)
716         return rc;
717 
718     rc = CustomDriver.submitAll();
719 
720     m_UserDB.close();
721 
722     return rc;
723 }
724 
DeleteCustomDriver(const QString & id)725 bool KSUserDB::DeleteCustomDriver(const QString &id)
726 {
727     m_UserDB.open();
728     QSqlTableModel CustomDriver(nullptr, m_UserDB);
729     CustomDriver.setTable("customdrivers");
730     CustomDriver.setFilter("id = \'" + id + "\'");
731 
732     CustomDriver.select();
733 
734     CustomDriver.removeRows(0, 1);
735     CustomDriver.submitAll();
736 
737     m_UserDB.close();
738 
739     return true;
740 }
741 
GetAllCustomDrivers(QList<QVariantMap> & CustomDrivers)742 void KSUserDB::GetAllCustomDrivers(QList<QVariantMap> &CustomDrivers)
743 {
744     CustomDrivers.clear();
745 
746     m_UserDB.open();
747     QSqlTableModel CustomDriver(nullptr, m_UserDB);
748     CustomDriver.setTable("customdrivers");
749     CustomDriver.select();
750 
751     for (int i = 0; i < CustomDriver.rowCount(); ++i)
752     {
753         QVariantMap recordMap;
754         QSqlRecord record = CustomDriver.record(i);
755         for (int j = 0; j < record.count(); j++)
756             recordMap[record.fieldName(j)] = record.value(j);
757 
758         CustomDrivers.append(recordMap);
759     }
760 
761     m_UserDB.close();
762 }
763 
764 /* HiPS Section */
765 
AddHIPSSource(const QMap<QString,QString> & oneSource)766 void KSUserDB::AddHIPSSource(const QMap<QString, QString> &oneSource)
767 {
768     m_UserDB.open();
769     QSqlTableModel HIPSSource(nullptr, m_UserDB);
770     HIPSSource.setTable("hips");
771     HIPSSource.select();
772 
773     QSqlRecord record = HIPSSource.record();
774 
775     for (QMap<QString, QString>::const_iterator iter = oneSource.begin(); iter != oneSource.end(); ++iter)
776         record.setValue(iter.key(), iter.value());
777 
778     HIPSSource.insertRecord(-1, record);
779 
780     HIPSSource.submitAll();
781 
782     m_UserDB.close();
783 }
784 
DeleteHIPSSource(const QString & ID)785 bool KSUserDB::DeleteHIPSSource(const QString &ID)
786 {
787     m_UserDB.open();
788     QSqlTableModel HIPSSource(nullptr, m_UserDB);
789     HIPSSource.setTable("hips");
790     HIPSSource.setFilter("ID = \'" + ID + "\'");
791 
792     HIPSSource.select();
793 
794     HIPSSource.removeRows(0, 1);
795     HIPSSource.submitAll();
796 
797     m_UserDB.close();
798 
799     return true;
800 }
801 
GetAllHIPSSources(QList<QMap<QString,QString>> & HIPSSources)802 void KSUserDB::GetAllHIPSSources(QList<QMap<QString, QString>> &HIPSSources)
803 {
804     HIPSSources.clear();
805 
806     m_UserDB.open();
807     QSqlTableModel HIPSSource(nullptr, m_UserDB);
808     HIPSSource.setTable("hips");
809     HIPSSource.select();
810 
811     for (int i = 0; i < HIPSSource.rowCount(); ++i)
812     {
813         QMap<QString, QString> recordMap;
814         QSqlRecord record = HIPSSource.record(i);
815         for (int j = 1; j < record.count(); j++)
816             recordMap[record.fieldName(j)] = record.value(j).toString();
817 
818         HIPSSources.append(recordMap);
819     }
820 
821     m_UserDB.close();
822 }
823 
824 
825 /* DSLR Section */
826 
AddDSLRInfo(const QMap<QString,QVariant> & oneInfo)827 void KSUserDB::AddDSLRInfo(const QMap<QString, QVariant> &oneInfo)
828 {
829     m_UserDB.open();
830     QSqlTableModel DSLRInfo(nullptr, m_UserDB);
831     DSLRInfo.setTable("dslr");
832     DSLRInfo.select();
833 
834     QSqlRecord record = DSLRInfo.record();
835 
836     for (QMap<QString, QVariant>::const_iterator iter = oneInfo.begin(); iter != oneInfo.end(); ++iter)
837         record.setValue(iter.key(), iter.value());
838 
839     DSLRInfo.insertRecord(-1, record);
840 
841     DSLRInfo.submitAll();
842 
843     m_UserDB.close();
844 }
845 
DeleteAllDSLRInfo()846 bool KSUserDB::DeleteAllDSLRInfo()
847 {
848     m_UserDB.open();
849     QSqlTableModel DSLRInfo(nullptr, m_UserDB);
850     DSLRInfo.setTable("dslr");
851     DSLRInfo.select();
852 
853     DSLRInfo.removeRows(0, DSLRInfo.rowCount());
854     DSLRInfo.submitAll();
855 
856     m_UserDB.close();
857 
858     return true;
859 }
860 
DeleteDSLRInfo(const QString & model)861 bool KSUserDB::DeleteDSLRInfo(const QString &model)
862 {
863     m_UserDB.open();
864     QSqlTableModel DSLRInfo(nullptr, m_UserDB);
865     DSLRInfo.setTable("dslr");
866     DSLRInfo.setFilter("model = \'" + model + "\'");
867 
868     DSLRInfo.select();
869 
870     DSLRInfo.removeRows(0, 1);
871     DSLRInfo.submitAll();
872 
873     m_UserDB.close();
874 
875     return true;
876 }
877 
GetAllDSLRInfos(QList<QMap<QString,QVariant>> & DSLRInfos)878 void KSUserDB::GetAllDSLRInfos(QList<QMap<QString, QVariant>> &DSLRInfos)
879 {
880     DSLRInfos.clear();
881 
882     m_UserDB.open();
883     QSqlTableModel DSLRInfo(nullptr, m_UserDB);
884     DSLRInfo.setTable("dslr");
885     DSLRInfo.select();
886 
887     for (int i = 0; i < DSLRInfo.rowCount(); ++i)
888     {
889         QMap<QString, QVariant> recordMap;
890         QSqlRecord record = DSLRInfo.record(i);
891         for (int j = 1; j < record.count(); j++)
892             recordMap[record.fieldName(j)] = record.value(j);
893 
894         DSLRInfos.append(recordMap);
895     }
896 
897     m_UserDB.close();
898 }
899 
900 /*
901  * Flag Section
902 */
903 
DeleteAllFlags()904 void KSUserDB::DeleteAllFlags()
905 {
906     m_UserDB.open();
907     QSqlTableModel flags(nullptr, m_UserDB);
908     flags.setEditStrategy(QSqlTableModel::OnManualSubmit);
909     flags.setTable("flags");
910     flags.select();
911 
912     flags.removeRows(0, flags.rowCount());
913     flags.submitAll();
914 
915     flags.clear();
916     m_UserDB.close();
917 }
918 
AddFlag(const QString & ra,const QString & dec,const QString & epoch,const QString & image_name,const QString & label,const QString & labelColor)919 void KSUserDB::AddFlag(const QString &ra, const QString &dec, const QString &epoch, const QString &image_name,
920                        const QString &label, const QString &labelColor)
921 {
922     m_UserDB.open();
923     QSqlTableModel flags(nullptr, m_UserDB);
924     flags.setTable("flags");
925 
926     int row = 0;
927     flags.insertRows(row, 1);
928     flags.setData(flags.index(row, 1), ra); // row,0 is autoincerement ID
929     flags.setData(flags.index(row, 2), dec);
930     flags.setData(flags.index(row, 3), image_name);
931     flags.setData(flags.index(row, 4), label);
932     flags.setData(flags.index(row, 5), labelColor);
933     flags.setData(flags.index(row, 6), epoch);
934     flags.submitAll();
935 
936     flags.clear();
937     m_UserDB.close();
938 }
939 
GetAllFlags()940 QList<QStringList> KSUserDB::GetAllFlags()
941 {
942     QList<QStringList> flagList;
943 
944     m_UserDB.open();
945     QSqlTableModel flags(nullptr, m_UserDB);
946     flags.setTable("flags");
947     flags.select();
948 
949     for (int i = 0; i < flags.rowCount(); ++i)
950     {
951         QStringList flagEntry;
952         QSqlRecord record = flags.record(i);
953         /* flagEntry order description
954          * The variation in the order is due to variation
955          * in flag entry description order and flag database
956          * description order.
957          * flag (database): ra, dec, icon, label, color, epoch
958          * flag (object):  ra, dec, epoch, icon, label, color
959         */
960         flagEntry.append(record.value(1).toString());
961         flagEntry.append(record.value(2).toString());
962         flagEntry.append(record.value(6).toString());
963         flagEntry.append(record.value(3).toString());
964         flagEntry.append(record.value(4).toString());
965         flagEntry.append(record.value(5).toString());
966         flagList.append(flagEntry);
967     }
968 
969     flags.clear();
970     m_UserDB.close();
971     return flagList;
972 }
973 
974 /*
975  * Generic Section
976  */
DeleteEquipment(const QString & type,const int & id)977 void KSUserDB::DeleteEquipment(const QString &type, const int &id)
978 {
979     m_UserDB.open();
980     QSqlTableModel equip(nullptr, m_UserDB);
981     equip.setTable(type);
982     equip.setFilter("id = " + QString::number(id));
983     equip.select();
984 
985     equip.removeRows(0, equip.rowCount());
986     equip.submitAll();
987 
988     equip.clear();
989     m_UserDB.close();
990 }
991 
DeleteAllEquipment(const QString & type)992 void KSUserDB::DeleteAllEquipment(const QString &type)
993 {
994     m_UserDB.open();
995     QSqlTableModel equip(nullptr, m_UserDB);
996     equip.setEditStrategy(QSqlTableModel::OnManualSubmit);
997     equip.setTable(type);
998     equip.setFilter("id >= 1");
999     equip.select();
1000     equip.removeRows(0, equip.rowCount());
1001     equip.submitAll();
1002 
1003     equip.clear();
1004     m_UserDB.close();
1005 }
1006 
1007 /*
1008  * Telescope section
1009  */
AddScope(const QString & model,const QString & vendor,const QString & driver,const QString & type,const double & focalLength,const double & aperture)1010 void KSUserDB::AddScope(const QString &model, const QString &vendor, const QString &driver, const QString &type,
1011                         const double &focalLength, const double &aperture)
1012 {
1013     m_UserDB.open();
1014     QSqlTableModel equip(nullptr, m_UserDB);
1015     equip.setTable("telescope");
1016 
1017     int row = 0;
1018     equip.insertRows(row, 1);
1019     equip.setData(equip.index(row, 1), vendor); // row,0 is autoincerement ID
1020     equip.setData(equip.index(row, 2), aperture);
1021     equip.setData(equip.index(row, 3), model);
1022     equip.setData(equip.index(row, 4), driver);
1023     equip.setData(equip.index(row, 5), type);
1024     equip.setData(equip.index(row, 6), focalLength);
1025     equip.submitAll();
1026 
1027     equip.clear(); //DB will not close if linked object not cleared
1028     m_UserDB.close();
1029 }
1030 
AddScope(const QString & model,const QString & vendor,const QString & driver,const QString & type,const double & focalLength,const double & aperture,const QString & id)1031 void KSUserDB::AddScope(const QString &model, const QString &vendor, const QString &driver, const QString &type,
1032                         const double &focalLength, const double &aperture, const QString &id)
1033 {
1034     m_UserDB.open();
1035     QSqlTableModel equip(nullptr, m_UserDB);
1036     equip.setTable("telescope");
1037     equip.setFilter("id = " + id);
1038     equip.select();
1039 
1040     if (equip.rowCount() > 0)
1041     {
1042         QSqlRecord record = equip.record(0);
1043         record.setValue(1, vendor);
1044         record.setValue(2, aperture);
1045         record.setValue(3, model);
1046         record.setValue(4, driver);
1047         record.setValue(5, type);
1048         record.setValue(6, focalLength);
1049         equip.setRecord(0, record);
1050         equip.submitAll();
1051     }
1052 
1053     m_UserDB.close();
1054 }
1055 #ifndef KSTARS_LITE
GetAllScopes(QList<Scope * > & scope_list)1056 void KSUserDB::GetAllScopes(QList<Scope *> &scope_list)
1057 {
1058     scope_list.clear();
1059 
1060     m_UserDB.open();
1061     QSqlTableModel equip(nullptr, m_UserDB);
1062     equip.setTable("telescope");
1063     equip.select();
1064 
1065     for (int i = 0; i < equip.rowCount(); ++i)
1066     {
1067         QSqlRecord record  = equip.record(i);
1068         QString id         = record.value("id").toString();
1069         QString vendor     = record.value("Vendor").toString();
1070         double aperture    = record.value("Aperture").toDouble();
1071         QString model      = record.value("Model").toString();
1072         QString driver     = record.value("Driver").toString();
1073         QString type       = record.value("Type").toString();
1074         double focalLength = record.value("FocalLength").toDouble();
1075         OAL::Scope *o      = new OAL::Scope(id, model, vendor, type, focalLength, aperture);
1076         o->setINDIDriver(driver);
1077         scope_list.append(o);
1078     }
1079 
1080     equip.clear();
1081     m_UserDB.close();
1082 }
1083 #endif
1084 /*
1085  * Eyepiece section
1086  */
AddEyepiece(const QString & vendor,const QString & model,const double & focalLength,const double & fov,const QString & fovunit)1087 void KSUserDB::AddEyepiece(const QString &vendor, const QString &model, const double &focalLength, const double &fov,
1088                            const QString &fovunit)
1089 {
1090     m_UserDB.open();
1091     QSqlTableModel equip(nullptr, m_UserDB);
1092     equip.setTable("eyepiece");
1093 
1094     int row = 0;
1095     equip.insertRows(row, 1);
1096     equip.setData(equip.index(row, 1), vendor); // row,0 is autoincerement ID
1097     equip.setData(equip.index(row, 2), model);
1098     equip.setData(equip.index(row, 3), focalLength);
1099     equip.setData(equip.index(row, 4), fov);
1100     equip.setData(equip.index(row, 5), fovunit);
1101     equip.submitAll();
1102 
1103     equip.clear();
1104     m_UserDB.close();
1105 }
1106 
AddEyepiece(const QString & vendor,const QString & model,const double & focalLength,const double & fov,const QString & fovunit,const QString & id)1107 void KSUserDB::AddEyepiece(const QString &vendor, const QString &model, const double &focalLength, const double &fov,
1108                            const QString &fovunit, const QString &id)
1109 {
1110     m_UserDB.open();
1111     QSqlTableModel equip(nullptr, m_UserDB);
1112     equip.setTable("eyepiece");
1113     equip.setFilter("id = " + id);
1114     equip.select();
1115 
1116     if (equip.rowCount() > 0)
1117     {
1118         QSqlRecord record = equip.record(0);
1119         record.setValue(1, vendor);
1120         record.setValue(2, model);
1121         record.setValue(3, focalLength);
1122         record.setValue(4, fov);
1123         record.setValue(5, fovunit);
1124         equip.setRecord(0, record);
1125         equip.submitAll();
1126     }
1127 
1128     m_UserDB.close();
1129 }
1130 #ifndef KSTARS_LITE
GetAllEyepieces(QList<OAL::Eyepiece * > & eyepiece_list)1131 void KSUserDB::GetAllEyepieces(QList<OAL::Eyepiece *> &eyepiece_list)
1132 {
1133     eyepiece_list.clear();
1134 
1135     m_UserDB.open();
1136     QSqlTableModel equip(nullptr, m_UserDB);
1137     equip.setTable("eyepiece");
1138     equip.select();
1139 
1140     for (int i = 0; i < equip.rowCount(); ++i)
1141     {
1142         QSqlRecord record  = equip.record(i);
1143         QString id         = record.value("id").toString();
1144         QString vendor     = record.value("Vendor").toString();
1145         QString model      = record.value("Model").toString();
1146         double focalLength = record.value("FocalLength").toDouble();
1147         double fov         = record.value("ApparentFOV").toDouble();
1148         QString fovUnit    = record.value("FOVUnit").toString();
1149 
1150         OAL::Eyepiece *o = new OAL::Eyepiece(id, model, vendor, fov, fovUnit, focalLength);
1151         eyepiece_list.append(o);
1152     }
1153 
1154     equip.clear();
1155     m_UserDB.close();
1156 }
1157 #endif
1158 /*
1159  * lens section
1160  */
AddLens(const QString & vendor,const QString & model,const double & factor)1161 void KSUserDB::AddLens(const QString &vendor, const QString &model, const double &factor)
1162 {
1163     m_UserDB.open();
1164     QSqlTableModel equip(nullptr, m_UserDB);
1165     equip.setTable("lens");
1166 
1167     int row = 0;
1168     equip.insertRows(row, 1);
1169     equip.setData(equip.index(row, 1), vendor); // row,0 is autoincerement ID
1170     equip.setData(equip.index(row, 2), model);
1171     equip.setData(equip.index(row, 3), factor);
1172     equip.submitAll();
1173 
1174     equip.clear();
1175     m_UserDB.close();
1176 }
1177 
AddLens(const QString & vendor,const QString & model,const double & factor,const QString & id)1178 void KSUserDB::AddLens(const QString &vendor, const QString &model, const double &factor, const QString &id)
1179 {
1180     m_UserDB.open();
1181     QSqlTableModel equip(nullptr, m_UserDB);
1182     equip.setTable("lens");
1183     equip.setFilter("id = " + id);
1184     equip.select();
1185 
1186     if (equip.rowCount() > 0)
1187     {
1188         QSqlRecord record = equip.record(0);
1189         record.setValue(1, vendor);
1190         record.setValue(2, model);
1191         record.setValue(3, factor);
1192         equip.submitAll();
1193     }
1194 
1195     m_UserDB.close();
1196 }
1197 #ifndef KSTARS_LITE
GetAllLenses(QList<OAL::Lens * > & lens_list)1198 void KSUserDB::GetAllLenses(QList<OAL::Lens *> &lens_list)
1199 {
1200     lens_list.clear();
1201 
1202     m_UserDB.open();
1203     QSqlTableModel equip(nullptr, m_UserDB);
1204     equip.setTable("lens");
1205     equip.select();
1206 
1207     for (int i = 0; i < equip.rowCount(); ++i)
1208     {
1209         QSqlRecord record = equip.record(i);
1210         QString id        = record.value("id").toString();
1211         QString vendor    = record.value("Vendor").toString();
1212         QString model     = record.value("Model").toString();
1213         double factor     = record.value("Factor").toDouble();
1214         OAL::Lens *o      = new OAL::Lens(id, model, vendor, factor);
1215         lens_list.append(o);
1216     }
1217 
1218     equip.clear();
1219     m_UserDB.close();
1220 }
1221 #endif
1222 /*
1223  *  filter section
1224  */
AddFilter(const QString & vendor,const QString & model,const QString & type,const QString & color,int offset,double exposure,bool useAutoFocus,const QString & lockedFilter,int absFocusPos)1225 void KSUserDB::AddFilter(const QString &vendor, const QString &model, const QString &type, const QString &color,
1226                          int offset, double exposure, bool useAutoFocus, const QString &lockedFilter, int absFocusPos)
1227 {
1228     if (m_UserDB.open())
1229     {
1230         QSqlTableModel equip(nullptr, m_UserDB);
1231         equip.setTable("filter");
1232 
1233         QSqlRecord record = equip.record();
1234         record.setValue("Vendor", vendor);
1235         record.setValue("Model", model);
1236         record.setValue("Type", type);
1237         record.setValue("Color", color);
1238         record.setValue("Offset", offset);
1239         record.setValue("Exposure", exposure);
1240         record.setValue("UseAutoFocus", useAutoFocus ? 1 : 0);
1241         record.setValue("LockedFilter", lockedFilter);
1242         record.setValue("AbsoluteFocusPosition", absFocusPos);
1243 
1244         if (equip.insertRecord(-1, record) == false)
1245             qCritical() << __FUNCTION__ << equip.lastError();
1246 
1247 
1248         /*int row = 0;
1249         equip.insertRows(row, 1);
1250         equip.setData(equip.index(row, 1), vendor);
1251         equip.setData(equip.index(row, 2), model);
1252         equip.setData(equip.index(row, 3), type);
1253         equip.setData(equip.index(row, 4), offset);
1254         equip.setData(equip.index(row, 5), color);
1255         equip.setData(equip.index(row, 6), exposure);
1256         equip.setData(equip.index(row, 7), lockedFilter);
1257         equip.setData(equip.index(row, 8), useAutoFocus ? 1 : 0);
1258         */
1259         if (equip.submitAll() == false)
1260             qCritical() << "AddFilter:" << equip.lastError();
1261 
1262         equip.clear();
1263         m_UserDB.close();
1264     }
1265     else qCritical() << "Failed opening database connection to add filters.";
1266 }
1267 
AddFilter(const QString & vendor,const QString & model,const QString & type,const QString & color,int offset,double exposure,bool useAutoFocus,const QString & lockedFilter,int absFocusPos,const QString & id)1268 void KSUserDB::AddFilter(const QString &vendor, const QString &model, const QString &type, const QString &color,
1269                          int offset, double exposure, bool useAutoFocus, const QString &lockedFilter, int absFocusPos, const QString &id)
1270 {
1271     m_UserDB.open();
1272     QSqlTableModel equip(nullptr, m_UserDB);
1273     equip.setTable("filter");
1274     equip.setFilter("id = " + id);
1275     equip.select();
1276 
1277     if (equip.rowCount() > 0)
1278     {
1279         QSqlRecord record = equip.record(0);
1280         record.setValue("Vendor", vendor);
1281         record.setValue("Model", model);
1282         record.setValue("Type", type);
1283         record.setValue("Color", color);
1284         record.setValue("Offset", offset);
1285         record.setValue("Exposure", exposure);
1286         record.setValue("UseAutoFocus", useAutoFocus ? 1 : 0);
1287         record.setValue("LockedFilter", lockedFilter);
1288         record.setValue("AbsoluteFocusPosition", absFocusPos);
1289         equip.setRecord(0, record);
1290         if (equip.submitAll() == false)
1291             qCritical() << "AddFilter:" << equip.lastError();
1292     }
1293 
1294     m_UserDB.close();
1295 }
1296 #ifndef KSTARS_LITE
GetAllFilters(QList<OAL::Filter * > & filter_list)1297 void KSUserDB::GetAllFilters(QList<OAL::Filter *> &filter_list)
1298 {
1299     m_UserDB.open();
1300     filter_list.clear();
1301     QSqlTableModel equip(nullptr, m_UserDB);
1302     equip.setTable("filter");
1303     equip.select();
1304 
1305     for (int i = 0; i < equip.rowCount(); ++i)
1306     {
1307         QSqlRecord record = equip.record(i);
1308         QString id        = record.value("id").toString();
1309         QString vendor    = record.value("Vendor").toString();
1310         QString model     = record.value("Model").toString();
1311         QString type      = record.value("Type").toString();
1312         QString color     = record.value("Color").toString();
1313         int offset        = record.value("Offset").toInt();
1314         double exposure   = record.value("Exposure").toDouble();
1315         QString lockedFilter  = record.value("LockedFilter").toString();
1316         bool useAutoFocus = record.value("UseAutoFocus").toInt() == 1;
1317         int absFocusPos   = record.value("AbsoluteFocusPosition").toInt();
1318         OAL::Filter *o    = new OAL::Filter(id, model, vendor, type, color, exposure, offset, useAutoFocus, lockedFilter,
1319                                             absFocusPos);
1320         filter_list.append(o);
1321     }
1322 
1323     equip.clear();
1324     m_UserDB.close();
1325 }
1326 #endif
1327 #if 0
1328 bool KSUserDB::ImportFlags()
1329 {
1330     QString flagfilename = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("flags.dat");
1331     QFile flagsfile(flagfilename);
1332     if (!flagsfile.exists())
1333     {
1334         return false;  // No upgrade needed. Flags file doesn't exist.
1335     }
1336 
1337     QList< QPair<QString, KSParser::DataTypes> > flag_file_sequence;
1338     flag_file_sequence.append(qMakePair(QString("RA"), KSParser::D_QSTRING));
1339     flag_file_sequence.append(qMakePair(QString("Dec"), KSParser::D_QSTRING));
1340     flag_file_sequence.append(qMakePair(QString("epoch"), KSParser::D_QSTRING));
1341     flag_file_sequence.append(qMakePair(QString("icon"), KSParser::D_QSTRING));
1342     flag_file_sequence.append(qMakePair(QString("label"), KSParser::D_QSTRING));
1343     flag_file_sequence.append(qMakePair(QString("color"), KSParser::D_QSTRING));
1344     KSParser flagparser(flagfilename, '#', flag_file_sequence, ' ');
1345 
1346     QHash<QString, QVariant> row_content;
1347     while (flagparser.HasNextRow())
1348     {
1349         row_content = flagparser.ReadNextRow();
1350         QString ra = row_content["RA"].toString();
1351         QString dec = row_content["Dec"].toString();
1352         QString epoch = row_content["epoch"].toString();
1353         QString icon = row_content["icon"].toString();
1354         QString label = row_content["label"].toString();
1355         QString color = row_content["color"].toString();
1356 
1357         AddFlag(ra, dec, epoch, icon, label, color);
1358     }
1359     return true;
1360 }
1361 
1362 bool KSUserDB::ImportUsers()
1363 {
1364     QString usersfilename = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("observerlist.xml");
1365     QFile usersfile(usersfilename);
1366 
1367     if (!usersfile.exists())
1368     {
1369         return false;  // No upgrade needed. Users file doesn't exist.
1370     }
1371 
1372     if( ! usersfile.open( QIODevice::ReadOnly ) )
1373         return false;
1374 
1375     QXmlStreamReader * reader = new QXmlStreamReader(&usersfile);
1376 
1377     while( ! reader->atEnd() )
1378     {
1379         reader->readNext();
1380 
1381         if( reader->isEndElement() )
1382             break;
1383 
1384         if( reader->isStartElement() )
1385         {
1386             if (reader->name() != "observers")
1387                 continue;
1388 
1389             //Read all observers
1390             while( ! reader->atEnd() )
1391             {
1392                 reader->readNext();
1393 
1394                 if( reader->isEndElement() )
1395                     break;
1396 
1397                 if( reader->isStartElement() )
1398                 {
1399                     // Read single observer
1400                     if( reader->name() == "observer" )
1401                     {
1402                         QString name, surname, contact;
1403                         while( ! reader->atEnd() )
1404                         {
1405                             reader->readNext();
1406 
1407                             if( reader->isEndElement() )
1408                                 break;
1409 
1410                             if( reader->isStartElement() )
1411                             {
1412                                 if( reader->name() == "name" )
1413                                 {
1414                                     name = reader->readElementText();
1415                                 }
1416                                 else if( reader->name() == "surname" )
1417                                 {
1418                                     surname = reader->readElementText();
1419                                 }
1420                                 else if( reader->name() == "contact" )
1421                                 {
1422                                     contact = reader->readElementText();
1423                                 }
1424                             }
1425                         }
1426                         AddObserver(name, surname, contact);
1427                     }
1428                 }
1429             }
1430         }
1431     }
1432     delete reader_;
1433     usersfile.close();
1434     return true;
1435 }
1436 
1437 bool KSUserDB::ImportEquipment()
1438 {
1439     QString equipfilename = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("equipmentlist.xml");
1440     QFile equipfile(equipfilename);
1441 
1442     if (!equipfile.exists())
1443     {
1444         return false;  // No upgrade needed. File doesn't exist.
1445     }
1446 
1447     if( ! equipfile.open( QIODevice::ReadOnly ) )
1448         return false;
1449 
1450     reader_ = new QXmlStreamReader(&equipfile);
1451     while( ! reader_->atEnd() )
1452     {
1453         reader_->readNext();
1454         if( reader_->isStartElement() )
1455         {
1456             while( ! reader_->atEnd() )
1457             {
1458                 reader_->readNext();
1459 
1460                 if( reader_->isEndElement() )
1461                     break;
1462 
1463                 if( reader_->isStartElement() )
1464                 {
1465                     if( reader_->name() == "scopes" )
1466                         readScopes();
1467                     else if( reader_->name() == "eyepieces" )
1468                         readEyepieces();
1469                     else if( reader_->name() == "lenses" )
1470                         readLenses();
1471                     else if( reader_->name() == "filters" )
1472                         readFilters();
1473                 }
1474             }
1475         }
1476     }
1477     delete reader_;
1478     equipfile.close();
1479     return true;
1480 }
1481 #endif
1482 
readScopes()1483 void KSUserDB::readScopes()
1484 {
1485     while (!reader_->atEnd())
1486     {
1487         reader_->readNext();
1488 
1489         if (reader_->isEndElement())
1490             break;
1491 
1492         if (reader_->isStartElement())
1493         {
1494             if (reader_->name() == "scope")
1495                 readScope();
1496         }
1497     }
1498 }
1499 
readEyepieces()1500 void KSUserDB::readEyepieces()
1501 {
1502     while (!reader_->atEnd())
1503     {
1504         reader_->readNext();
1505 
1506         if (reader_->isEndElement())
1507             break;
1508 
1509         if (reader_->isStartElement())
1510         {
1511             if (reader_->name() == "eyepiece")
1512                 readEyepiece();
1513         }
1514     }
1515 }
1516 
readLenses()1517 void KSUserDB::readLenses()
1518 {
1519     while (!reader_->atEnd())
1520     {
1521         reader_->readNext();
1522 
1523         if (reader_->isEndElement())
1524             break;
1525 
1526         if (reader_->isStartElement())
1527         {
1528             if (reader_->name() == "lens")
1529                 readLens();
1530         }
1531     }
1532 }
1533 
readFilters()1534 void KSUserDB::readFilters()
1535 {
1536     while (!reader_->atEnd())
1537     {
1538         reader_->readNext();
1539 
1540         if (reader_->isEndElement())
1541             break;
1542 
1543         if (reader_->isStartElement())
1544         {
1545             if (reader_->name() == "filter")
1546                 readFilter();
1547         }
1548     }
1549 }
1550 
readScope()1551 void KSUserDB::readScope()
1552 {
1553     QString model, vendor, type, driver = i18nc("No driver", "None");
1554     double aperture = 0, focalLength = 0;
1555 
1556     while (!reader_->atEnd())
1557     {
1558         reader_->readNext();
1559 
1560         if (reader_->isEndElement())
1561             break;
1562 
1563         if (reader_->isStartElement())
1564         {
1565             if (reader_->name() == "model")
1566             {
1567                 model = reader_->readElementText();
1568             }
1569             else if (reader_->name() == "vendor")
1570             {
1571                 vendor = reader_->readElementText();
1572             }
1573             else if (reader_->name() == "type")
1574             {
1575                 type = reader_->readElementText();
1576                 if (type == "N")
1577                     type = "Newtonian";
1578                 if (type == "R")
1579                     type = "Refractor";
1580                 if (type == "M")
1581                     type = "Maksutov";
1582                 if (type == "S")
1583                     type = "Schmidt-Cassegrain";
1584                 if (type == "K")
1585                     type = "Kutter (Schiefspiegler)";
1586                 if (type == "C")
1587                     type = "Cassegrain";
1588                 if (type == "RC")
1589                     type = "Ritchey-Chretien";
1590             }
1591             else if (reader_->name() == "focalLength")
1592             {
1593                 focalLength = (reader_->readElementText()).toDouble();
1594             }
1595             else if (reader_->name() == "aperture")
1596                 aperture = (reader_->readElementText()).toDouble();
1597             else if (reader_->name() == "driver")
1598                 driver = reader_->readElementText();
1599         }
1600     }
1601 
1602     AddScope(model, vendor, driver, type, focalLength, aperture);
1603 }
1604 
readEyepiece()1605 void KSUserDB::readEyepiece()
1606 {
1607     QString model, focalLength, vendor, fov, fovUnit;
1608     while (!reader_->atEnd())
1609     {
1610         reader_->readNext();
1611 
1612         if (reader_->isEndElement())
1613             break;
1614 
1615         if (reader_->isStartElement())
1616         {
1617             if (reader_->name() == "model")
1618             {
1619                 model = reader_->readElementText();
1620             }
1621             else if (reader_->name() == "vendor")
1622             {
1623                 vendor = reader_->readElementText();
1624             }
1625             else if (reader_->name() == "apparentFOV")
1626             {
1627                 fov     = reader_->readElementText();
1628                 fovUnit = reader_->attributes().value("unit").toString();
1629             }
1630             else if (reader_->name() == "focalLength")
1631             {
1632                 focalLength = reader_->readElementText();
1633             }
1634         }
1635     }
1636 
1637     AddEyepiece(vendor, model, focalLength.toDouble(), fov.toDouble(), fovUnit);
1638 }
1639 
readLens()1640 void KSUserDB::readLens()
1641 {
1642     QString model, factor, vendor;
1643     while (!reader_->atEnd())
1644     {
1645         reader_->readNext();
1646 
1647         if (reader_->isEndElement())
1648             break;
1649 
1650         if (reader_->isStartElement())
1651         {
1652             if (reader_->name() == "model")
1653             {
1654                 model = reader_->readElementText();
1655             }
1656             else if (reader_->name() == "vendor")
1657             {
1658                 vendor = reader_->readElementText();
1659             }
1660             else if (reader_->name() == "factor")
1661             {
1662                 factor = reader_->readElementText();
1663             }
1664         }
1665     }
1666 
1667     AddLens(vendor, model, factor.toDouble());
1668 }
1669 
readFilter()1670 void KSUserDB::readFilter()
1671 {
1672     QString model, vendor, type, color, lockedFilter;
1673     int offset = 0;
1674     double exposure = 1.0;
1675     bool useAutoFocus = false;
1676     int absFocusPos = 0;
1677 
1678     while (!reader_->atEnd())
1679     {
1680         reader_->readNext();
1681 
1682         if (reader_->isEndElement())
1683             break;
1684 
1685         if (reader_->isStartElement())
1686         {
1687             if (reader_->name() == "model")
1688             {
1689                 model = reader_->readElementText();
1690             }
1691             else if (reader_->name() == "vendor")
1692             {
1693                 vendor = reader_->readElementText();
1694             }
1695             else if (reader_->name() == "type")
1696             {
1697                 type = reader_->readElementText();
1698             }
1699             else if (reader_->name() == "offset")
1700             {
1701                 offset = reader_->readElementText().toInt();
1702             }
1703             else if (reader_->name() == "color")
1704             {
1705                 color = reader_->readElementText();
1706             }
1707             else if (reader_->name() == "exposure")
1708             {
1709                 exposure = reader_->readElementText().toDouble();
1710             }
1711             else if (reader_->name() == "lockedFilter")
1712             {
1713                 lockedFilter = reader_->readElementText();
1714             }
1715             else if (reader_->name() == "useAutoFocus")
1716             {
1717                 useAutoFocus = (reader_->readElementText() == "1");
1718             }
1719             else if (reader_->name() == "AbsoluteAutoFocus")
1720             {
1721                 absFocusPos = (reader_->readElementText().toInt());
1722             }
1723         }
1724     }
1725     AddFilter(vendor, model, type, color, offset, exposure, useAutoFocus, lockedFilter, absFocusPos);
1726 }
1727 
GetAllHorizons()1728 QList<ArtificialHorizonEntity *> KSUserDB::GetAllHorizons()
1729 {
1730     QList<ArtificialHorizonEntity *> horizonList;
1731 
1732     m_UserDB.open();
1733     QSqlTableModel regions(nullptr, m_UserDB);
1734     regions.setTable("horizons");
1735     regions.select();
1736 
1737     QSqlTableModel points(nullptr, m_UserDB);
1738 
1739     for (int i = 0; i < regions.rowCount(); ++i)
1740     {
1741         QSqlRecord record         = regions.record(i);
1742         const QString regionTable = record.value("name").toString();
1743         const QString regionName  = record.value("label").toString();
1744 
1745         const int flags           = record.value("enabled").toInt();
1746         const bool enabled        = flags & 0x1 ? true : false;
1747         const bool ceiling        = flags & 0x2 ? true : false;
1748 
1749         points.setTable(regionTable);
1750         points.select();
1751 
1752         std::shared_ptr<LineList> skyList(new LineList());
1753 
1754         ArtificialHorizonEntity *horizon = new ArtificialHorizonEntity;
1755 
1756         horizon->setRegion(regionName);
1757         horizon->setEnabled(enabled);
1758         horizon->setCeiling(ceiling);
1759         horizon->setList(skyList);
1760 
1761         horizonList.append(horizon);
1762 
1763         for (int j = 0; j < points.rowCount(); j++)
1764         {
1765             std::shared_ptr<SkyPoint> p(new SkyPoint());
1766 
1767             record = points.record(j);
1768             p->setAz(record.value(0).toDouble());
1769             p->setAlt(record.value(1).toDouble());
1770             p->HorizontalToEquatorial(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
1771             skyList->append(std::move(p));
1772         }
1773 
1774         points.clear();
1775     }
1776 
1777     regions.clear();
1778     m_UserDB.close();
1779     return horizonList;
1780 }
1781 
DeleteAllHorizons()1782 void KSUserDB::DeleteAllHorizons()
1783 {
1784     m_UserDB.open();
1785     QSqlTableModel regions(nullptr, m_UserDB);
1786     regions.setEditStrategy(QSqlTableModel::OnManualSubmit);
1787     regions.setTable("horizons");
1788     regions.select();
1789 
1790     QSqlQuery query(m_UserDB);
1791 
1792     for (int i = 0; i < regions.rowCount(); ++i)
1793     {
1794         QSqlRecord record  = regions.record(i);
1795         QString tableQuery = QString("DROP TABLE %1").arg(record.value("name").toString());
1796         if (!query.exec(tableQuery))
1797             qCWarning(KSTARS) << query.lastError().text();
1798     }
1799 
1800     regions.removeRows(0, regions.rowCount());
1801     regions.submitAll();
1802 
1803     regions.clear();
1804     m_UserDB.close();
1805 }
1806 
AddHorizon(ArtificialHorizonEntity * horizon)1807 void KSUserDB::AddHorizon(ArtificialHorizonEntity *horizon)
1808 {
1809     m_UserDB.open();
1810     QSqlTableModel regions(nullptr, m_UserDB);
1811     regions.setTable("horizons");
1812 
1813     regions.select();
1814     QString tableName = QString("horizon_%1").arg(regions.rowCount() + 1);
1815 
1816     regions.insertRow(0);
1817     regions.setData(regions.index(0, 1), tableName);
1818     regions.setData(regions.index(0, 2), horizon->region());
1819     int flags = 0;
1820     if (horizon->enabled()) flags |= 0x1;
1821     if (horizon->ceiling()) flags |= 0x2;
1822     regions.setData(regions.index(0, 3), flags);
1823     regions.submitAll();
1824     regions.clear();
1825 
1826     QString tableQuery = QString("CREATE TABLE %1 (Az REAL NOT NULL, Alt REAL NOT NULL)").arg(tableName);
1827     QSqlQuery query(m_UserDB);
1828     query.exec(tableQuery);
1829 
1830     QSqlTableModel points(nullptr, m_UserDB);
1831 
1832     points.setTable(tableName);
1833 
1834     SkyList *skyList = horizon->list()->points();
1835 
1836     for (const auto &item : *skyList)
1837     {
1838         points.select();
1839         QSqlRecord rec(points.record());
1840 
1841         rec.setValue("Az", item->az().Degrees());
1842         rec.setValue("Alt", item->alt().Degrees());
1843         points.insertRecord(-1, rec);
1844     }
1845 
1846     points.submitAll();
1847     points.clear();
1848 
1849     m_UserDB.close();
1850 }
1851 
AddProfile(const QString & name)1852 int KSUserDB::AddProfile(const QString &name)
1853 {
1854     m_UserDB.open();
1855     int id = -1;
1856 
1857     QSqlQuery query(m_UserDB);
1858     bool rc = query.exec(QString("INSERT INTO profile (name) VALUES('%1')").arg(name));
1859 
1860     if (rc == false)
1861         qCWarning(KSTARS) << query.lastQuery() << query.lastError().text();
1862     else
1863         id = query.lastInsertId().toInt();
1864 
1865     m_UserDB.close();
1866 
1867     return id;
1868 }
1869 
DeleteProfile(ProfileInfo * pi)1870 bool KSUserDB::DeleteProfile(ProfileInfo *pi)
1871 {
1872     m_UserDB.open();
1873 
1874     QSqlQuery query(m_UserDB);
1875     bool rc;
1876 
1877     rc = query.exec("DELETE FROM profile WHERE id=" + QString::number(pi->id));
1878 
1879     if (rc == false)
1880         qCWarning(KSTARS) << query.lastQuery() << query.lastError().text();
1881 
1882     m_UserDB.close();
1883 
1884     return rc;
1885 }
1886 
SaveProfile(ProfileInfo * pi)1887 void KSUserDB::SaveProfile(ProfileInfo *pi)
1888 {
1889     // Remove all drivers
1890     DeleteProfileDrivers(pi);
1891 
1892     m_UserDB.open();
1893     QSqlQuery query(m_UserDB);
1894 
1895     // Clear data
1896     if (!query.exec(QString("UPDATE profile SET "
1897                             "host=null,port=null,city=null,province=null,country=null,indiwebmanagerport=NULL,"
1898                             "autoconnect=NULL,portselector=NULL,primaryscope=0,guidescope=0,indihub=0 WHERE id=%1")
1899                     .arg(pi->id)))
1900         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1901 
1902     // Update Name
1903     if (!query.exec(QString("UPDATE profile SET name='%1' WHERE id=%2").arg(pi->name).arg(pi->id)))
1904         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1905 
1906     // Update Remote Data
1907     if (pi->host.isEmpty() == false)
1908     {
1909         if (!query.exec(
1910                     QString("UPDATE profile SET host='%1',port=%2 WHERE id=%3").arg(pi->host).arg((pi->port)).arg(pi->id)))
1911             qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1912 
1913         if (pi->INDIWebManagerPort != -1)
1914         {
1915             if (!query.exec(QString("UPDATE profile SET indiwebmanagerport='%1' WHERE id=%2")
1916                             .arg(pi->INDIWebManagerPort)
1917                             .arg(pi->id)))
1918                 qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1919         }
1920     }
1921 
1922     // Update City Info
1923     if (pi->city.isEmpty() == false)
1924     {
1925         if (!query.exec(QString("UPDATE profile SET city='%1',province='%2',country='%3' WHERE id=%4")
1926                         .arg(pi->city, pi->province, pi->country)
1927                         .arg(pi->id)))
1928         {
1929             qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1930         }
1931     }
1932 
1933     // Update Auto Connect Info
1934     if (!query.exec(QString("UPDATE profile SET autoconnect=%1 WHERE id=%2").arg(pi->autoConnect ? 1 : 0).arg(pi->id)))
1935         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1936 
1937     // Update Port Selector Info
1938     if (!query.exec(QString("UPDATE profile SET portselector=%1 WHERE id=%2").arg(pi->portSelector ? 1 : 0).arg(pi->id)))
1939         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1940 
1941     // Update Guide Application Info
1942     if (!query.exec(QString("UPDATE profile SET guidertype=%1 WHERE id=%2").arg(pi->guidertype).arg(pi->id)))
1943         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1944 
1945     // Update INDI Hub
1946     if (!query.exec(QString("UPDATE profile SET indihub=%1 WHERE id=%2").arg(pi->indihub).arg(pi->id)))
1947         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1948 
1949     // If using external guider
1950     if (pi->guidertype != 0)
1951     {
1952         if (!query.exec(QString("UPDATE profile SET guiderhost='%1' WHERE id=%2").arg(pi->guiderhost).arg(pi->id)))
1953             qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1954         if (!query.exec(QString("UPDATE profile SET guiderport=%1 WHERE id=%2").arg(pi->guiderport).arg(pi->id)))
1955             qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1956     }
1957 
1958     // Update scope selection
1959     if (!query.exec(QString("UPDATE profile SET primaryscope='%1' WHERE id=%2").arg(pi->primaryscope).arg(pi->id)))
1960         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1961     if (!query.exec(QString("UPDATE profile SET guidescope=%1 WHERE id=%2").arg(pi->guidescope).arg(pi->id)))
1962         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1963 
1964     // Update remote drivers
1965     if (!query.exec(QString("UPDATE profile SET remotedrivers='%1' WHERE id=%2").arg(pi->remotedrivers).arg(pi->id)))
1966         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1967 
1968     QMapIterator<QString, QString> i(pi->drivers);
1969     while (i.hasNext())
1970     {
1971         i.next();
1972         if (!query.exec(QString("INSERT INTO driver (label, role, profile) VALUES('%1','%2',%3)")
1973                         .arg(i.value(), i.key())
1974                         .arg(pi->id)))
1975         {
1976             qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
1977         }
1978     }
1979 
1980     /*if (pi->customDrivers.isEmpty() == false && !query.exec(QString("INSERT INTO custom_driver (drivers, profile) VALUES('%1',%2)").arg(pi->customDrivers).arg(pi->id)))
1981         qDebug()  << query.lastQuery() << query.lastError().text();*/
1982 
1983     m_UserDB.close();
1984 }
1985 
GetAllProfiles(QList<std::shared_ptr<ProfileInfo>> & profiles)1986 void KSUserDB::GetAllProfiles(QList<std::shared_ptr<ProfileInfo>> &profiles)
1987 {
1988     m_UserDB.open();
1989     QSqlTableModel profile(nullptr, m_UserDB);
1990     profile.setTable("profile");
1991     profile.select();
1992 
1993     for (int i = 0; i < profile.rowCount(); ++i)
1994     {
1995         QSqlRecord record = profile.record(i);
1996 
1997         int id       = record.value("id").toInt();
1998         QString name = record.value("name").toString();
1999         std::shared_ptr<ProfileInfo> pi(new ProfileInfo(id, name));
2000 
2001         // Add host and port
2002         pi->host = record.value("host").toString();
2003         pi->port = record.value("port").toInt();
2004 
2005         // City info
2006         pi->city     = record.value("city").toString();
2007         pi->province = record.value("province").toString();
2008         pi->country  = record.value("country").toString();
2009 
2010         pi->INDIWebManagerPort = record.value("indiwebmanagerport").toInt();
2011         pi->autoConnect        = (record.value("autoconnect").toInt() == 1);
2012         pi->portSelector       = (record.value("portselector").toInt() == 1);
2013 
2014         pi->indihub = record.value("indihub").toInt();
2015 
2016         pi->guidertype = record.value("guidertype").toInt();
2017         if (pi->guidertype != 0)
2018         {
2019             pi->guiderhost = record.value("guiderhost").toString();
2020             pi->guiderport = record.value("guiderport").toInt();
2021         }
2022 
2023         pi->primaryscope = record.value("primaryscope").toInt();
2024         pi->guidescope = record.value("guidescope").toInt();
2025 
2026         pi->remotedrivers = record.value("remotedrivers").toString();
2027 
2028         GetProfileDrivers(pi.get());
2029         //GetProfileCustomDrivers(pi);
2030 
2031         profiles.append(pi);
2032     }
2033 
2034     profile.clear();
2035     m_UserDB.close();
2036 }
2037 
GetProfileDrivers(ProfileInfo * pi)2038 void KSUserDB::GetProfileDrivers(ProfileInfo *pi)
2039 {
2040     m_UserDB.open();
2041 
2042     QSqlTableModel driver(nullptr, m_UserDB);
2043     driver.setTable("driver");
2044     driver.setFilter("profile=" + QString::number(pi->id));
2045     if (driver.select() == false)
2046         qCWarning(KSTARS) << "Driver select error:" << driver.lastError().text();
2047 
2048     for (int i = 0; i < driver.rowCount(); ++i)
2049     {
2050         QSqlRecord record = driver.record(i);
2051         QString label     = record.value("label").toString();
2052         QString role      = record.value("role").toString();
2053 
2054         pi->drivers[role] = label;
2055     }
2056 
2057     driver.clear();
2058     m_UserDB.close();
2059 }
2060 
2061 /*void KSUserDB::GetProfileCustomDrivers(ProfileInfo* pi)
2062 {
2063     userdb_.open();
2064     QSqlTableModel custom_driver(0, userdb_);
2065     custom_driver.setTable("driver");
2066     custom_driver.setFilter("profile=" + QString::number(pi->id));
2067     if (custom_driver.select() == false)
2068         qDebug() << "custom driver select error: " << custom_driver.query().lastQuery() << custom_driver.lastError().text();
2069 
2070     QSqlRecord record = custom_driver.record(0);
2071     pi->customDrivers   = record.value("drivers").toString();
2072 
2073     custom_driver.clear();
2074     userdb_.close();
2075 }*/
2076 
DeleteProfileDrivers(ProfileInfo * pi)2077 void KSUserDB::DeleteProfileDrivers(ProfileInfo *pi)
2078 {
2079     m_UserDB.open();
2080 
2081     QSqlQuery query(m_UserDB);
2082 
2083     /*if (!query.exec("DELETE FROM custom_driver WHERE profile=" + QString::number(pi->id)))
2084         qDebug() << query.lastQuery() << query.lastError().text();*/
2085 
2086     if (!query.exec("DELETE FROM driver WHERE profile=" + QString::number(pi->id)))
2087         qCWarning(KSTARS) << query.executedQuery() << query.lastError().text();
2088 
2089     m_UserDB.close();
2090 }
2091