Kstars

addcatalogobject.cpp
1 /*
2  SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "addcatalogobject.h"
8 #include "ui_addcatalogobject.h"
9 #include "kstars_debug.h"
10 
11 #include <QInputDialog>
12 #include <QPushButton>
13 
15  : QDialog(parent), ui(new Ui::AddCatalogObject), m_object{ obj }
16 {
17  ui->setupUi(this);
18  ui->ra->setUnits(dmsBox::HOURS);
19  fill_form_from_object();
20 
21  connect(ui->name, &QLineEdit::textChanged,
22  [&](const auto &name) { m_object.setName(name); });
23 
24  connect(ui->long_name, &QLineEdit::textChanged,
25  [&](const auto &name) { m_object.setLongName(name); });
26 
27  connect(ui->catalog_identifier, &QLineEdit::textChanged,
28  [&](const auto &ident) { m_object.setCatalogIdentifier(ident); });
29 
30  connect(ui->type, QOverload<int>::of(&QComboBox::currentIndexChanged),
31  [&](const auto index) {
32  if (index > SkyObject::TYPE_UNKNOWN)
33  m_object.setType(SkyObject::TYPE_UNKNOWN);
34 
35  m_object.setType(index);
36 
37  refresh_flux();
38  });
39 
40  auto validateAndStoreCoordinates = [&]() {
41  bool raOk(false), decOk(false);
42  auto ra = ui->ra->createDms(&raOk);
43  auto dec = ui->dec->createDms(&decOk);
44  auto* okButton = ui->buttonBox->button(QDialogButtonBox::Ok);
45  Q_ASSERT(!!okButton);
46  okButton->setEnabled(raOk && decOk);
47  if (raOk && decOk) {
48  m_object.setRA0(ra);
49  m_object.setDec0(dec);
50  }
51  };
52 
53  connect(ui->ra, &dmsBox::textChanged, validateAndStoreCoordinates);
54  connect(ui->dec, &dmsBox::textChanged, validateAndStoreCoordinates);
55 
56  auto updateMag = [&]()
57  {
58  m_object.setMag(
59  ui->magUnknown->isChecked() ? NaN::f : static_cast<float>(ui->mag->value()));
60  };
61  connect(ui->mag, QOverload<double>::of(&QDoubleSpinBox::valueChanged), updateMag);
62  connect(ui->magUnknown, &QCheckBox::stateChanged, updateMag);
63 
64  connect(ui->maj, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
65  [&](const auto value) { m_object.setMaj(static_cast<float>(value)); });
66 
67  connect(ui->min, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
68  [&](const auto value) { m_object.setMin(static_cast<float>(value)); });
69 
70  connect(ui->flux, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
71  [&](const auto value) { m_object.setFlux(static_cast<float>(value)); });
72 
73  connect(ui->position_angle, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
74  [&](const auto value) { m_object.setPA(value); });
75 
76  connect(ui->guessFromTextButton, &QPushButton::clicked, [this]() { this->guess_form_contents_from_text(); });
77 }
78 
79 AddCatalogObject::~AddCatalogObject()
80 {
81  delete ui;
82 }
83 
84 void AddCatalogObject::fill_form_from_object()
85 {
86  if (m_object.hasName()) // N.B. Avoid filling name fields with "unnamed"
87  ui->name->setText(m_object.name());
88  if (m_object.hasLongName())
89  ui->long_name->setText(m_object.longname());
90  ui->catalog_identifier->setText(m_object.catalogIdentifier());
91 
92  for (int k = 0; k < SkyObject::NUMBER_OF_KNOWN_TYPES; ++k)
93  {
94  ui->type->addItem(SkyObject::typeName(k));
95  }
96  ui->type->addItem(SkyObject::typeName(SkyObject::TYPE_UNKNOWN));
97  ui->type->setCurrentIndex((int)(m_object.type()));
98 
99  dms ra0 = m_object.ra0();
100  dms dec0 = m_object.dec0(); // Make a copy to avoid overwriting by signal-slot connection
101  ui->ra->show(ra0);
102  ui->dec->show(dec0);
103  if (std::isnan(m_object.mag()))
104  {
105  ui->magUnknown->setChecked(true);
106  }
107  else
108  {
109  ui->mag->setValue(m_object.mag());
110  ui->magUnknown->setChecked(false);
111  }
112  ui->flux->setValue(m_object.flux());
113  ui->position_angle->setValue(m_object.pa());
114  ui->maj->setValue(m_object.a());
115  ui->min->setValue(m_object.b());
116  refresh_flux();
117 }
118 
119 void AddCatalogObject::refresh_flux()
120 {
121  ui->flux->setEnabled(m_object.type() == SkyObject::RADIO_SOURCE);
122 
123  if (!ui->flux->isEnabled())
124  ui->flux->setValue(0);
125 }
126 
127 void AddCatalogObject::guess_form_contents_from_text()
128 {
129  bool accepted = false;
131  this,
132  i18n("Guess object data from text"),
133  i18n("Copy-paste a text blurb with data on the object, and KStars will try to guess the contents of the fields from the text. The result is just a guess, so please verify the coordinates and the other information."),
134  QString(),
135  &accepted);
136  if (accepted && !text.isEmpty())
137  {
138  guess_form_contents_from_text(text);
139  }
140 }
141 
142 void AddCatalogObject::guess_form_contents_from_text(QString text)
143 {
144  // Parse text to fill in the entries in the form, using regexes to
145  // guess the field values
146 
147  // TODO: Guess type from catalog name if the type match failed
148 
149  QRegularExpression matchJ2000Line("^(.*)(?:J2000|ICRS|FK5|\\(2000(?:\\.0)?\\))(.*)$");
150  matchJ2000Line.setPatternOptions(QRegularExpression::MultilineOption);
151  QRegularExpression matchCoords("(?:^|[^-\\d])([-+]?\\d\\d?)(?:h ?|d ?|[^\\d]?° ?|:| )(\\d\\d)(?:m ?|\' ?|’ ?|′ "
152  "?|:| )(\\d\\d(?:\\.\\d+)?)?(?:s|\"|\'\'|”|″)?\\b");
153  QRegularExpression matchCoords2("J?\\d{6,6}[-+]\\d{6,6}");
154  QRegularExpression findMag1(
155  "(?:[mM]ag(?:nitudes?)?\\s*(?:\\([vV]\\))?|V(?=\\b))(?:\\s*=|:)?\\s*(-?\\d{1,2}(?:\\.\\d{1,3})?)");
156  QRegularExpression findMag2("\\b(-?\\d{1,2}\\.\\d{1,3})?\\s*(?:[mM]ag|V|B)\\b");
157  QRegularExpression findSize1("\\b(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\s*[xX×]\\s*(\\d{1,3}(?:\\.\\d{1,2})"
158  "?)\\s*(°|\'|\"|\'\')?\\b");
159  QRegularExpression findSize2("\\b(?:[Ss]ize|[Dd]imensions?|[Dd]iameter)[: "
160  "](?:\\([vV]\\))?\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b");
161  QRegularExpression findMajorAxis("\\b[Mm]ajor\\s*[Aa]xis:?\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b");
162  QRegularExpression findMinorAxis("\\b[Mm]inor\\s*[Aa]xis:?\\s*(\\d{1,3}(?:\\.\\d{1,2})?)\\s*(°|\'|\"|\'\')?\\b");
163  QRegularExpression findPA(
164  "\\b(?:[Pp]osition *[Aa]ngle|PA|[pP]\\.[aA]\\.):?\\s*(\\d{1,3}(\\.\\d{1,2})?)(?:°|[Ddeg])?\\b");
165  QRegularExpression findName1(
166  "\\b(?:(?:[nN]ames?|NAMES?)[: ]|[iI]dent(?:ifier)?:|[dD]esignation:)\\h*\"?([-+\'A-Za-z0-9 ]*)\"?\\b");
167  QStringList catalogNames;
168  catalogNames << "NGC"
169  << "IC"
170  << "M"
171  << "PGC"
172  << "UGC"
173  << "UGCA"
174  << "MCG"
175  << "ESO"
176  << "SDSS"
177  << "LEDA"
178  << "IRAS"
179  << "PNG"
180  << "Abell"
181  << "ACO"
182  << "HCG"
183  << "CGCG"
184  << "[IV]+ ?Zw"
185  << "Hickson"
186  << "AGC"
187  << "2MASS"
188  << "RCS2"
189  << "Terzan"
190  << "PN [A-Z0-9]"
191  << "VV"
192  << "PK"
193  << "GSC2"
194  << "LBN"
195  << "LDN"
196  << "Caldwell"
197  << "HIP"
198  << "AM"
199  << "vdB"
200  << "Barnard"
201  << "Shkh?"
202  << "KTG"
203  << "Palomar"
204  << "KPG"
205  << "CGPG"
206  << "TYC"
207  << "Arp"
208  << "Minkowski"
209  << "KUG"
210  << "DDO"
211  ;
213  objectTypes.append({"[Op]pen ?[Cc]luster|OCL|\\*Cl|Cl\\*|OpC|Cl\\?|Open Cl\\.", SkyObject::OPEN_CLUSTER});
214  objectTypes.append({"Globular ?Cluster|GlC|GCl|Glob\\. Cl\\.|Globular|Gl\\?", SkyObject::GLOBULAR_CLUSTER});
215  objectTypes.append({"(?:[Gg]as(?:eous)?|Diff(?:\\.|use)?|Emission|Ref(?:\\.|lection)?) ?[Nn]eb(?:ula|\\.)?|Neb|RfN|HII|GNe", SkyObject::GASEOUS_NEBULA});
216  objectTypes.append({"PN|PNe|Pl\\.? ?[Nn]eb\\.?|(?:[Pp]re[- ]?)[Pp]lanetary|PPNe|PPN|pA\\*|post[- ]?AGB", SkyObject::PLANETARY_NEBULA});
217  objectTypes.append({"SNR|[Ss]upernova ?[Rr]em(?:\\.|nant)?|SNRem(?:\\.|nant)?", SkyObject::SUPERNOVA_REMNANT});
218  objectTypes.append({"Gxy?|HIIG|H2G|[bB]CG|SBG|AGN|EmG|LINER|LIRG|GiG|GinP", SkyObject::GALAXY});
219  objectTypes.append({"Ast\\.?|Asterism", SkyObject::ASTERISM});
220  objectTypes.append({"ClG|GrG|CGG|[Gg](?:ala)?xy ?(?:[Gg]roup|[Cc]luster|[Pp]air|[Tt]rio|[Tt]riple)|GClus|GGrp|GGroup|GClstr|GPair|GTrpl|GTrio", SkyObject::GALAXY_CLUSTER});
221  objectTypes.append({"ISM|DNeb?|[dD](?:k\\.?|ark) ?[Nn]eb(?:ula|\\.)?", SkyObject::DARK_NEBULA});
222  objectTypes.append({"QSO|[qQ]uasar", SkyObject::QUASAR});
223  objectTypes.append({"(?:[Dd]ouble|[Dd]bl\\.?|[Tt]riple|[Mm]ult(?:iple|\\.)? ?[Ss]tar)|\\*\\*|Mult\\.? ?\\*", SkyObject::MULT_STAR});
224  objectTypes.append({"[nN]ebula", SkyObject::GASEOUS_NEBULA}); // Catch all nebula
225  objectTypes.append({"[gG]alaxy", SkyObject::GALAXY}); // Catch all galaxy
226 
227  QRegularExpression findName2("\\b(" + catalogNames.join("|") + ")\\s+(J?[-+0-9\\.]+[A-Da-h]?)\\b");
228  QRegularExpression findName3("\\b([A-Za-z]+[0-9]?)\\s+(J?[-+0-9]+[A-Da-h]?)\\b");
229 
230  // FIXME: This code will clean up by a lot if std::optional<> can be used
231  QString coordText;
232  bool coordsFound = false,
233  magFound = false,
234  sizeFound = false,
235  nameFound = false,
236  positionAngleFound = false,
237  catalogDetermined = false,
238  typeFound = false;
239 
240  dms RA, Dec;
241  float mag = NaN::f;
242  float majorAxis = NaN::f;
243  float minorAxis = NaN::f;
244  float positionAngle = 0;
245  QString name;
246  QString catalogName;
247  QString catalogIdentifier;
248  SkyObject::TYPE type = SkyObject::TYPE_UNKNOWN;
249 
250  // Note: The following method is a proxy to support older versions of Qt.
251  // In Qt 5.5 and above, the QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) method obviates the need for the following.
252  auto indexOf = [](const QString & s, const QRegularExpression & regExp, int from, QRegularExpressionMatch * m) -> int
253  {
254  *m = regExp.match(s, from);
255  return m->capturedStart(0);
256  };
257 
258  auto countNonOverlappingMatches = [indexOf](const QString & string, const QRegularExpression & regExp,
259  QStringList *list = nullptr) -> int
260  {
261  int count = 0;
262  int matchIndex = -1;
263  int lastMatchLength = 1;
265  while ((matchIndex = indexOf(string, regExp, matchIndex + lastMatchLength, &rmatch)) >= 0)
266  {
267  ++count;
268  lastMatchLength = rmatch.captured(0).length();
269  if (list)
270  list->append(rmatch.captured(0));
271  }
272  return count;
273  };
274 
276  int nonOverlappingMatchCount;
277  std::size_t coordTextIndex = 0;
278  if ((nonOverlappingMatchCount = countNonOverlappingMatches(text, matchCoords)) == 2)
279  {
280  coordText = text;
281  }
282  else if (nonOverlappingMatchCount > 2)
283  {
284  qCDebug(KSTARS) << "Found more than 2 coordinate matches. Trying to match J2000 line.";
285  if ((coordTextIndex = indexOf(text, matchJ2000Line, 0, &rmatch)) >= 0)
286  {
287  coordText = rmatch.captured(1) + rmatch.captured(2);
288  qCDebug(KSTARS) << "Found a J2000 line match: " << coordText;
289  }
290  }
291 
292  if (!coordText.isEmpty())
293  {
294  int coord1 = indexOf(coordText, matchCoords, 0, &rmatch);
295  if (coord1 >= 0) {
296  std::size_t length1 = rmatch.captured(0).length();
297  RA = dms(rmatch.captured(1) + ' ' + rmatch.captured(2) + ' ' + rmatch.captured(3), false);
298  int coord2 = indexOf(coordText, matchCoords, coord1 + length1, &rmatch);
299  if (coord2 >= 0) {
300  Dec = dms(rmatch.captured(1) + ' ' + rmatch.captured(2) + ' ' + rmatch.captured(3), true);
301  qCDebug(KSTARS) << "Extracted coordinates: " << RA.toHMSString() << " " << Dec.toDMSString();
302  coordsFound = true;
303 
304  // Remove the coordinates from the original string so subsequent tasks don't confuse it
305  std::size_t length2 = rmatch.captured(0).length();
306  qCDebug(KSTARS) << "Eliminating text: " << text.midRef(coordTextIndex + coord1, length1) << " and " << text.midRef(coordTextIndex + coord2, length2);
307  text.replace(coordTextIndex + coord1, length1, "\n");
308  text.replace(coordTextIndex + coord2 - length1 + 1, length2, "\n");
309  qCDebug(KSTARS) << "Text now: " << text;
310  }
311  }
312  }
313  else
314  {
315  if (text.contains(matchCoords2, &rmatch))
316  {
317  QString matchString = rmatch.captured(0);
318  QRegularExpression extractCoords2("(\\d\\d)(\\d\\d)(\\d\\d)([-+]\\d\\d)(\\d\\d)(\\d\\d)");
319  Q_ASSERT(matchString.contains(extractCoords2, &rmatch));
320  RA = dms(rmatch.captured(1) + ' ' + rmatch.captured(2) + ' ' + rmatch.captured(3), false);
321  Dec = dms(rmatch.captured(4) + ' ' + rmatch.captured(5) + ' ' + rmatch.captured(6), true);
322  coordsFound = true;
323 
324  // Remove coordinates to avoid downstream confusion with it
325  qCDebug(KSTARS) << "Eliminating text: " << text.midRef(rmatch.capturedStart(), rmatch.captured(0).length());
326  text.replace(rmatch.capturedStart(), rmatch.captured(0).length(), "\n");
327  qCDebug(KSTARS) << "Text now: " << text;
328  }
329  else
330  {
331  QStringList matches;
332  qCDebug(KSTARS) << "Could not extract RA/Dec. Found " << countNonOverlappingMatches(text, matchCoords, &matches)
333  << " coordinate matches:";
334  qCDebug(KSTARS) << matches;
335  }
336  }
337 
338  // Type determination: Support full names of types, or SIMBAD/NED shorthands
339  for (const auto& p : objectTypes)
340  {
341  QRegularExpression findType("\\b(?:" + p.first + ")\\b");
342  if (text.contains(findType, &rmatch)) {
343  type = p.second;
344  typeFound = true;
345  qCDebug(KSTARS) << "Found Type: " << SkyObject::typeName(p.second);
346  qCDebug(KSTARS) << "Eliminating text: " << text.midRef(rmatch.capturedStart(), rmatch.captured(0).length());
347  text.replace(rmatch.capturedStart(), rmatch.captured(0).length(), "\n"); // Remove to avoid downstream confusion
348  qCDebug(KSTARS) << "Text now: " << text;
349  break;
350  }
351  }
352  if (!typeFound) {
353  qCDebug(KSTARS) << "Type not found";
354  }
355 
356  nameFound = true;
357  catalogDetermined = true; // Transition to std::optional with C++17
358  if (text.contains(findName1, &rmatch)) // Explicit name search
359  {
360  qCDebug(KSTARS) << "Found explicit name field: " << rmatch.captured(1) << " in text " << rmatch.captured(0);
361  name = rmatch.captured(1);
362  catalogDetermined = false;
363  }
364  else if (text.contains(findName2, &rmatch))
365  {
366  catalogDetermined = true;
367  catalogName = rmatch.captured(1);
368  catalogIdentifier = rmatch.captured(2);
369  name = catalogName + ' ' + catalogIdentifier;
370  qCDebug(KSTARS) << "Found known catalog field: " << name
371  << " in text " << rmatch.captured(0);
372  }
373  else if (text.contains(findName3, &rmatch))
374  {
375  // N.B. This case is not strong enough to assume catalog name was found correctly
376  name = rmatch.captured(1) + ' ' + rmatch.captured(2);
377  qCDebug(KSTARS) << "Found something that looks like a catalog designation: "
378  << name << " in text " << rmatch.captured(0);
379  }
380  else
381  {
382  qCDebug(KSTARS) << "Could not find name.";
383  nameFound = false;
384  catalogDetermined = false;
385  }
386 
387  magFound = true;
388  if (text.contains(findMag1, &rmatch))
389  {
390  qCDebug(KSTARS) << "Found magnitude: " << rmatch.captured(1) << " in text " << rmatch.captured(0);
391  mag = rmatch.captured(1).toFloat();
392  }
393  else if (text.contains(findMag2, &rmatch))
394  {
395  qCDebug(KSTARS) << "Found magnitude: " << rmatch.captured(1) << " in text " << rmatch.captured(0);
396  mag = rmatch.captured(1).toFloat();
397  }
398  else
399  {
400  qCDebug(KSTARS) << "Could not find magnitude.";
401  magFound = false;
402  }
403 
404  sizeFound = true;
405  if (text.contains(findSize1, &rmatch))
406  {
407  qCDebug(KSTARS) << "Found size: " << rmatch.captured(1) << " x " << rmatch.captured(3) << " with units "
408  << rmatch.captured(4) << " in text " << rmatch.captured(0);
409  majorAxis = rmatch.captured(1).toFloat();
410  QString unitText2;
411  if (rmatch.captured(2).isEmpty())
412  {
413  unitText2 = rmatch.captured(4);
414  }
415  else
416  {
417  unitText2 = rmatch.captured(2);
418  }
419 
420  if (unitText2.contains("°"))
421  majorAxis *= 60;
422  else if (unitText2.contains("\"") || unitText2.contains("\'\'"))
423  majorAxis /= 60;
424 
425  minorAxis = rmatch.captured(3).toFloat();
426  if (rmatch.captured(4).contains("°"))
427  minorAxis *= 60;
428  else if (rmatch.captured(4).contains("\"") || rmatch.captured(4).contains("\'\'"))
429  minorAxis /= 60;
430  qCDebug(KSTARS) << "Major axis = " << majorAxis << "; minor axis = " << minorAxis << " in arcmin";
431  }
432  else if (text.contains(findSize2, &rmatch))
433  {
434  majorAxis = rmatch.captured(1).toFloat();
435  if (rmatch.captured(2).contains("°"))
436  majorAxis *= 60;
437  else if (rmatch.captured(2).contains("\"") || rmatch.captured(2).contains("\'\'"))
438  majorAxis /= 60;
439  minorAxis = majorAxis;
440  }
441  else if (text.contains(findMajorAxis, &rmatch))
442  {
443  majorAxis = rmatch.captured(1).toFloat();
444  if (rmatch.captured(2).contains("°"))
445  majorAxis *= 60;
446  else if (rmatch.captured(2).contains("\"") || rmatch.captured(2).contains("\'\'"))
447  majorAxis /= 60;
448  minorAxis = majorAxis;
449  if (text.contains(findMinorAxis, &rmatch))
450  {
451  minorAxis = rmatch.captured(1).toFloat();
452  if (rmatch.captured(2).contains("°"))
453  minorAxis *= 60;
454  else if (rmatch.captured(2).contains("\"") || rmatch.captured(2).contains("\'\'"))
455  minorAxis /= 60;
456  }
457  }
458 
459  else
460  {
461  qCDebug(KSTARS)
462  << "Could not find size."; // FIXME: Improve to include separate major and minor axis matches, and size matches for round objects.
463  sizeFound = false;
464  }
465 
466  positionAngleFound = true;
467  if (text.contains(findPA, &rmatch))
468  {
469  qCDebug(KSTARS) << "Found position angle: " << rmatch.captured(1) << " in text " << rmatch.captured(0);
470  positionAngle = rmatch.captured(1).toFloat();
471  }
472  else
473  {
474  qCDebug(KSTARS) << "Could not find position angle.";
475  positionAngleFound = false;
476  }
477 
478  if (typeFound)
479  ui->type->setCurrentIndex((int)type);
480  if (nameFound)
481  ui->name->setText(name);
482  if (magFound)
483  {
484  ui->mag->setValue(mag);
485  ui->magUnknown->setChecked(false);
486  } else
487  {
488  ui->magUnknown->setChecked(true);
489  }
490  if (coordsFound)
491  {
492  ui->ra->show(RA);
493  ui->dec->show(Dec);
494  }
495  if (positionAngleFound)
496  ui->position_angle->setValue(positionAngle);
497  if (sizeFound)
498  {
499  ui->maj->setValue(majorAxis);
500  ui->min->setValue(minorAxis);
501  }
502  if (catalogDetermined)
503  {
504  ui->catalog_identifier->setText(catalogIdentifier);
505  }
506  refresh_flux();
507 }
void append(const T &value)
QTextStream & dec(QTextStream &s)
Type type(const QSqlDatabase &db)
QStringRef midRef(int position, int n) const const
void clicked(bool checked)
virtual QString name(void) const
Definition: skyobject.h:145
float mag() const
Definition: skyobject.h:206
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
void stateChanged(int state)
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
Definition: dms.cpp:370
void valueChanged(double d)
int type(void) const
Definition: skyobject.h:188
float a() const
QString i18n(const char *text, const TYPE &arg...)
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition: dms.cpp:279
void textChanged(const QString &text)
bool isEmpty() const const
int length() const const
double pa() const override
float toFloat(bool *ok) const const
QString getMultiLineText(QWidget *parent, const QString &title, const QString &label, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
QString join(const QString &separator) const const
QString & replace(int position, int n, QChar after)
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
float b() const
float flux() const
const CachingDms & ra() const
Definition: skypoint.h:263
const CachingDms & dec0() const
Definition: skypoint.h:257
const char * name(StandardAction id)
void currentIndexChanged(int index)
const CachingDms & ra0() const
Definition: skypoint.h:251
A simple data entry dialog to create and edit objects in CatalogDB catalogs.
virtual QString longname(void) const
Definition: skyobject.h:164
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
const QString & catalogIdentifier() const
AddCatalogObject(QWidget *parent, const CatalogObject &obj={})
A simple container object to hold the minimum information for a Deeb Sky Object to be drawn on the sk...
Definition: catalogobject.h:40
QString captured(int nth) const const
QString typeName() const
Definition: skyobject.cpp:389
int capturedStart(int nth) const const
void accepted()
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 04:00:52 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.