Kstars

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

KDE's Doxygen guidelines are available online.