Kstars

horizonmanager.cpp
1 /*
2  SPDX-FileCopyrightText: 2015 Jasem Mutlaq <[email protected]>
3 
4  SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "horizonmanager.h"
8 
9 #include "kstars.h"
10 #include "kstarsdata.h"
11 #include "linelist.h"
12 #include "ksnotification.h"
13 #include "Options.h"
14 #include "skymap.h"
15 #include "projections/projector.h"
16 #include "skycomponents/artificialhorizoncomponent.h"
17 #include "skycomponents/skymapcomposite.h"
18 
19 #include <QStandardItemModel>
20 
21 #include <kstars_debug.h>
22 
23 #define MIN_NUMBER_POINTS 2
24 
25 HorizonManagerUI::HorizonManagerUI(QWidget *p) : QFrame(p)
26 {
27  setupUi(this);
28 }
29 
31 {
32 #ifdef Q_OS_OSX
34 #endif
35  ui = new HorizonManagerUI(this);
36 
37  ui->setStyleSheet("QPushButton:checked { background-color: red; }");
38 
39  ui->addRegionB->setIcon(QIcon::fromTheme("list-add"));
40  ui->addPointB->setIcon(QIcon::fromTheme("list-add"));
41  ui->removeRegionB->setIcon(QIcon::fromTheme("list-remove"));
42  ui->toggleCeilingB->setIcon(QIcon::fromTheme("window"));
43  ui->removePointB->setIcon(QIcon::fromTheme("list-remove"));
44  ui->clearPointsB->setIcon(QIcon::fromTheme("edit-clear"));
45  ui->saveB->setIcon(QIcon::fromTheme("document-save"));
46  ui->selectPointsB->setIcon(
47  QIcon::fromTheme("snap-orthogonal"));
48 
49  ui->tipLabel->setPixmap(
50  (QIcon::fromTheme("help-hint").pixmap(64, 64)));
51 
52  ui->regionValidation->setPixmap(
53  QIcon::fromTheme("process-stop").pixmap(32, 32));
54  ui->regionValidation->setToolTip(i18n("Region is invalid."));
55  ui->regionValidation->hide();
56 
57  setWindowTitle(i18nc("@title:window", "Artificial Horizon Manager"));
58 
59  QVBoxLayout *mainLayout = new QVBoxLayout;
60  mainLayout->addWidget(ui);
61  setLayout(mainLayout);
62 
64  mainLayout->addWidget(buttonBox);
65  connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
66  connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(slotSaveChanges()));
67  connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(slotClosed()));
68 
69  selectPoints = false;
70 
71  // Set up List view
72  m_RegionsModel = new QStandardItemModel(0, 3, this);
73  m_RegionsModel->setHorizontalHeaderLabels(QStringList()
74  << i18n("Region") << i18nc("Azimuth", "Az") << i18nc("Altitude", "Alt"));
75 
76  ui->regionsList->setModel(m_RegionsModel);
77 
78  ui->pointsList->setModel(m_RegionsModel);
79  ui->pointsList->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
80  ui->pointsList->verticalHeader()->hide();
81  ui->pointsList->setColumnHidden(0, true);
82 
83  horizonComponent = KStarsData::Instance()->skyComposite()->artificialHorizon();
84 
85  // Get the list
86  const QList<ArtificialHorizonEntity *> *horizonList = horizonComponent->getHorizon().horizonList();
87 
88  for (auto &horizon : *horizonList)
89  {
90  QStandardItem *regionItem = new QStandardItem(horizon->region());
91  regionItem->setCheckable(true);
92  regionItem->setCheckState(horizon->enabled() ? Qt::Checked : Qt::Unchecked);
93 
94  if (horizon->ceiling())
95  regionItem->setData(QIcon::fromTheme("window"), Qt::DecorationRole);
96  else
97  regionItem->setData(QIcon(), Qt::DecorationRole);
98  regionItem->setData(horizon->ceiling(), Qt::UserRole);
99 
100  m_RegionsModel->appendRow(regionItem);
101 
102  SkyList *points = horizon->list()->points();
103 
104  for (auto &p : *points)
105  {
106  QList<QStandardItem *> pointsList;
107  pointsList << new QStandardItem("") << new QStandardItem(p->az().toDMSString())
108  << new QStandardItem(p->alt().toDMSString());
109  regionItem->appendRow(pointsList);
110  }
111  }
112 
113  ui->removeRegionB->setEnabled(true);
114  ui->toggleCeilingB->setEnabled(true);
115 
116  connect(m_RegionsModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(verifyItemValue(QStandardItem*)));
117 
118  //Connect buttons
119  connect(ui->addRegionB, SIGNAL(clicked()), this, SLOT(slotAddRegion()));
120  connect(ui->removeRegionB, SIGNAL(clicked()), this, SLOT(slotRemoveRegion()));
121  connect(ui->toggleCeilingB, SIGNAL(clicked()), this, SLOT(slotToggleCeiling()));
122 
123  connect(ui->regionsList, SIGNAL(clicked(QModelIndex)), this, SLOT(slotSetShownRegion(QModelIndex)));
124 
125  connect(ui->addPointB, SIGNAL(clicked()), this, SLOT(slotAddPoint()));
126  connect(ui->removePointB, SIGNAL(clicked()), this, SLOT(slotRemovePoint()));
127  connect(ui->clearPointsB, SIGNAL(clicked()), this, SLOT(clearPoints()));
128  connect(ui->selectPointsB, SIGNAL(clicked(bool)), this, SLOT(setSelectPoints(bool)));
129 
130  connect(ui->pointsList->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)),
131  this, SLOT(slotCurrentPointChanged(QModelIndex, QModelIndex)));
132 
133  connect(ui->saveB, SIGNAL(clicked()), this, SLOT(slotSaveChanges()));
134 
135  if (horizonList->count() > 0)
136  {
137  ui->regionsList->selectionModel()->setCurrentIndex(m_RegionsModel->index(0, 0),
139  showRegion(0);
140  }
141 }
142 
143 // If the user hit's the 'X', still want to remove the live preview.
144 void HorizonManager::closeEvent(QCloseEvent *event)
145 {
146  Q_UNUSED(event);
147  slotClosed();
148 }
149 
150 // This gets the live preview to be shown when the window is shown.
151 void HorizonManager::showEvent(QShowEvent *event)
152 {
153  QWidget::showEvent( event );
154  QStandardItem *regionItem = m_RegionsModel->item(ui->regionsList->currentIndex().row(), 0);
155  if (regionItem)
156  {
157  setupLivePreview(regionItem);
158  SkyMap::Instance()->forceUpdateNow();
159  }
160 }
161 
162 // Highlights the current point.
163 void HorizonManager::slotCurrentPointChanged(const QModelIndex &selected, const QModelIndex &deselected)
164 {
165  Q_UNUSED(deselected);
166  if (livePreview.get() != nullptr &&
167  selected.row() >= 0 &&
168  selected.row() < livePreview->points()->size())
169  horizonComponent->setSelectedPreviewPoint(selected.row());
170  else
171  horizonComponent->setSelectedPreviewPoint(-1);
172  SkyMap::Instance()->forceUpdateNow();
173 }
174 
175 // Controls the UI validation check-mark, which indicates if the current
176 // region is valid or not.
177 void HorizonManager::setupValidation(int region)
178 {
179  QStandardItem *regionItem = m_RegionsModel->item(region, 0);
180 
181  if (regionItem && regionItem->rowCount() >= MIN_NUMBER_POINTS)
182  {
183  if (validate(region))
184  {
185  ui->regionValidation->setPixmap(
186  QIcon::fromTheme("dialog-ok").pixmap(32, 32));
187  ui->regionValidation->setEnabled(true);
188  ui->regionValidation->setToolTip(i18n("Region is valid"));
189  }
190  else
191  {
192  ui->regionValidation->setPixmap(
193  QIcon::fromTheme("process-stop").pixmap(32, 32));
194  ui->regionValidation->setEnabled(false);
195  ui->regionValidation->setToolTip(i18n("Region is invalid."));
196  }
197 
198  ui->regionValidation->show();
199  }
200  else
201  ui->regionValidation->hide();
202 }
203 
204 void HorizonManager::showRegion(int regionID)
205 {
206  if (regionID < 0 || regionID >= m_RegionsModel->rowCount())
207  return;
208  else
209  {
210  ui->pointsList->setRootIndex(m_RegionsModel->index(regionID, 0));
211  ui->pointsList->setColumnHidden(0, true);
212 
213  QStandardItem *regionItem = m_RegionsModel->item(regionID, 0);
214 
215  if (regionItem->rowCount() > 0)
216  ui->pointsList->setCurrentIndex(regionItem->child(regionItem->rowCount() - 1, 0)->index());
217  else
218  // Invalid index.
219  ui->pointsList->setCurrentIndex(QModelIndex());
220 
221  setupValidation(regionID);
222 
223  ui->addPointB->setEnabled(true);
224  ui->removePointB->setEnabled(true);
225  ui->selectPointsB->setEnabled(true);
226  ui->clearPointsB->setEnabled(true);
227 
228  if (regionItem != nullptr)
229  {
230  setupLivePreview(regionItem);
231  SkyMap::Instance()->forceUpdateNow();
232  }
233  }
234 
235  ui->saveB->setEnabled(true);
236 }
237 
238 bool HorizonManager::validate(int regionID)
239 {
240  QStandardItem *regionItem = m_RegionsModel->item(regionID, 0);
241 
242  if (regionItem == nullptr || regionItem->rowCount() < MIN_NUMBER_POINTS)
243  return false;
244 
245  for (int i = 0; i < regionItem->rowCount(); i++)
246  {
247  dms az = dms::fromString(regionItem->child(i, 1)->data(Qt::DisplayRole).toString(), true);
248  dms alt = dms::fromString(regionItem->child(i, 2)->data(Qt::DisplayRole).toString(), true);
249 
250  if (std::isnan(az.Degrees()) || std::isnan(alt.Degrees()))
251  return false;
252  }
253 
254  return true;
255 }
256 
257 void HorizonManager::removeEmptyRows(int regionID)
258 {
259  QStandardItem *regionItem = m_RegionsModel->item(regionID, 0);
260 
261  if (regionItem == nullptr)
262  return;
263 
264  QList<int> emptyRows;
265  for (int i = 0; i < regionItem->rowCount(); i++)
266  {
267  dms az = dms::fromString(regionItem->child(i, 1)->data(Qt::DisplayRole).toString(), true);
268  dms alt = dms::fromString(regionItem->child(i, 2)->data(Qt::DisplayRole).toString(), true);
269 
270  if (std::isnan(az.Degrees()) || std::isnan(alt.Degrees()))
271  emptyRows.append(i);
272  }
273  std::sort(emptyRows.begin(), emptyRows.end(), [](int a, int b) -> bool
274  {
275  return a > b;
276  });
277  for (int i = 0; i < emptyRows.size(); ++i)
278  regionItem->removeRow(emptyRows[i]);
279  return;
280 }
281 
283 {
284  terminateLivePreview();
285 
286  setPointSelection(false);
287 
288  QStandardItem *regionItem = new QStandardItem(i18n("Region %1", m_RegionsModel->rowCount() + 1));
289  regionItem->setCheckable(true);
290  regionItem->setCheckState(Qt::Checked);
291  m_RegionsModel->appendRow(regionItem);
292 
293  QModelIndex index = regionItem->index();
294  ui->regionsList->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
295 
296  showRegion(m_RegionsModel->rowCount() - 1);
297 }
298 
299 void HorizonManager::slotToggleCeiling()
300 {
301  int regionID = ui->regionsList->currentIndex().row();
302  QStandardItem *regionItem = m_RegionsModel->item(regionID, 0);
303  if(!regionItem)
304  return;
305 
306  if(!regionItem)
307  return;
308  bool turnCeilingOn = !regionItem->data(Qt::UserRole).toBool();
309  if (turnCeilingOn)
310  {
311  regionItem->setData(QIcon::fromTheme("window"), Qt::DecorationRole);
312  regionItem->setData(true, Qt::UserRole);
313  }
314  else
315  {
316  regionItem->setData(QIcon(), Qt::DecorationRole);
317  regionItem->setData(false, Qt::UserRole);
318  }
319 }
320 
322 {
323  terminateLivePreview();
324 
325  setPointSelection(false);
326 
327  int regionID = ui->regionsList->currentIndex().row();
328  deleteRegion(regionID);
329 
330  if (regionID > 0)
331  showRegion(regionID - 1);
332  else if (m_RegionsModel->rowCount() == 0)
333  {
334  ui->regionValidation->hide();
335  m_RegionsModel->clear();
336  }
337 }
338 
339 void HorizonManager::deleteRegion(int regionID)
340 {
341  if (regionID == -1)
342  return;
343 
344  if (regionID < m_RegionsModel->rowCount())
345  {
346  horizonComponent->removeRegion(m_RegionsModel->item(regionID, 0)->data(Qt::DisplayRole).toString());
347  m_RegionsModel->removeRow(regionID);
348  SkyMap::Instance()->forceUpdate();
349  }
350 }
351 
352 void HorizonManager::slotClosed()
353 {
354  setSelectPoints(false);
355  terminateLivePreview();
356  SkyMap::Instance()->forceUpdate();
357 }
358 
359 void HorizonManager::slotSaveChanges()
360 {
361  terminateLivePreview();
362  setPointSelection(false);
363 
364  for (int i = 0; i < m_RegionsModel->rowCount(); i++)
365  {
366  removeEmptyRows(i);
367  if (validate(i) == false)
368  {
369  KSNotification::error(i18n("%1 region is invalid.",
370  m_RegionsModel->item(i, 0)->data(Qt::DisplayRole).toString()));
371  return;
372  }
373  }
374 
375  for (int i = 0; i < m_RegionsModel->rowCount(); i++)
376  {
377  QStandardItem *regionItem = m_RegionsModel->item(i, 0);
378  QString regionName = regionItem->data(Qt::DisplayRole).toString();
379 
380  horizonComponent->removeRegion(regionName);
381 
382  std::shared_ptr<LineList> list(new LineList());
383  dms az, alt;
384  std::shared_ptr<SkyPoint> p;
385 
386  for (int j = 0; j < regionItem->rowCount(); j++)
387  {
388  az = dms::fromString(regionItem->child(j, 1)->data(Qt::DisplayRole).toString(), true);
389  alt = dms::fromString(regionItem->child(j, 2)->data(Qt::DisplayRole).toString(), true);
390  if (qIsNaN(az.Degrees()) || qIsNaN(alt.Degrees())) continue;
391 
392  p.reset(new SkyPoint());
393  p->setAz(az);
394  p->setAlt(alt);
395  p->HorizontalToEquatorial(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
396 
397  list->append(p);
398  }
399 
400  const bool ceiling = regionItem->data(Qt::UserRole).toBool();
401  horizonComponent->addRegion(regionName, regionItem->checkState() == Qt::Checked ? true : false, list, ceiling);
402  }
403 
404  horizonComponent->save();
405 
406  SkyMap::Instance()->forceUpdateNow();
407 }
408 
409 void HorizonManager::slotSetShownRegion(QModelIndex idx)
410 {
411  showRegion(idx.row());
412 }
413 
414 // Copies values from the model to the livePreview, for the passed in region,
415 // and passes the livePreview to the horizonComponent, which renders the live preview.
416 void HorizonManager::setupLivePreview(QStandardItem * region)
417 {
418  if (region == nullptr) return;
419  livePreview.reset(new LineList());
420  const int numPoints = region->rowCount();
421  for (int i = 0; i < numPoints; i++)
422  {
423  QStandardItem *azItem = region->child(i, 1);
424  QStandardItem *altItem = region->child(i, 2);
425 
426  const dms az = dms::fromString(azItem->data(Qt::DisplayRole).toString(), true);
427  const dms alt = dms::fromString(altItem->data(Qt::DisplayRole).toString(), true);
428  // Don't render points with bad values.
429  if (qIsNaN(az.Degrees()) || qIsNaN(alt.Degrees()))
430  continue;
431 
432  std::shared_ptr<SkyPoint> point(new SkyPoint());
433  point->setAz(az);
434  point->setAlt(alt);
435  point->HorizontalToEquatorial(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
436 
437  livePreview->append(point);
438  }
439 
440  horizonComponent->setLivePreview(livePreview);
441 }
442 
443 void HorizonManager::addPoint(SkyPoint *skyPoint)
444 {
445  QStandardItem *region = m_RegionsModel->item(ui->regionsList->currentIndex().row(), 0);
446  if (region == nullptr)
447  return;
448 
449  // Add the point after the current index in pointsList (row + 1).
450  // If there is no current index, or if somehow (shouldn't happen)
451  // the current index is larger than the list size, insert the point at the end
452  int row = ui->pointsList->currentIndex().row();
453  if ((row < 0) || (row >= region->rowCount()))
454  row = region->rowCount();
455  else row = row + 1;
456 
457  QList<QStandardItem *> pointsList;
458  pointsList << new QStandardItem("") << new QStandardItem("") << new QStandardItem("");
459 
460  region->insertRow(row, pointsList);
461  auto index = region->child(row, 0)->index();
462  ui->pointsList->setCurrentIndex(index);
463 
464  m_RegionsModel->setHorizontalHeaderLabels(QStringList()
465  << i18n("Region") << i18nc("Azimuth", "Az") << i18nc("Altitude", "Alt"));
466  ui->pointsList->setColumnHidden(0, true);
467  ui->pointsList->setRootIndex(region->index());
468 
469  // If a point was supplied (i.e. the user clicked on the SkyMap, as opposed to
470  // just clicking the addPoint button), then set up its coordinates.
471  if (skyPoint != nullptr)
472  {
473  QStandardItem *az = region->child(row, 1);
474  QStandardItem *alt = region->child(row, 2);
475 
476  az->setData(skyPoint->az().toDMSString(), Qt::DisplayRole);
477  alt->setData(skyPoint->alt().toDMSString(), Qt::DisplayRole);
478 
479  setupLivePreview(region);
480  slotCurrentPointChanged(ui->pointsList->currentIndex(), ui->pointsList->currentIndex());
481  }
482 }
483 
484 // Called when the user clicks on the SkyMap to add a new point.
485 void HorizonManager::addSkyPoint(SkyPoint * skypoint)
486 {
487  if (selectPoints == false)
488  return;
489  // Make a copy. This point wasn't staying stable in UI tests.
490  SkyPoint pt = *skypoint;
491  addPoint(&pt);
492 }
493 
494 // Called when the user clicks on the addPoint button.
495 void HorizonManager::slotAddPoint()
496 {
497  addPoint(nullptr);
498 }
499 
500 void HorizonManager::slotRemovePoint()
501 {
502  int regionID = ui->regionsList->currentIndex().row();
503  QStandardItem *regionItem = m_RegionsModel->item(regionID, 0);
504  if (regionItem == nullptr)
505  return;
506 
507  int row = ui->pointsList->currentIndex().row();
508  if (row == -1)
509  row = regionItem->rowCount() - 1;
510  regionItem->removeRow(row);
511 
512  setupValidation(regionID);
513 
514  if (livePreview.get() && row < livePreview->points()->count())
515  {
516  livePreview->points()->takeAt(row);
517 
518  if (livePreview->points()->isEmpty())
519  terminateLivePreview();
520  else
521  SkyMap::Instance()->forceUpdateNow();
522  }
523 }
524 
525 void HorizonManager::clearPoints()
526 {
527  QStandardItem *regionItem = m_RegionsModel->item(ui->regionsList->currentIndex().row(), 0);
528 
529  if (regionItem)
530  {
531  regionItem->removeRows(0, regionItem->rowCount());
532 
533  horizonComponent->removeRegion(regionItem->data(Qt::DisplayRole).toString(), true);
534 
535  ui->regionValidation->hide();
536  }
537 
538  terminateLivePreview();
539 }
540 
541 void HorizonManager::setSelectPoints(bool enable)
542 {
543  selectPoints = enable;
544  ui->selectPointsB->clearFocus();
545 }
546 
547 void HorizonManager::verifyItemValue(QStandardItem * item)
548 {
549  bool azOK = true, altOK = true;
550 
551  if (item->column() >= 1)
552  {
553  QStandardItem *parent = item->parent();
554 
555  dms azAngle = dms::fromString(parent->child(item->row(), 1)->data(Qt::DisplayRole).toString(), true);
556  dms altAngle = dms::fromString(parent->child(item->row(), 2)->data(Qt::DisplayRole).toString(), true);
557 
558  if (std::isnan(azAngle.Degrees()))
559  azOK = false;
560  if (std::isnan(altAngle.Degrees()))
561  altOK = false;
562 
563  if ((item->column() == 1 && azOK == false) || (item->column() == 2 && altOK == false))
564 
565  {
566  KSNotification::error(i18n("Invalid angle value: %1", item->data(Qt::DisplayRole).toString()));
567  disconnect(m_RegionsModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(verifyItemValue(QStandardItem*)));
568  item->setData(QVariant(qQNaN()), Qt::DisplayRole);
569  connect(m_RegionsModel, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(verifyItemValue(QStandardItem*)));
570  return;
571  }
572  else if (azOK && altOK)
573  {
574  setupLivePreview(item->parent());
575  setupValidation(ui->regionsList->currentIndex().row());
576  SkyMap::Instance()->forceUpdateNow();
577  }
578  }
579 }
580 
581 void HorizonManager::terminateLivePreview()
582 {
583  if (!livePreview.get())
584  return;
585 
586  livePreview.reset();
587  horizonComponent->setLivePreview(livePreview);
588 }
589 
590 void HorizonManager::setPointSelection(bool enable)
591 {
592  selectPoints = enable;
593  ui->selectPointsB->setChecked(enable);
594 }
void append(const T &value)
const dms & alt() const
Definition: skypoint.h:281
void removeRows(int row, int count)
DecorationRole
void forceUpdateNow()
Convenience function; simply calls forceUpdate(true).
Definition: skymap.h:377
virtual void reject()
int row() const const
Qt::CheckState checkState() const const
Stores dms coordinates for a point in the sky. for converting between coordinate systems.
Definition: skypoint.h:44
QIcon fromTheme(const QString &name)
void slotAddRegion()
Add region.
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
void slotRemoveRegion()
Delete region.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QStandardItem * child(int row, int column) const const
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
int size() const const
void setHorizontalHeaderLabels(const QStringList &labels)
void rejected()
int rowCount() const const
QString i18n(const char *text, const TYPE &arg...)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition: dms.cpp:279
void setWindowFlags(Qt::WindowFlags type)
void insertRow(int row, const QList< QStandardItem * > &items)
virtual void showEvent(QShowEvent *event)
void setWindowTitle(const QString &)
QStandardItem * parent() const const
QModelIndex index() const const
GeoCoordinates geo(const QVariant &location)
void setEnabled(bool enabled)
bool toBool() const const
int row() const const
SkyMapComposite * skyComposite()
Definition: kstarsdata.h:165
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
QPushButton * button(QDialogButtonBox::StandardButton which) const const
void removeRow(int row)
const double & Degrees() const
Definition: dms.h:141
virtual QVariant data(int role) const const
void appendRow(const QList< QStandardItem * > &items)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QList::iterator begin()
void forceUpdate(bool now=false)
Recalculates the positions of objects in the sky, and then repaints the sky map.
Definition: skymap.cpp:1186
virtual void setData(const QVariant &value, int role)
void setCheckable(bool checkable)
int column() const const
void setLayout(QLayout *layout)
QList::iterator end()
void setCheckState(Qt::CheckState state)
void appendRow(const QList< QStandardItem * > &items)
static dms fromString(const QString &s, bool deg)
Static function to create a DMS object from a QString.
Definition: dms.cpp:421
QString toString() const const
HorizonManager(QWidget *ks)
Constructor.
const dms & az() const
Definition: skypoint.h:275
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 19 2022 03:57:51 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.