19 #include "kstars/version.h"
23 skydb_ = QSqlDatabase::addDatabase(
"QSQLITE",
"skydb");
24 QString dbfile = KStandardDirs::locateLocal(
"appdata",
25 QString(
"skycomponents.db"));
27 bool first_run =
false;
28 if (!testdb.exists()) {
29 kDebug()<< i18n(
"DSO DB does not exist!");
32 skydb_.setDatabaseName(dbfile);
34 kWarning() << i18n(
"Unable to open DSO database file!");
35 kWarning() << LastError();
37 kDebug() << i18n(
"Opened the DSO Database. Ready!");
38 if (first_run ==
true) {
46 void CatalogDB::FirstRun() {
47 kWarning() << i18n(
"Rebuilding Additional Sky Catalog Database");
48 QVector<QString> tables;
49 tables.append(
"CREATE TABLE Version ("
50 "Version CHAR DEFAULT NULL)");
51 tables.append(
"INSERT INTO Version VALUES (\"" KSTARS_VERSION
"\")");
52 tables.append(
"CREATE TABLE ObjectDesignation ("
53 "id INTEGER NOT NULL DEFAULT NULL PRIMARY KEY,"
54 "id_Catalog INTEGER DEFAULT NULL REFERENCES Catalog (id),"
55 "UID_DSO INTEGER DEFAULT NULL REFERENCES DSO (UID),"
56 "LongName MEDIUMTEXT DEFAULT NULL,"
57 "IDNumber INTEGER DEFAULT NULL,"
58 "Trixel INTEGER NULL)");
62 tables.append(
"CREATE TABLE Catalog ("
63 "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT,"
64 "Name CHAR NOT NULL DEFAULT 'NULL',"
65 "Prefix CHAR DEFAULT 'NULL',"
66 "Color CHAR DEFAULT '#CC0000',"
67 "Epoch FLOAT DEFAULT 2000.0,"
68 "Author CHAR DEFAULT NULL,"
69 "License MEDIUMTEXT DEFAULT NULL,"
70 "FluxFreq CHAR DEFAULT 'NULL',"
71 "FluxUnit CHAR DEFAULT 'NULL')");
73 tables.append(
"CREATE TABLE DSO ("
74 "UID INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT,"
75 "RA DOUBLE NOT NULL DEFAULT 0.0,"
76 "Dec DOUBLE DEFAULT 0.0,"
79 "Type INTEGER DEFAULT NULL,"
80 "Magnitude DECIMAL DEFAULT NULL,"
81 "PositionAngle INTEGER DEFAULT NULL,"
82 "MajorAxis FLOAT NOT NULL DEFAULT NULL,"
83 "MinorAxis FLOAT DEFAULT NULL,"
84 "Flux FLOAT DEFAULT NULL,"
85 "Add1 VARCHAR DEFAULT NULL,"
86 "Add2 INTEGER DEFAULT NULL,"
87 "Add3 INTEGER DEFAULT NULL,"
88 "Add4 INTEGER DEFAULT NULL)");
90 for (
int i = 0; i < tables.count(); ++i) {
91 QSqlQuery query(skydb_);
92 if (!query.exec(tables[i])) {
93 kDebug() << query.lastError();
105 QSqlError CatalogDB::LastError() {
107 return skydb_.lastError();
113 return &catalog_list_;
118 catalog_list_.clear();
120 QSqlTableModel catalog(0, skydb_);
121 catalog.setTable(
"Catalog");
124 for (
int i = 0; i < catalog.rowCount(); ++i) {
125 QSqlRecord record = catalog.record(i);
126 QString name = record.value(
"Name").toString();
127 catalog_list_.append(name);
139 int CatalogDB::FindCatalog(
const QString& catalog_name) {
141 QSqlTableModel catalog(0, skydb_);
143 catalog.setTable(
"Catalog");
144 catalog.setFilter(
"Name LIKE \'" + catalog_name +
"\'");
147 int catalog_count = catalog.rowCount();
148 QSqlRecord record = catalog.record(0);
151 if (catalog_count > 0)
152 returnval = record.value(
"id").toInt();
161 void CatalogDB::AddCatalog(
const CatalogData& catalog_data) {
163 QSqlTableModel cat_entry(0, skydb_);
164 cat_entry.setTable(
"Catalog");
167 cat_entry.insertRows(row, 1);
169 cat_entry.setData(cat_entry.index(row, 1), catalog_data.
catalog_name);
170 cat_entry.setData(cat_entry.index(row, 2), catalog_data.
prefix);
171 cat_entry.setData(cat_entry.index(row, 3), catalog_data.
color);
172 cat_entry.setData(cat_entry.index(row, 4), catalog_data.
epoch);
173 cat_entry.setData(cat_entry.index(row, 5), catalog_data.
author);
174 cat_entry.setData(cat_entry.index(row, 6), catalog_data.
license);
175 cat_entry.setData(cat_entry.index(row, 7), catalog_data.
fluxfreq);
176 cat_entry.setData(cat_entry.index(row, 8), catalog_data.
fluxunit);
178 cat_entry.submitAll();
186 ClearDSOEntries(FindCatalog(catalog_name));
189 QSqlTableModel catalog(0, skydb_);
192 catalog.setTable(
"Catalog");
193 catalog.setFilter(
"Name LIKE \'" + catalog_name +
"\'");
196 catalog.removeRows(0, catalog.rowCount());
205 void CatalogDB::ClearDSOEntries(
int catalog_id) {
208 QStringList del_query;
215 del_query.append(
"DELETE FROM ObjectDesignation WHERE id_Catalog = " +
216 QString::number(catalog_id));
218 for (
int i = 0; i < del_query.count(); ++i) {
219 QSqlQuery query(skydb_);
220 if (!query.exec(del_query[i])) {
221 kDebug() << query.lastError();
229 const double magnitude) {
236 QSqlTableModel dsoentries(0, skydb_);
239 "((RA - " + QString().setNum(ra) +
") between -0.0016 and 0.0016) and "
240 "((Dec - " + QString().setNum(dec) +
") between -0.0016 and 0.0016) and"
241 "((Magnitude - " + QString().setNum(magnitude) +
") between -0.1 and 0.1)";
243 dsoentries.setTable(
"DSO");
244 dsoentries.setFilter(filter);
247 int entry_count = dsoentries.rowCount();
248 QSqlRecord record = dsoentries.record(0);
252 returnval = record.value(
"UID").toInt();
266 catalog_entry.
ra == 0.0 ||
268 catalog_entry.
dec == 0.0) {
269 kDebug() <<
"Attempt to add incorrect ra & dec with ID:"
270 << catalog_entry.
ID <<
" Long Name: "
285 QSqlQuery add_query(skydb_);
286 add_query.prepare(
"INSERT INTO DSO (RA, Dec, Type, Magnitude, PositionAngle,"
287 " MajorAxis, MinorAxis, Flux) VALUES (:RA, :Dec, :Type,"
288 " :Magnitude, :PositionAngle, :MajorAxis, :MinorAxis,"
290 add_query.bindValue(
"RA", catalog_entry.
ra);
291 add_query.bindValue(
"Dec", catalog_entry.
dec);
292 add_query.bindValue(
"Type", catalog_entry.
type);
293 add_query.bindValue(
"Magnitude", catalog_entry.
magnitude);
294 add_query.bindValue(
"PositionAngle", catalog_entry.
position_angle);
295 add_query.bindValue(
"MajorAxis", catalog_entry.
major_axis);
296 add_query.bindValue(
"MinorAxis", catalog_entry.
minor_axis);
297 add_query.bindValue(
"Flux", catalog_entry.
flux);
298 if (!add_query.exec()) {
299 kWarning() <<
"Custom Catalog Insert Query FAILED!";
300 kWarning() << add_query.lastQuery();
304 rowuid = add_query.lastInsertId().toInt();
322 QSqlQuery add_od(skydb_);
323 add_od.prepare(
"INSERT INTO ObjectDesignation (id_Catalog, UID_DSO, LongName"
324 ", IDNumber) VALUES (:catid, :rowuid, :longname, :id)");
325 add_od.bindValue(
"catid", catid);
326 add_od.bindValue(
"rowuid", rowuid);
327 add_od.bindValue(
"longname", catalog_entry.
long_name);
328 add_od.bindValue(
"id", catalog_entry.
ID);
329 if (!add_od.exec()) {
330 kWarning() << add_od.lastQuery();
331 kWarning() << skydb_.lastError();
340 QDir::setCurrent(QDir::homePath());
341 QString filename = fname;
344 if (filename.at(0) ==
'~')
345 filename = QDir::homePath() + filename.mid(1, filename.length());
347 QFile ccFile(filename);
349 if (ccFile.open(QIODevice::ReadOnly)) {
351 QString catalog_name;
357 for (
int times = 10; times >= 0 && !stream.atEnd(); --times)
358 lines.append(stream.readLine());
364 if (lines.size() < 1 ||
365 !ParseCatalogInfoToDB(lines, columns, catalog_name, delimiter)) {
366 kWarning() <<
"Issue in catalog file header: " << filename;
381 buildParserSequence(columns);
384 KSParser catalog_text_parser(filename,
'#', sequence, delimiter);
386 QHash<QString, QVariant> row_content;
392 dms read_ra(row_content[
"RA"].toString(),
false);
393 dms read_dec(row_content[
"Dc"].toString(),
true);
394 kDebug()<<row_content[
"Nm"].toString();
396 catalog_entry.
ID = row_content[
"ID"].toInt();
397 catalog_entry.
long_name = row_content[
"Nm"].toString();
400 catalog_entry.
type = row_content[
"Tp"].toInt();
401 catalog_entry.
magnitude = row_content[
"Mg"].toFloat();
403 catalog_entry.
major_axis = row_content[
"Mj"].toFloat();
404 catalog_entry.
minor_axis = row_content[
"Mn"].toFloat();
405 catalog_entry.
flux = row_content[
"Flux"].toFloat();
414 bool CatalogDB::ParseCatalogInfoToDB(
const QStringList &lines,
415 QStringList &columns,
416 QString &catalog_name,
425 bool foundDataColumns =
false;
430 QString catPrefix, catColor, catFluxFreq, catFluxUnit;
432 bool showerrs =
false;
434 catalog_name.clear();
443 for (; i < lines.size(); ++i) {
444 QString
d(lines.at(i));
445 if (
d.left(1) !=
"#")
break;
447 int idelimiter =
d.indexOf(
"# Delimiter: ");
448 int iname =
d.indexOf(
"# Name: ");
449 int iprefix =
d.indexOf(
"# Prefix: ");
450 int icolor =
d.indexOf(
"# Color: ");
451 int iepoch =
d.indexOf(
"# Epoch: ");
452 int ifluxfreq =
d.indexOf(
"# Flux Frequency: ");
453 int ifluxunit =
d.indexOf(
"# Flux Unit: ");
455 if (idelimiter == 0) {
456 idelimiter =
d.indexOf(
":") + 2;
457 kWarning() << idelimiter <<
d;
458 if (delimiter ==
'\0') {
459 delimiter = d.mid(idelimiter).at(0).toAscii();
462 errs.append(i18n(
"Parsing header: ") +
463 i18n(
"Extra Delimiter field in header: %1."
464 " Will be ignored", d.mid(idelimiter)));
466 }
else if (iname == 0) {
467 iname = d.indexOf(
":")+2;
468 if (catalog_name.isEmpty()) {
469 catalog_name = d.mid(iname);
472 errs.append(i18n(
"Parsing header: ") +
473 i18n(
"Extra Name field in header: %1."
474 " Will be ignored", d.mid(iname)));
476 }
else if (iprefix == 0) {
477 iprefix = d.indexOf(
":")+2;
478 if (catPrefix.isEmpty()) {
479 catPrefix = d.mid(iprefix);
482 errs.append(i18n(
"Parsing header: ") +
483 i18n(
"Extra Prefix field in header: %1."
484 " Will be ignored", d.mid(iprefix)));
486 }
else if (icolor == 0) {
487 icolor = d.indexOf(
":")+2;
488 if (catColor.isEmpty()) {
489 catColor = d.mid(icolor);
492 errs.append(i18n(
"Parsing header: ") +
493 i18n(
"Extra Color field in header: %1."
494 " Will be ignored", d.mid(icolor)));
496 }
else if (iepoch == 0) {
497 iepoch = d.indexOf(
":")+2;
498 if (catEpoch == 0.) {
500 catEpoch = d.mid(iepoch).toFloat(&ok);
503 errs.append(i18n(
"Parsing header: ") +
504 i18n(
"Could not convert Epoch to float: "
505 "%1. Using 2000. instead",
510 }
else if (ifluxfreq == 0) {
511 ifluxfreq = d.indexOf(
":")+2;
512 if (catFluxFreq.isEmpty()) {
513 catFluxFreq = d.mid(ifluxfreq);
516 errs.append(i18n(
"Parsing header: ") +
517 i18n(
"Extra Flux Frequency field in header:"
518 " %1. Will be ignored",
521 }
else if (ifluxunit == 0) {
523 ifluxunit = d.indexOf(
":") + 2;
525 if (catFluxUnit.isEmpty()) {
526 catFluxUnit = d.mid(ifluxunit);
529 errs.append(i18n(
"Parsing header: ") +
530 i18n(
"Extra Flux Unit field in "
531 "header: %1. Will be ignored",
534 }
else if (!foundDataColumns) {
542 QStringList fields = d.split(
' ', QString::SkipEmptyParts);
547 QStringList master(fields);
549 for (
int j = 0; j < fields.size(); ++j) {
550 QString s(fields.at(j));
551 if (master.contains(s)) {
558 master.removeAt(master.indexOf(s));
561 }
else if (fields.contains(s)) {
564 errs.append(i18n(
"Parsing header: ") +
565 i18n(
"Duplicate data field descriptor "
566 "\"%1\" will be ignored", s));
570 errs.append(i18n(
"Parsing header: ") +
571 i18n(
"Invalid data field descriptor "
572 "\"%1\" will be ignored", s));
576 if (ncol) foundDataColumns =
true;
581 if (delimiter ==
'\0')
584 if (!foundDataColumns) {
586 errs.append(i18n(
"Parsing header: ") +
587 i18n(
"No valid column descriptors found. Exiting"));
591 if (i == lines.size()) {
592 if (showerrs) errs.append(i18n(
"Parsing header: ") +
593 i18n(
"No data lines found after"
594 " header. Exiting."));
598 if (catalog_name.isEmpty()) {
599 if (showerrs) errs.append(i18n(
"Parsing header: ") +
600 i18n(
"No Catalog Name specified;"
601 " setting to \"Custom\""));
602 catalog_name = i18n(
"Custom");
604 if (catPrefix.isEmpty()) {
605 if (showerrs) errs.append(i18n(
"Parsing header: ") +
606 i18n(
"No Catalog Prefix specified"
607 "; setting to \"CC\""));
610 if (catColor.isEmpty()) {
611 if (showerrs) errs.append(i18n(
"Parsing header: ") +
612 i18n(
"No Catalog Color specified"
613 "; setting to Red"));
614 catColor =
"#CC0000";
616 if (catEpoch == 0.) {
617 if (showerrs) errs.append(i18n(
"Parsing header: ") +
618 i18n(
"No Catalog Epoch specified"
619 "; assuming 2000."));
624 if (FindCatalog(catalog_name) != -1) {
625 if (KMessageBox::warningYesNo(0,
626 i18n(
"A catalog of the same name already exists. "
627 "Overwrite contents? If you press yes, the"
628 " new catalog will erase the old one!"),
629 i18n(
"Overwrite Existing Catalog"))
630 == KMessageBox::No) {
631 KMessageBox::information(0,
"Catalog addition cancelled.");
642 new_catalog.
prefix = catPrefix;
643 new_catalog.
color = catColor;
644 new_catalog.
epoch = catEpoch;
648 AddCatalog(new_catalog);
657 QSqlTableModel catalog(0, skydb_);
658 catalog.setTable(
"Catalog");
659 catalog.setFilter(
"Name LIKE \'" + catalog_name +
"\'");
662 QSqlRecord record = catalog.record(0);
663 load_catalog.
prefix = record.value(
"Prefix").toString();
664 load_catalog.
color = record.value(
"Color").toString();
665 load_catalog.
fluxfreq = record.value(
"FluxFreq").toString();
666 load_catalog.
fluxunit = record.value(
"FluxUnit").toString();
667 load_catalog.
epoch = record.value(
"Epoch").toFloat();
676 QList < QPair <int, QString> > &object_names,
679 QString selected_catalog = QString::number(FindCatalog(catalog));
681 QSqlQuery get_query(skydb_);
682 get_query.prepare(
"SELECT Epoch, Type, RA, Dec, Magnitude, Prefix, "
683 "IDNumber, LongName, MajorAxis, MinorAxis, "
684 "PositionAngle, Flux FROM ObjectDesignation JOIN DSO "
685 "JOIN Catalog WHERE Catalog.id = :catID AND "
686 "ObjectDesignation.id_Catalog = Catalog.id AND "
687 "ObjectDesignation.UID_DSO = DSO.UID");
688 get_query.bindValue(
"catID", selected_catalog);
694 if (!get_query.exec()) {
695 kWarning() << get_query.lastQuery();
696 kWarning() << get_query.lastError();
699 while (get_query.next()) {
701 int cat_epoch = get_query.value(0).toInt();
702 unsigned char iType = get_query.value(1).toInt();
703 dms RA(get_query.value(2).toDouble());
704 dms Dec(get_query.value(3).toDouble());
705 float mag = get_query.value(4).toFloat();
706 QString catPrefix = get_query.value(5).toString();
707 int id_number_in_catalog = get_query.value(6).toInt();
708 QString lname = get_query.value(7).toString();
709 float a = get_query.value(8).toFloat();
710 float b = get_query.value(9).toFloat();
711 float PA = get_query.value(10).toFloat();
712 float flux = get_query.value(11).toFloat();
714 QString name = catPrefix +
' ' + QString::number(id_number_in_catalog);
718 if (cat_epoch == 1950) {
722 }
else if (cat_epoch == 2000) {
729 kWarning() <<
"Unknown epoch while dealing with custom "
730 "catalog. Will ignore the epoch and assume"
742 name, QString(), lname,
743 catPrefix, a, b, -PA);
750 if (!name.isEmpty()) {
751 object_names.append(qMakePair<int,QString>(iType, name));
755 if (!lname.isEmpty() && lname != name) {
756 object_names.append(qMakePair<int,QString>(iType, lname));
766 buildParserSequence(
const QStringList& Columns) {
768 QStringList::const_iterator iter = Columns.begin();
770 while (iter != Columns.end()) {
774 if (*iter == QString(
"ID"))
776 else if (*iter == QString(
"RA"))
778 else if (*iter == QString(
"Dc"))
780 else if (*iter == QString(
"Tp"))
782 else if (*iter == QString(
"Nm"))
784 else if (*iter == QString(
"Mg"))
786 else if (*iter == QString(
"Flux"))
788 else if (*iter == QString(
"Mj"))
790 else if (*iter == QString(
"Mn"))
792 else if (*iter == QString(
"PA"))
794 else if (*iter == QString(
"Ig"))
797 sequence.append(qMakePair(*iter, current_type));
bool HasNextRow()
Returns True if there are more rows to be read.
void set(const dms &r, const dms &d)
Sets RA, Dec and RA0, Dec0 according to arguments.
bool AddCatalogContents(const QString &filename)
Add contents of custom catalog to the program database.
Generic class for text file parsers used in KStars.
Class to store details of a Catalog Entry.
const double & Degrees() const
void GetAllObjects(const QString &catalog_name, QList< SkyObject * > &sky_list, QList< QPair< int, QString > > &object_names, CatalogComponent *catalog_pointer)
Creates objects of type SkyObject and assigns them to references.
static const double EBROKEN_DOUBLE
These are the values used in case of error in conversion.
void AddEntry(const CatalogEntryData &catalog_entry)
Used to add a cross referenced entry into the database.
void RefreshCatalogList()
Rechecks the database and builds the Catalog listing.
DataTypes
DataTypes for building sequence D_QSTRING QString Type D_INT Integer Type D_FLOAT Floating Point Type...
void setCustomCatalog(CatalogComponent *s)
Set the reference to the custom catalog component, if any.
QStringList * Catalogs()
Accessor for list of all available catalogs in db.
The sky coordinates of a point in the sky.
Add the catalog with given details into the database.
Represents a custom user-defined catalog.
An angle, stored as degrees, but expressible in many ways.
~CatalogDB()
Attempt to close database and remove reference from the DB List.
Provides all necessary information about a deep-sky object: data inherited from SkyObject (coordinate...
bool Initialize()
Initializes the database and sets up pointers to Catalog DB Performs the following actions: ...
void setFlux(const float &f)
Set the integrated flux value of the object.
void GetCatalogData(const QString &catalog_name, CatalogData &catalog_data)
Get information about the catalog like Prefix etc.
QHash< QString, QVariant > ReadNextRow()
Generic function used to read the next row of a text file.
This is a subclass of SkyObject.
void B1950ToJ2000(void)
Exact precession from Besselian epoch 1950 to epoch J2000.
int FindFuzzyEntry(const double ra, const double dec, const double magnitude)
returns the id of the row if it matches with certain fuzz.
void RemoveCatalog(const QString &catalog_name)
Removes the catalog from the database and refreshes the listing.