11#include <QMutexLocker>
12#include <QTemporaryDir>
13#include <qsqldatabase.h>
14#include "cachingdms.h"
15#include "catalogsdb.h"
19#include "final_action.h"
20#include "sqlstatements.cpp"
22using namespace CatalogsDB;
27int get_connection_index()
38 if (!
query.prepare(statement))
40 throw DatabaseError(
"Can't prepare query!", DatabaseError::ErrorType::PREPARE,
50std::pair<bool, QString> migrate_db(
const int version,
QSqlDatabase &db,
53 if (prefix.size() > 0)
60 const auto success =
add_ts.exec(
QString(
"ALTER TABLE %1catalogs ADD COLUMN "
61 "timestamp DEFAULT NULL")
64 return {
false,
add_ts.lastError().text() };
69 if (version < 3 && prefix ==
"")
72 const auto success =
add_colors.exec(SqlStatements::create_colors_table);
74 return {
false,
add_colors.lastError().text() };
89 DatabaseError::ErrorType::OPEN, m_db.
lastError());
93 std::tie(m_db_version, m_htmesh_level, init) = get_db_meta();
95 if (!init && m_db_version > 0 && m_db_version < SqlStatements::current_db_version)
103 QString(
"Could not backup dso database before upgrading."),
104 DatabaseError::ErrorType::VERSION,
QSqlError{});
107 const auto &success = migrate_db(m_db_version, m_db);
110 m_db_version = SqlStatements::current_db_version;
118 DatabaseError::ErrorType::VERSION,
124 QString(
"Wrong database version. Expected %1 and got %2 and "
125 "migration is not possible.")
126 .arg(SqlStatements::current_db_version)
128 DatabaseError::ErrorType::VERSION, success.second);
138 if (!initialize_db())
141 DatabaseError::ErrorType::INIT, m_db.
lastError());
148 SqlStatements::user_catalog_name,
true,
true, 1);
152 DatabaseError::ErrorType::CREATE_CATALOG,
res.second);
159 DatabaseError::ErrorType::CREATE_CATALOG,
166 DatabaseError::ErrorType::CREATE_MASTER,
171 m_q_cat_by_id = make_query(m_db, SqlStatements::get_catalog_by_id,
true);
172 m_q_obj_by_trixel = make_query(m_db, SqlStatements::dso_by_trixel,
false);
173 m_q_obj_by_trixel_no_nulls = make_query(m_db, SqlStatements::dso_by_trixel_no_nulls,
false);
174 m_q_obj_by_trixel_null_mag = make_query(m_db, SqlStatements::dso_by_trixel_null_mag,
false);
175 m_q_obj_by_name = make_query(m_db, SqlStatements::dso_by_name,
true);
176 m_q_obj_by_name_exact = make_query(m_db, SqlStatements::dso_by_name_exact,
true);
177 m_q_obj_by_lim = make_query(m_db, SqlStatements::dso_by_lim,
true);
178 m_q_obj_by_maglim = make_query(m_db, SqlStatements::dso_by_maglim,
true);
179 m_q_obj_by_maglim_and_type =
180 make_query(m_db, SqlStatements::dso_by_maglim_and_type,
true);
181 m_q_obj_by_oid = make_query(m_db, SqlStatements::dso_by_oid,
true);
186bool DBManager::initialize_db()
188 if (m_db_version < 0 || m_htmesh_level < 1)
189 throw std::runtime_error(
"DBManager not initialized properly, m_db_vesion and "
190 "m_htmesh_level have to be set.");
192 if (!m_db.
exec(SqlStatements::create_meta_table).
isActive())
195 if (!m_db.
exec(SqlStatements::create_colors_table).
isActive())
207 return m_db.
exec(SqlStatements::create_catalog_list_table).
isActive();
210std::tuple<int, int, bool> DBManager::get_db_meta()
212 auto query = m_db.
exec(SqlStatements::get_meta);
216 query.value(2).toBool() };
218 return { SqlStatements::current_db_version, SqlStatements::default_htmesh_level,
225 SqlStatements::get_catalog_ids);
227 std::vector<int>
ids;
240 const auto &
ids = get_catalog_ids();
250 query.exec(
QString(
"DROP VIEW IF EXISTS ") + SqlStatements::all_catalog_view);
262 view += SqlStatements::all_catalog_view;
266 for (
auto *field : SqlStatements::catalog_collumns)
288 result &= query.exec(view);
294 query.bindValue(
":id",
cat.id);
295 query.bindValue(
":name",
cat.name);
296 query.bindValue(
":mut",
cat.mut);
297 query.bindValue(
":enabled",
cat.enabled);
298 query.bindValue(
":precedence",
cat.precedence);
299 query.bindValue(
":author",
cat.author);
300 query.bindValue(
":source",
cat.source);
301 query.bindValue(
":description",
cat.description);
302 query.bindValue(
":version",
cat.version);
303 query.bindValue(
":color",
cat.color);
304 query.bindValue(
":license",
cat.license);
305 query.bindValue(
":maintainer",
cat.maintainer);
306 query.bindValue(
":timestamp",
cat.timestamp);
310 const int id,
const QString &name,
const bool mut,
const bool enabled,
311 const double precedence,
const QString &author,
const QString &source,
312 const QString &description,
const int version,
const QString &color,
315 return register_catalog({ id, name, precedence, author, source, description, mut,
316 enabled, version, color, license, maintainer, timestamp });
322 return {
false,
i18n(
"Catalog with that ID already exists.") };
326 if (!
query.exec(SqlStatements::create_catalog_table(
cat.id)))
328 return {
false,
query.lastError().text() };
331 query.prepare(SqlStatements::insert_catalog);
332 bind_catalog(query,
cat);
334 return {
query.exec(),
query.lastError().text() };
346 if (!query.exec(SqlStatements::drop_master))
351 if (!query.exec(SqlStatements::create_master))
357 success &= query.exec(SqlStatements::create_master_trixel_index);
358 success &= query.exec(SqlStatements::create_master_mag_index);
359 success &= query.exec(SqlStatements::create_master_type_index);
360 success &= query.exec(SqlStatements::create_master_name_index);
366 return { query.value(
"id").
toInt(),
367 query.value(
"name").toString(),
368 query.value(
"precedence").toDouble(),
369 query.value(
"author").toString(),
370 query.value(
"source").toString(),
371 query.value(
"description").toString(),
372 query.value(
"mut").toBool(),
373 query.value(
"enabled").toBool(),
374 query.value(
"version").
toInt(),
375 query.value(
"color").toString(),
376 query.value(
"license").toString(),
377 query.value(
"maintainer").toString(),
378 query.value(
"timestamp").toDateTime() };
386 if (!m_q_cat_by_id.
exec())
387 return {
false, {} };
389 if (!m_q_cat_by_id.
next())
390 return {
false, {} };
395 return {
true,
cat };
407 if (!m_q_cat_by_id.
exec())
410 return m_q_cat_by_id.
next();
429 const double ra =
query.value(2).toDouble();
430 const double dec =
query.value(3).toDouble();
431 const float mag =
query.isNull(4) ? NaN::f :
query.value(4).toFloat();
435 const float major =
query.value(8).toFloat();
436 const float minor =
query.value(9).toFloat();
438 const float flux =
query.value(11).toFloat();
447CatalogObjectVector DBManager::_get_objects_in_trixel_generic(
QSqlQuery &query,
const int trixel)
450 query.bindValue(0, trixel);
454 QString(
"The by-trixel query for objects in trixel=%1 failed.")
456 DatabaseError::ErrorType::UNKNOWN,
query.lastError());
458 CatalogObjectVector objects;
468 objects.reserve(count);
470 while (
query.previous())
472 objects.push_back(read_catalogobject(query));
481CatalogObjectList DBManager::fetch_objects(
QSqlQuery &query)
const
483 CatalogObjectList objects;
491 if (!
query.isActive())
494 objects.push_back(read_catalogobject(query));
506 return CatalogObjectList();
509 m_q_obj_by_name_exact.
bindValue(
":name", name);
510 CatalogObjectList
objs { fetch_objects(m_q_obj_by_name_exact) };
517 m_q_obj_by_name.
bindValue(
":name", name);
518 m_q_obj_by_name.
bindValue(
":limit",
int(limit -
objs.size()));
520 CatalogObjectList
moreObjects = fetch_objects(m_q_obj_by_name);
527 const QString &name,
const int limit)
531 query.prepare(SqlStatements::dso_by_name_and_catalog(
catalog_id));
532 query.bindValue(
":name", name);
533 query.bindValue(
":limit", limit);
536 return fetch_objects(query);
539std::pair<bool, CatalogObject> DBManager::read_first_object(
QSqlQuery &query)
const
541 if (!query.exec() || !query.first())
542 return {
false, {} };
544 return {
true, read_catalogobject(query) };
557 return read_first_object(m_q_obj_by_oid);
567 query.bindValue(0, oid);
569 return read_first_object(query);
575 m_q_obj_by_maglim.
bindValue(
":maglim", maglim);
576 m_q_obj_by_maglim.
bindValue(
":limit", limit);
578 return fetch_objects(m_q_obj_by_maglim);
586 return fetch_objects(m_q_obj_by_lim);
592 m_q_obj_by_maglim_and_type.
bindValue(
":type", type);
593 m_q_obj_by_maglim_and_type.
bindValue(
":limit", limit);
594 m_q_obj_by_maglim_and_type.
bindValue(
":maglim", maglim);
596 return fetch_objects(m_q_obj_by_maglim_and_type);
605 query.prepare(SqlStatements::dso_in_catalog_by_maglim(
catalog_id));
606 query.bindValue(
":type", type);
607 query.bindValue(
":limit", limit);
608 query.bindValue(
":maglim", maglim);
609 return fetch_objects(query);
616 return {
false,
i18n(
"Catalog could not be found.") };
618 const auto &
cat = success.second;
619 if (
cat.enabled == enabled)
623 query.prepare(SqlStatements::enable_disable_catalog);
624 query.bindValue(
":enabled", enabled);
625 query.bindValue(
":id",
id);
637 std::transform(
ids.cbegin(),
ids.cend(), std::back_inserter(
catalogs),
640 const auto &found = get_catalog(id);
646 QString(
"Could not retrieve the catalog with id=%1").arg(id));
656 const float a,
const float b,
const double pa,
657 const float flux, Trixel trixel,
660 query.prepare(SqlStatements::insert_dso(
catalog_id));
662 query.bindValue(
":hash",
new_id);
663 query.bindValue(
":oid",
new_id);
664 query.bindValue(
":type",
static_cast<int>(t));
665 query.bindValue(
":ra", r.
Degrees());
666 query.bindValue(
":dec", d.Degrees());
667 query.bindValue(
":magnitude", (
m < 99 && !std::isnan(
m)) ?
m :
QVariant{});
668 query.bindValue(
":name", n);
670 query.bindValue(
":catalog_identifier",
672 query.bindValue(
":major_axis", a > 0 ? a :
QVariant{});
673 query.bindValue(
":minor_axis", b > 0 ? b :
QVariant{});
674 query.bindValue(
":position_angle", pa > 0 ? pa :
QVariant{});
675 query.bindValue(
":flux", flux > 0 ? flux :
QVariant{});
676 query.bindValue(
":trixel", trixel);
697std::pair<bool, QString>
701 const float a,
const float b,
const double pa,
const float flux)
706 return {
false,
i18n(
"Catalog with id=%1 not found.",
catalog_id) };
708 if (!success.second.mut)
709 return {
false,
i18n(
"Catalog is immutable!") };
718 bind_catalogobject(query,
catalog_id, t, r, d, n,
m,
lname,
catalog_identifier, a, b,
719 pa, flux, trixel,
new_id);
723 auto err = query.lastError().text();
724 if (
err.startsWith(
"UNIQUE"))
725 err =
i18n(
"The object is already in the catalog!");
727 return {
false,
i18n(
"Could not insert object! %1",
err) };
739 query.prepare(SqlStatements::remove_dso(
catalog_id));
740 query.bindValue(
":oid",
id);
743 return {
false, query.lastError().text() };
753 return {
false,
i18n(
"Catalog could not be found.") };
757 return {
false,
i18n(
"Output file is not writable.") };
765 i18n(
"Could not attach output file.<br>%1", query.lastError().text()) };
771 query.exec(
"DETACH tmp");
776 return {
false,
i18n(
"Could not copy catalog to output file.<br>%1")
777 .
arg(query.lastError().text()) };
779 if (!query.exec(SqlStatements::create_catalog_registry(
"tmp.catalogs")))
780 return {
false,
i18n(
"Could not create catalog registry in output file.<br>%1")
781 .
arg(query.lastError().text()) };
783 query.prepare(SqlStatements::insert_into_catalog_registry(
"tmp.catalogs"));
785 auto cat = found.second;
787 bind_catalog(query,
cat);
792 i18n(
"Could not insert catalog into registry in output file.<br>%1")
793 .
arg(query.lastError().text()) };
796 if (!query.exec(
QString(
"PRAGMA tmp.user_version = %1").arg(m_db_version)))
798 return {
false,
i18n(
"Could not insert set exported database version.<br>%1")
799 .
arg(query.lastError().text()) };
802 if (!query.exec(
QString(
"PRAGMA tmp.application_id = %1").arg(application_id)))
805 i18n(
"Could not insert set exported database application id.<br>%1")
806 .
arg(query.lastError().text()) };
813 const bool overwrite)
821 return {
false,
i18n(
"Catalog file is not readable.") };
830 i18n(
"Could not attach input file.<br>%1", query.lastError().text()) };
836 query.exec(
"DETACH tmp");
839 if (!query.exec(
"PRAGMA tmp.application_id") || !query.next() ||
840 query.value(0).
toInt() != CatalogsDB::application_id)
841 return {
false,
i18n(
"Invalid catalog file.") };
843 if (!query.exec(
"PRAGMA tmp.user_version") || !query.next() ||
844 query.value(0).
toInt() < m_db_version)
846 const auto &success = migrate_db(query.value(0).
toInt(), m_db,
"tmp");
848 return {
false,
i18n(
"Could not migrate old catalog format.<br>%1",
852 if (!query.exec(
"SELECT id FROM tmp.catalogs LIMIT 1") || !query.next())
854 i18n(
"Could read the catalog id.<br>%1", query.lastError().text()) };
856 const auto id = query.value(0).
toInt();
863 if (!overwrite && found.second.mut)
864 return {
false,
i18n(
"Catalog already exists in the database!") };
866 auto success = remove_catalog_force(
id);
875 "INSERT INTO catalogs (id, name, mut, enabled, precedence, author, source, "
876 "description, version, color, license, maintainer, timestamp) SELECT id, "
877 "name, mut, enabled, precedence, author, source, description, version, "
878 "color, license, maintainer, timestamp FROM tmp.catalogs LIMIT 1") ||
879 !query.exec(
QString(
"CREATE TABLE cat_%1 AS SELECT * FROM tmp.cat").arg(
id)))
881 i18n(
"Could not import the catalog.<br>%1", query.lastError().text()) };
886 return {
false,
i18n(
"Could not refresh the master catalog.<br>",
894 if (
id == SqlStatements::user_catalog_id)
895 return {
false,
i18n(
"Removing the user catalog is not allowed.") };
897 return remove_catalog_force(
id);
900std::pair<bool, QString> DBManager::remove_catalog_force(
const int id)
915 return {
false,
i18n(
"Could not remove the catalog from the registry.<br>%1")
929 return {
false,
i18n(
"Both catalogs have to exist!") };
932 return {
false,
i18n(
"Destination catalog has to be mutable!") };
936 if (!query.exec(SqlStatements::move_objects(
id_1,
id_2)))
937 return {
false, query.lastError().text() };
939 if (!query.exec(SqlStatements::set_catalog_all_objects(
id_2)))
940 return {
false, query.lastError().text() };
948 return {
false,
i18n(
"Cannot update nonexisting catalog.") };
952 query.prepare(SqlStatements::update_catalog_meta);
953 query.bindValue(
":name",
cat.name);
954 query.bindValue(
":author",
cat.author);
955 query.bindValue(
":source",
cat.source);
956 query.bindValue(
":description",
cat.description);
957 query.bindValue(
":id",
cat.id);
958 query.bindValue(
":color",
cat.color);
959 query.bindValue(
":license",
cat.license);
960 query.bindValue(
":maintainer",
cat.maintainer);
961 query.bindValue(
":timestamp",
cat.timestamp);
963 return { query.exec(), query.lastError().text() };
971 const auto element = std::adjacent_find(
972 cats.cbegin(),
cats.cend(), [](
const auto &
c1,
const auto &
c2)
974 return (c1.id >= CatalogsDB::custom_cat_min_id) &&
975 (c2.id >= CatalogsDB::custom_cat_min_id) && (c2.id - c1.id) > 1;
978 return std::max(CatalogsDB::custom_cat_min_id,
979 (element ==
cats.cend() ?
cats.back().id : element->id) + 1);
982QString CatalogsDB::dso_db_path()
985 .
filePath(Options::dSOCatalogFilename());
988std::pair<bool, Catalog> CatalogsDB::read_catalog_meta_from_file(
const QString &path)
991 "QSQLITE",
QString(
"tmp_%1_%2").arg(path).arg(get_connection_index())) };
995 return {
false, {} };
999 if (!
query.exec(
"PRAGMA user_version") || !
query.next() ||
1000 query.value(0).
toInt() < SqlStatements::current_db_version)
1010 return {
false, {} };
1012 const auto &success = migrate_db(
query.value(0).
toInt(), db);
1014 return {
false, {} };
1017 if (!
query.exec(SqlStatements::get_first_catalog) || !
query.first())
1018 return {
false, {} };
1021 return {
true, read_catalog(query) };
1027 while (
query.next())
1039 if (!query.exec(SqlStatements::dso_count_by_type_master))
1040 return {
false, {} };
1042 return {
true, read_statistics(query) };
1045const std::pair<bool, CatalogStatistics>
1049 if (!query.exec(SqlStatements::dso_count_by_type(
catalog_id)))
1050 return {
false, {} };
1052 return {
true, read_statistics(query) };
1055std::pair<bool, QString>
1057 const CatalogObjectVector &objects)
1060 const auto &success = get_catalog(
catalog_id);
1062 return {
false,
i18n(
"Catalog with id=%1 not found.",
catalog_id) };
1064 if (!success.second.mut)
1065 return {
false,
i18n(
"Catalog is immutable!") };
1070 for (
const auto &
object : objects)
1075 bind_catalogobject(query,
catalog_id,
object, trixel);
1079 auto err = query.lastError().text();
1080 if (
err.startsWith(
"UNIQUE"))
1081 err =
i18n(
"The object is already in the catalog!");
1083 return {
false,
i18n(
"Could not insert object! %1",
err) };
1087 return { m_db.commit() &&update_catalog_views() &&compile_master_catalog(),
1088 m_db.lastError().text() };
1097 if (!query.prepare(SqlStatements::dso_by_wildcard()))
1101 query.bindValue(
":wildcard",
wildcard);
1102 query.bindValue(
":limit", limit);
1104 return fetch_objects(query);
1107std::tuple<bool, const QString, CatalogObjectList>
1115 if (!query.prepare(SqlStatements::dso_general_query(
where,
order_by)))
1117 return {
false, query.lastError().text(), {} };
1120 query.bindValue(
":limit", limit);
1122 return {
false,
"", fetch_objects(query) };
1125CatalogsDB::CatalogColorMap CatalogsDB::parse_color_string(
const QString &str)
1127 CatalogsDB::CatalogColorMap colors{};
1131 const auto &parts = str.
split(
";");
1132 auto it = parts.constBegin();
1134 if (
it->length() > 0)
1135 colors[
"default"] = *
it;
1137 while (
it != parts.constEnd())
1139 const auto &scheme = *(++
it);
1140 if (
it != parts.constEnd())
1142 const auto next = ++
it;
1143 if (next == parts.constEnd())
1146 const auto &color = *next;
1147 colors[scheme] =
QColor(color);
1159QString CatalogsDB::to_color_string(CatalogColorMap colors)
1164 colors.erase(
"default");
1166 for (
const auto &item : colors)
1168 if (item.second.isValid())
1170 color_list << item.first << item.second.name();
1184 if (!query.exec(SqlStatements::get_colors))
1189 colors[
cat.id] = parse_color_string(
cat.color);
1192 while (query.next())
1195 const auto &scheme = query.value(
"scheme").toString();
1196 const auto &color = query.value(
"color").toString();
1205 return get_catalog_colors()[id];
1208std::pair<bool, QString>
1215 if (!query.prepare(SqlStatements::insert_color))
1217 return {
false, query.lastError().text() };
1220 query.bindValue(
":catalog",
id);
1221 for (
const auto &item : colors)
1223 query.bindValue(
":scheme", item.first);
1224 query.bindValue(
":color", item.second);
1227 return {
false, query.lastError().text() };
1230 return {
true,
"" };
a dms subclass that caches its sine and cosine values every time the angle is changed.
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
const oid getObjectId() const
const QString & catalogIdentifier() const
double pa() const override
Manages the catalog database and provides an interface to provide an interface to query and modify th...
CatalogObjectList get_objects_all()
Get all objects from the database.
std::pair< bool, QString > add_object(const int catalog_id, const SkyObject::TYPE t, const CachingDms &r, const CachingDms &d, const QString &n, const float m=NaN::f, const QString &lname=QString(), const QString &catalog_identifier=QString(), const float a=0.0, const float b=0.0, const double pa=0.0, const float flux=0)
Add a CatalogObject to a table with `catalog_id`.
int find_suitable_catalog_id()
Finds the smallest free id for a catalog.
bool compile_master_catalog()
Compiles the master catalog by merging the individual catalogs based on oid and precedence and create...
bool update_catalog_views()
Updates the all_catalog_view so that it includes all known catalogs.
CatalogObjectList find_objects_by_name(const QString &name, const int limit=-1, const bool exactMatchOnly=false)
Find an objects by name.
std::pair< bool, QString > set_catalog_enabled(const int id, const bool enabled)
Enable or disable a catalog.
ColorMap get_catalog_colors()
const std::pair< bool, CatalogStatistics > get_catalog_statistics(const int catalog_id)
CatalogObjectList find_objects_by_wildcard(const QString &wildcard, const int limit=-1)
Find an objects by searching the name four wildcard.
std::tuple< bool, const QString, CatalogObjectList > general_master_query(const QString &where, const QString &order_by="", const int limit=-1)
Find an objects by searching the master catlog with a query like SELECT ... FROM master WHERE \p wher...
std::pair< bool, QString > update_catalog_meta(const Catalog &cat)
Update the metatadata `catalog`.
std::pair< bool, QString > remove_catalog(const int id)
remove a catalog
const std::pair< bool, Catalog > get_catalog(const int id)
std::pair< bool, QString > remove_object(const int catalog_id, const CatalogObject::oid &id)
Remove the catalog object with the `oid` from the catalog with the `catalog_id`.
CatalogObjectList get_objects_in_catalog(SkyObject::TYPE type, const int catalog_id, float maglim=default_maglim, int limit=-1)
Get limit objects from the catalog with `catalog_id` of type with magnitude smaller than maglim (smal...
DBManager(const QString &filename)
Constructs a database manager from the filename which is resolved to a path in the kstars data direct...
std::pair< bool, QString > register_catalog(const int id, const QString &name, const bool mut, const bool enabled, const double precedence, const QString &author=cat_defaults.author, const QString &source=cat_defaults.source, const QString &description=cat_defaults.description, const int version=cat_defaults.version, const QString &color=cat_defaults.color, const QString &license=cat_defaults.license, const QString &maintainer=cat_defaults.maintainer, const QDateTime ×tamp=cat_defaults.timestamp)
Registers a new catalog in the database.
std::pair< bool, QString > import_catalog(const QString &file_path, const bool overwrite=false)
Loads a dumped catalog from path `file_path`.
std::pair< bool, QString > add_objects(const int catalog_id, const CatalogObjectVector &objects)
Add the `objects` to a table with `catalog_id`.
const std::vector< Catalog > get_catalogs(bool include_disabled=false)
CatalogObjectList get_objects(float maglim=default_maglim, int limit=-1)
Get limit objects with magnitude smaller than maglim (smaller = brighter) from the database.
bool catalog_exists(const int id)
std::pair< bool, QString > insert_catalog_colors(const int id, const CatalogColorMap &colors)
Saves the configures colors of the catalog with id id in colors into the database.
const std::pair< bool, CatalogStatistics > get_master_statistics()
std::pair< bool, QString > dump_catalog(int catalog_id, QString file_path)
Dumps the catalog with `id` into the file under the path file_path.
std::pair< bool, CatalogObject > get_object(const CatalogObject::oid &oid)
Get an object by `oid`.
std::pair< bool, QString > copy_objects(const int id_1, const int id_2)
Clone objects from the catalog with `id_1` to another with id_2.
Database related error, thrown when database access fails or an action does not succeed.
static SkyMesh * Create(int level)
creates the single instance of SkyMesh.
virtual QString name(void) const
virtual QString longname(void) const
TYPE
The type classification of the SkyObject.
The sky coordinates of a point in the sky.
const CachingDms & ra0() const
const CachingDms & dec0() const
An angle, stored as degrees, but expressible in many ways.
const double & Degrees() const
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
QString name(StandardShortcut id)
bool isValid() const const
QString name(NameFormat format) const const
QDateTime currentDateTime()
QString filePath(const QString &fileName) const const
bool copy(const QString &fileName, const QString &newName)
QSqlQuery exec(const QString &query) const const
QSqlDatabase addDatabase(QSqlDriver *driver, const QString &connectionName)
QSqlError lastError() const const
void setDatabaseName(const QString &name)
QString text() const const
void bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType)
bool isActive() const const
QString arg(Args &&... args) const const
void resize(qsizetype newSize, QChar fillChar)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QTextStream & dec(QTextStream &stream)
Holds statistical information about the objects in a catalog.
A simple struct to hold information about catalogs.