Kstars

observinglist.cpp
1/*
2 SPDX-FileCopyrightText: 2004-2020 Jeff Woods <jcwoods@bellsouth.net>
3 SPDX-FileCopyrightText: 2004-2020 Jason Harris <jharris@30doradus.org>
4 SPDX-FileCopyrightText: Prakash Mohan <prakash.mohan@kdemail.net>
5 SPDX-FileCopyrightText: Akarsh Simha <akarsh@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "observinglist.h"
11
12#include "config-kstars.h"
13
14#include "constellationboundarylines.h"
15#include "fov.h"
16#include "imageviewer.h"
17#include "ksalmanac.h"
18#include "ksnotification.h"
19#include "ksdssdownloader.h"
20#include "kspaths.h"
21#include "kstars.h"
22#include "kstarsdata.h"
23#include "ksutils.h"
24#include "obslistpopupmenu.h"
25#include "obslistwizard.h"
26#include "Options.h"
27#include "sessionsortfilterproxymodel.h"
28#include "skymap.h"
29#include "thumbnailpicker.h"
30#include "dialogs/detaildialog.h"
31#include "dialogs/finddialog.h"
32#include "dialogs/locationdialog.h"
33#include "oal/execute.h"
34#include "skycomponents/skymapcomposite.h"
35#include "skyobjects/skyobject.h"
36#include "skyobjects/starobject.h"
37#include "tools/altvstime.h"
38#include "tools/eyepiecefield.h"
39#include "tools/wutdialog.h"
40
41#ifdef HAVE_INDI
42#include <basedevice.h>
43#include "indi/indilistener.h"
44#include "indi/drivermanager.h"
45#include "indi/driverinfo.h"
46#include "ekos/manager.h"
47#endif
48
49#include <kplotaxis.h>
50#include <kplotobject.h>
51#include <KMessageBox>
52#include <QMessageBox>
53#include <QStatusBar>
54#include <QProgressDialog>
55#include <QInputDialog>
56
57#include <kstars_debug.h>
58
59//
60// ObservingListUI
61// ---------------------------------
62ObservingListUI::ObservingListUI(QWidget *p) : QFrame(p)
63{
64 setupUi(this);
65}
66
67//
68// ObservingList
69// ---------------------------------
70ObservingList::ObservingList()
71 : QDialog((QWidget *)KStars::Instance()), LogObject(nullptr), m_CurrentObject(nullptr), isModified(false), m_dl(nullptr),
72 m_manager{ CatalogsDB::dso_db_path() }
73{
74#ifdef Q_OS_MACOS
75 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
76#endif
77 ui = new ObservingListUI(this);
78 QVBoxLayout *mainLayout = new QVBoxLayout;
79 mainLayout->addWidget(ui);
80 setWindowTitle(i18nc("@title:window", "Observation Planner"));
81
82 setLayout(mainLayout);
83
85 setFocusPolicy(Qt::StrongFocus);
86 geo = KStarsData::Instance()->geo();
87 sessionView = false;
88 m_listFileName = QString();
89 pmenu.reset(new ObsListPopupMenu());
90 //Set up the Table Views
91 m_WishListModel.reset(new QStandardItemModel(0, 5, this));
92 m_SessionModel.reset(new QStandardItemModel(0, 5));
93
94 m_WishListModel->setHorizontalHeaderLabels(
95 QStringList() << i18n("Name") << i18n("Alternate Name") << i18nc("Right Ascension", "RA (J2000)")
96 << i18nc("Declination", "Dec (J2000)") << i18nc("Magnitude", "Mag") << i18n("Type")
97 << i18n("Current Altitude"));
98 m_SessionModel->setHorizontalHeaderLabels(
99 QStringList() << i18n("Name") << i18n("Alternate Name") << i18nc("Right Ascension", "RA (J2000)")
100 << i18nc("Declination", "Dec (J2000)") << i18nc("Magnitude", "Mag") << i18n("Type")
101 << i18nc("Constellation", "Constell.") << i18n("Time") << i18nc("Altitude", "Alt")
102 << i18nc("Azimuth", "Az"));
103
104 m_WishListSortModel.reset(new QSortFilterProxyModel(this));
105 m_WishListSortModel->setSourceModel(m_WishListModel.get());
106 m_WishListSortModel->setDynamicSortFilter(true);
107 m_WishListSortModel->setSortRole(Qt::UserRole);
108 ui->WishListView->setModel(m_WishListSortModel.get());
109 ui->WishListView->horizontalHeader()->setStretchLastSection(true);
110
111 ui->WishListView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
112 m_SessionSortModel.reset(new SessionSortFilterProxyModel());
113 m_SessionSortModel->setSourceModel(m_SessionModel.get());
114 m_SessionSortModel->setDynamicSortFilter(true);
115 ui->SessionView->setModel(m_SessionSortModel.get());
116 ui->SessionView->horizontalHeader()->setStretchLastSection(true);
117 ui->SessionView->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
118 ksal.reset(new KSAlmanac);
119 ksal->setLocation(geo);
120 ui->avt->setGeoLocation(geo);
121 ui->avt->setSunRiseSetTimes(ksal->getSunRise(), ksal->getSunSet());
122 ui->avt->setLimits(-12.0, 12.0, -90.0, 90.0);
123 ui->avt->axis(KPlotWidget::BottomAxis)->setTickLabelFormat('t');
124 ui->avt->axis(KPlotWidget::BottomAxis)->setLabel(i18n("Local Time"));
125 ui->avt->axis(KPlotWidget::TopAxis)->setTickLabelFormat('t');
126 ui->avt->axis(KPlotWidget::TopAxis)->setTickLabelsShown(true);
127 ui->DateEdit->setDate(dt.date());
128 ui->SetLocation->setText(geo->fullName());
129 ui->ImagePreview->installEventFilter(this);
130 ui->WishListView->viewport()->installEventFilter(this);
131 ui->WishListView->installEventFilter(this);
132 ui->SessionView->viewport()->installEventFilter(this);
133 ui->SessionView->installEventFilter(this);
134 // setDefaultImage();
135 //Connections
136 connect(ui->WishListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotCenterObject()));
137 connect(ui->WishListView->selectionModel(),
138 SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(slotNewSelection()));
139 connect(ui->SessionView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
140 this, SLOT(slotNewSelection()));
141 connect(ui->WUTButton, SIGNAL(clicked()), this, SLOT(slotWUT()));
142 connect(ui->FindButton, SIGNAL(clicked()), this, SLOT(slotFind()));
143 connect(ui->OpenButton, SIGNAL(clicked()), this, SLOT(slotOpenList()));
144 connect(ui->SaveButton, SIGNAL(clicked()), this, SLOT(slotSaveSession()));
145 connect(ui->SaveAsButton, SIGNAL(clicked()), this, SLOT(slotSaveSessionAs()));
146 connect(ui->WizardButton, SIGNAL(clicked()), this, SLOT(slotWizard()));
147 connect(ui->batchAddButton, SIGNAL(clicked()), this, SLOT(slotBatchAdd()));
148 connect(ui->SetLocation, SIGNAL(clicked()), this, SLOT(slotLocation()));
149 connect(ui->Update, SIGNAL(clicked()), this, SLOT(slotUpdate()));
150 connect(ui->DeleteImage, SIGNAL(clicked()), this, SLOT(slotDeleteCurrentImage()));
151 connect(ui->SearchImage, SIGNAL(clicked()), this, SLOT(slotSearchImage()));
152 connect(ui->SetTime, SIGNAL(clicked()), this, SLOT(slotSetTime()));
153 connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotChangeTab(int)));
154 connect(ui->saveImages, SIGNAL(clicked()), this, SLOT(slotSaveAllImages()));
155 connect(ui->DeleteAllImages, SIGNAL(clicked()), this, SLOT(slotDeleteAllImages()));
156 connect(ui->OALExport, SIGNAL(clicked()), this, SLOT(slotOALExport()));
157 connect(ui->clearListB, SIGNAL(clicked()), this, SLOT(slotClearList()));
158 //Add icons to Push Buttons
159 ui->OpenButton->setIcon(QIcon::fromTheme("document-open"));
160 ui->OpenButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
161 ui->SaveButton->setIcon(QIcon::fromTheme("document-save"));
162 ui->SaveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
163 ui->SaveAsButton->setIcon(
164 QIcon::fromTheme("document-save-as"));
165 ui->SaveAsButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
166 ui->WizardButton->setIcon(QIcon::fromTheme("tools-wizard"));
167 ui->WizardButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
168 noSelection = true;
169 showScope = false;
170 ui->NotesEdit->setEnabled(false);
171 ui->SetTime->setEnabled(false);
172 ui->TimeEdit->setEnabled(false);
173 ui->SearchImage->setEnabled(false);
174 ui->saveImages->setEnabled(false);
175 ui->DeleteImage->setEnabled(false);
176 ui->OALExport->setEnabled(false);
177
178 m_NoImagePixmap =
179 QPixmap(":/images/noimage.png")
180 .scaled(ui->ImagePreview->width(), ui->ImagePreview->height(), Qt::KeepAspectRatio, Qt::FastTransformation);
181 m_altCostHelper = [this](const SkyPoint & p) -> QStandardItem *
182 {
183 const double inf = std::numeric_limits<double>::infinity();
184 double altCost = 0.;
185 QString itemText;
186 double maxAlt = p.maxAlt(*(geo->lat()));
187 if (Options::obsListDemoteHole() && maxAlt > 90. - Options::obsListHoleSize())
188 maxAlt = 90. - Options::obsListHoleSize();
189 if (maxAlt <= 0.)
190 {
191 altCost = -inf;
192 itemText = i18n("Never rises");
193 }
194 else
195 {
196 altCost = (p.alt().Degrees() / maxAlt) * 100.;
197 if (altCost < 0)
198 itemText = i18nc("Short text to describe that object has not risen yet", "Not risen");
199 else
200 {
201 if (altCost > 100.)
202 {
203 altCost = -inf;
204 itemText = i18nc("Object is in the Dobsonian hole", "In hole");
205 }
206 else
207 itemText = QString::number(altCost, 'f', 0) + '%';
208 }
209 }
210
211 QStandardItem *altItem = new QStandardItem(itemText);
212 altItem->setData(altCost, Qt::UserRole);
213 // qCDebug(KSTARS) << "Updating altitude for " << p.ra().toHMSString() << " " << p.dec().toDMSString() << " alt = " << p.alt().toDMSString() << " info to " << itemText;
214 return altItem;
215 };
216
217 // Needed to fix weird bug on Windows that started with Qt 5.9 that makes the title bar
218 // not visible and therefore dialog not movable.
219#ifdef Q_OS_WIN
220 move(100, 100);
221#endif
222}
223
224void ObservingList::showEvent(QShowEvent *)
225{
226 // ONLY run for first ever load
227
228 if (m_initialWishlistLoad == false)
229 {
230 m_initialWishlistLoad = true;
231
232 slotLoadWishList(); //Load the wishlist from disk if present
233 m_CurrentObject = nullptr;
235
237 m_altitudeUpdater = new QTimer(this);
238 connect(m_altitudeUpdater, SIGNAL(timeout()), this, SLOT(slotUpdateAltitudes()));
239 m_altitudeUpdater->start(120000); // update altitudes every 2 minutes
240 }
241}
242
243//SLOTS
244
245void ObservingList::slotAddObject(const SkyObject *_obj, bool session, bool update)
246{
247 if (!m_initialWishlistLoad)
248 {
249 showEvent(nullptr); // Initialize the observing wishlist
250 }
251 bool addToWishList = true;
252 if (!_obj)
253 _obj = SkyMap::Instance()->clickedObject(); // Eh? Why? Weird default behavior.
254
255 if (!_obj)
256 {
257 qCWarning(KSTARS) << "Trying to add null object to observing list! Ignoring.";
258 return;
259 }
260
261 QString finalObjectName = getObjectName(_obj);
262
263 if (finalObjectName.isEmpty())
264 {
265 KSNotification::sorry(i18n("Stars and objects whose names KStars does not know are not supported in the observing lists"));
266 return;
267 }
268
269 //First, make sure object is not already in the list
270 QSharedPointer<SkyObject> obj = findObject(_obj);
271 if (obj)
272 {
273 addToWishList = false;
274 if (!session)
275 {
277 i18n("%1 is already in your wishlist.", finalObjectName),
278 0); // FIXME: This message is too inconspicuous if using the Find dialog to add
279 return;
280 }
281 }
282 else
283 {
284 assert(!findObject(_obj, session));
285 qCDebug(KSTARS) << "Cloned object " << finalObjectName << " to add to observing list.";
287 _obj->clone()); // Use a clone in case the original SkyObject is deleted due to change in catalog configuration.
288 }
289
290 if (session && sessionList().contains(obj))
291 {
292 KStars::Instance()->statusBar()->showMessage(i18n("%1 is already in the session plan.", finalObjectName), 0);
293 return;
294 }
295
296 // JM: If we are loading observing list from disk, solar system objects magnitudes are not calculated until later
297 // Therefore, we manual invoke updateCoords to force computation of magnitude.
298 if ((obj->type() == SkyObject::COMET || obj->type() == SkyObject::ASTEROID || obj->type() == SkyObject::MOON ||
299 obj->type() == SkyObject::PLANET) &&
300 obj->mag() == 0)
301 {
302 KSNumbers num(dt.djd());
303 CachingDms LST = geo->GSTtoLST(dt.gst());
304 obj->updateCoords(&num, true, geo->lat(), &LST, true);
305 }
306
307 QString smag = "--";
308 if (-30.0 < obj->mag() && obj->mag() < 90.0)
309 smag = QString::number(obj->mag(), 'f', 2); // The lower limit to avoid display of unrealistic comet magnitudes
310
311 SkyPoint p = obj->recomputeHorizontalCoords(dt, geo);
312
313 QList<QStandardItem *> itemList;
314
315 auto getItemWithUserRole = [](const QString & itemText) -> QStandardItem *
316 {
317 QStandardItem *ret = new QStandardItem(itemText);
318 ret->setData(itemText, Qt::UserRole);
319 return ret;
320 };
321
322 // Fill itemlist with items that are common to both wishlist additions and session plan additions
323 auto populateItemList = [&getItemWithUserRole, &itemList, &finalObjectName, obj, &p, &smag]()
324 {
325 itemList.clear();
326 QStandardItem *keyItem = getItemWithUserRole(finalObjectName);
327 keyItem->setData(QVariant::fromValue<void *>(static_cast<void *>(obj.data())), Qt::UserRole + 1);
328 itemList
329 << keyItem // NOTE: The rest of the methods assume that the SkyObject pointer is available in the first column!
330 << getItemWithUserRole(obj->translatedLongName()) << getItemWithUserRole(p.ra0().toHMSString())
331 << getItemWithUserRole(p.dec0().toDMSString()) << getItemWithUserRole(smag)
332 << getItemWithUserRole(obj->typeName());
333 };
334
335 //Insert object in the Wish List
336 if (addToWishList)
337 {
338 m_WishList.append(obj);
339 m_CurrentObject = obj.data();
340
341 //QString ra, dec;
342 //ra = "";//p.ra().toHMSString();
343 //dec = p.dec().toDMSString();
344
345 populateItemList();
346 // FIXME: Instead sort by a "clever" observability score, calculated as follows:
347 // - First sort by (max altitude) - (current altitude) rounded off to the nearest
348 // - Weight by declination - latitude (in the northern hemisphere, southern objects get higher precedence)
349 // - Demote objects in the hole
350 SkyPoint p = obj->recomputeHorizontalCoords(KStarsDateTime::currentDateTimeUtc(), geo); // Current => now
351 itemList << m_altCostHelper(p);
352 m_WishListModel->appendRow(itemList);
353
354 //Note addition in statusbar
355 KStars::Instance()->statusBar()->showMessage(i18n("Added %1 to observing list.", finalObjectName), 0);
356 ui->WishListView->resizeColumnsToContents();
357 if (!update)
358 slotSaveList();
359 }
360 //Insert object in the Session List
361 if (session)
362 {
363 m_SessionList.append(obj);
364 dt.setTime(TimeHash.value(finalObjectName, obj->transitTime(dt, geo)));
365 dms lst(geo->GSTtoLST(dt.gst()));
366 p.EquatorialToHorizontal(&lst, geo->lat());
367
368 QString alt = "--", az = "--";
369
370 QStandardItem *BestTime = new QStandardItem();
371 /* QString ra, dec;
372 if(obj->name() == "star" ) {
373 ra = obj->ra0().toHMSString();
374 dec = obj->dec0().toDMSString();
375 BestTime->setData( QString( "--" ), Qt::DisplayRole );
376 }
377 else {*/
378 BestTime->setData(TimeHash.value(finalObjectName, obj->transitTime(dt, geo)), Qt::DisplayRole);
379 alt = p.alt().toDMSString();
380 az = p.az().toDMSString();
381 //}
382 // TODO: Change the rest of the parameters to their appropriate datatypes.
383 populateItemList();
384 itemList << getItemWithUserRole(KSUtils::constNameToAbbrev(
385 KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(obj.data())))
386 << BestTime << getItemWithUserRole(alt) << getItemWithUserRole(az);
387
388 m_SessionModel->appendRow(itemList);
389 //Adding an object should trigger the modified flag
390 isModified = true;
391 ui->SessionView->resizeColumnsToContents();
392 //Note addition in statusbar
393 KStars::Instance()->statusBar()->showMessage(i18n("Added %1 to session list.", finalObjectName), 0);
394 SkyMap::Instance()->forceUpdate();
395 }
397}
398
399void ObservingList::slotRemoveObject(const SkyObject *_o, bool session, bool update)
400{
401 if (!update) // EH?!
402 {
403 if (!_o)
404 _o = SkyMap::Instance()->clickedObject();
405 else if (sessionView) //else if is needed as clickedObject should not be removed from the session list.
406 session = true;
407 }
408
409 // Is the pointer supplied in our own lists?
410 const QList<QSharedPointer<SkyObject>> &list = (session ? sessionList() : obsList());
411 QStandardItemModel *currentModel = (session ? m_SessionModel.get() : m_WishListModel.get());
412
413 QSharedPointer<SkyObject> o = findObject(_o, session);
414 if (!o)
415 {
416 qWarning() << "Object (name: " << getObjectName(o.data())
417 << ") supplied to ObservingList::slotRemoveObject() was not found in the "
418 << QString(session ? "session" : "observing") << " list!";
419 return;
420 }
421
422 int k = list.indexOf(o);
423 assert(k >= 0);
424
425 // Remove from hash
426 ImagePreviewHash.remove(o.data());
427
428 if (o.data() == LogObject)
430
431 //Remove row from the TableView model
432 // FIXME: Is there no faster way?
433 for (int irow = 0; irow < currentModel->rowCount(); ++irow)
434 {
435 QString name = currentModel->item(irow, 0)->text();
436 if (getObjectName(o.data()) == name)
437 {
438 currentModel->removeRow(irow);
439 break;
440 }
441 }
442
443 if (!session)
444 {
445 obsList().removeAt(k);
446 ui->avt->removeAllPlotObjects();
447 ui->WishListView->resizeColumnsToContents();
448 if (!update)
449 slotSaveList();
450 }
451 else
452 {
453 if (!update)
454 TimeHash.remove(o->name());
455 sessionList().removeAt(k); //Remove from the session list
456 isModified = true; //Removing an object should trigger the modified flag
457 ui->avt->removeAllPlotObjects();
458 ui->SessionView->resizeColumnsToContents();
459 SkyMap::Instance()->forceUpdate();
460 }
461}
462
464{
465 //Find each object by name in the session list, and remove it
466 //Go backwards so item alignment doesn't get screwed up as rows are removed.
467 for (int irow = getActiveModel()->rowCount() - 1; irow >= 0; --irow)
468 {
469 bool rowSelected;
470 if (sessionView)
471 rowSelected = ui->SessionView->selectionModel()->isRowSelected(irow, QModelIndex());
472 else
473 rowSelected = ui->WishListView->selectionModel()->isRowSelected(irow, QModelIndex());
474
475 if (rowSelected)
476 {
477 QModelIndex sortIndex, index;
478 sortIndex = getActiveSortModel()->index(irow, 0);
479 index = getActiveSortModel()->mapToSource(sortIndex);
480 SkyObject *o = static_cast<SkyObject *>(index.data(Qt::UserRole + 1).value<void *>());
481 Q_ASSERT(o);
482 slotRemoveObject(o, sessionView);
483 }
484 }
485
486 if (sessionView)
487 {
488 //we've removed all selected objects, so clear the selection
489 ui->SessionView->selectionModel()->clear();
490 //Update the lists in the Execute window as well
491 KStarsData::Instance()->executeSession()->init();
492 }
493
495 ui->ImagePreview->setCursor(Qt::ArrowCursor);
496}
497
499{
500 bool found = false;
501 singleSelection = false;
502 noSelection = false;
503 showScope = false;
504 //ui->ImagePreview->clearPreview();
505 //ui->ImagePreview->setPixmap(QPixmap());
506 ui->ImagePreview->setCursor(Qt::ArrowCursor);
507 QModelIndexList selectedItems;
508 QString newName;
510 QString labelText;
511 ui->DeleteImage->setEnabled(false);
512
513 selectedItems =
514 getActiveSortModel()->mapSelectionToSource(getActiveView()->selectionModel()->selection()).indexes();
515
516 if (selectedItems.size() == getActiveModel()->columnCount())
517 {
518 newName = selectedItems[0].data().toString();
519 singleSelection = true;
520 //Find the selected object in the SessionList,
521 //then break the loop. Now SessionList.current()
522 //points to the new selected object (until now it was the previous object)
523 for (auto &o_temp : getActiveList())
524 {
525 if (getObjectName(o_temp.data()) == newName)
526 {
527 o = o_temp;
528 found = true;
529 break;
530 }
531 }
532 }
533
534 if (singleSelection)
535 {
536 //Enable buttons
537 ui->ImagePreview->setCursor(Qt::PointingHandCursor);
538#ifdef HAVE_INDI
539 showScope = true;
540#endif
541 if (found)
542 {
543 m_CurrentObject = o.data();
544 //QPoint pos(0,0);
545 plot(o.data());
546 //Change the m_currentImageFileName, DSS/SDSS Url to correspond to the new object
548 ui->SearchImage->setEnabled(true);
549 if (currentObject()->hasName())
550 {
551 //Display the current object's user notes in the NotesEdit
552 //First, save the last object's user log to disk, if necessary
553 saveCurrentUserLog(); //uses LogObject, which is still the previous obj.
554 //set LogObject to the new selected object
555 LogObject = currentObject();
556 ui->NotesEdit->setEnabled(true);
557
558 const auto &userLog =
559 KStarsData::Instance()->getUserData(LogObject->name()).userLog;
560
561 if (userLog.isEmpty())
562 {
563 ui->NotesEdit->setPlainText(
564 i18n("Record here observation logs and/or data on %1.", getObjectName(LogObject)));
565 }
566 else
567 {
568 ui->NotesEdit->setPlainText(userLog);
569 }
570 if (sessionView)
571 {
572 ui->TimeEdit->setEnabled(true);
573 ui->SetTime->setEnabled(true);
574 ui->TimeEdit->setTime(TimeHash.value(o->name(), o->transitTime(dt, geo)));
575 }
576 }
577 else //selected object is named "star"
578 {
579 //clear the log text box
581 ui->NotesEdit->clear();
582 ui->NotesEdit->setEnabled(false);
583 ui->SearchImage->setEnabled(false);
584 }
585 QString ImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentImageFileName);
586 if (!ImagePath.isEmpty())
587 {
588 //If the image is present, show it!
589 KSDssImage ksdi(ImagePath);
590 KSDssImage::Metadata md = ksdi.getMetadata();
591 //ui->ImagePreview->showPreview( QUrl::fromLocalFile( ksdi.getFileName() ) );
592 if (ImagePreviewHash.contains(o.data()) == false)
593 ImagePreviewHash[o.data()] = QPixmap(ksdi.getFileName()).scaledToHeight(ui->ImagePreview->width());
594
595 //ui->ImagePreview->setPixmap(QPixmap(ksdi.getFileName()).scaledToHeight(ui->ImagePreview->width()));
596 ui->ImagePreview->setPixmap(ImagePreviewHash[o.data()]);
597 if (md.isValid())
598 {
599 ui->dssMetadataLabel->setText(
600 i18n("DSS Image metadata: \n Size: %1\' x %2\' \n Photometric band: %3 \n Version: %4",
602 }
603 else
604 ui->dssMetadataLabel->setText(i18n("No image info available."));
605 ui->ImagePreview->show();
606 ui->DeleteImage->setEnabled(true);
607 }
608 else
609 {
611 ui->dssMetadataLabel->setText(
612 i18n("No image available. Click on the placeholder image to download one."));
613 }
614 QString cname =
615 KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(o.data());
616 if (o->type() != SkyObject::CONSTELLATION)
617 {
618 labelText = "<b>";
619 if (o->type() == SkyObject::PLANET)
620 labelText += o->translatedName();
621 else
622 labelText += o->name();
623 if (std::isfinite(o->mag()) && o->mag() <= 30.)
624 labelText += ":</b> " + i18nc("%1 magnitude of object, %2 type of sky object (planet, asteroid "
625 "etc), %3 name of a constellation",
626 "%1 mag %2 in %3", o->mag(), o->typeName().toLower(), cname);
627 else
628 labelText +=
629 ":</b> " + i18nc("%1 type of sky object (planet, asteroid etc), %2 name of a constellation",
630 "%1 in %2", o->typeName(), cname);
631 }
632 }
633 else
634 {
636 qCWarning(KSTARS) << "Object " << newName << " not found in list.";
637 }
638 ui->quickInfoLabel->setText(labelText);
639 }
640 else
641 {
642 if (selectedItems.isEmpty()) //Nothing selected
643 {
644 //Disable buttons
645 noSelection = true;
646 ui->NotesEdit->setEnabled(false);
647 m_CurrentObject = nullptr;
648 ui->TimeEdit->setEnabled(false);
649 ui->SetTime->setEnabled(false);
650 ui->SearchImage->setEnabled(false);
651 //Clear the user log text box.
653 ui->NotesEdit->setPlainText("");
654 //Clear the plot in the AVTPlotwidget
655 ui->avt->removeAllPlotObjects();
656 }
657 else //more than one object selected.
658 {
659 ui->NotesEdit->setEnabled(false);
660 ui->TimeEdit->setEnabled(false);
661 ui->SetTime->setEnabled(false);
662 ui->SearchImage->setEnabled(false);
663 m_CurrentObject = nullptr;
664 //Clear the plot in the AVTPlotwidget
665 ui->avt->removeAllPlotObjects();
666 //Clear the user log text box.
668 ui->NotesEdit->setPlainText("");
669 ui->quickInfoLabel->setText(QString());
670 }
671 }
672}
673
675{
676 if (getSelectedItems().size() == 1)
677 {
678 SkyMap::Instance()->setClickedObject(currentObject());
679 SkyMap::Instance()->setClickedPoint(currentObject());
680 SkyMap::Instance()->slotCenter();
681 }
682}
683
685{
686#ifdef HAVE_INDI
687
688 if (INDIListener::Instance()->size() == 0)
689 {
690 KSNotification::sorry(i18n("No connected mounts found."));
691 return;
692 }
693
694 for (auto &oneDevice : INDIListener::devices())
695 {
696 if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
697 continue;
698
699 if (oneDevice->isConnected() == false)
700 {
701 KSNotification::error(i18n("Mount %1 is offline. Please connect and retry again.", oneDevice->getDeviceName()));
702 return;
703 }
704
705 auto mount = oneDevice->getMount();
706 if (!mount)
707 continue;
708 mount->Slew(currentObject());
709 return;
710 }
711
712 KSNotification::sorry(i18n("No connected mounts found."));
713
714#endif
715}
716
718{
719#ifdef HAVE_INDI
720 Ekos::Manager::Instance()->addObjectToScheduler(currentObject());
721#endif
722}
723
724//FIXME: This will open multiple Detail windows for each object;
725//Should have one window whose target object changes with selection
727{
728 if (currentObject())
729 {
731 new DetailDialog(currentObject(), KStarsData::Instance()->ut(), geo, KStars::Instance());
732 dd->exec();
733 delete dd;
734 }
735}
736
738{
739 KStarsDateTime lt = dt;
740 lt.setTime(QTime(8, 0, 0));
741 QPointer<WUTDialog> w = new WUTDialog(KStars::Instance(), sessionView, geo, lt);
742 w->exec();
743 delete w;
744}
745
747{
748 Q_ASSERT(!sessionView);
749 if (getSelectedItems().size())
750 {
751 foreach (const QModelIndex &i, getSelectedItems())
752 {
754 if (getObjectName(o.data()) == i.data().toString())
756 o.data(),
757 true); // FIXME: Would be good to have a wrapper that accepts QSharedPointer<SkyObject>
758 }
759 }
760}
761
763{
764 if (FindDialog::Instance()->exec() == QDialog::Accepted)
765 {
766 SkyObject *o = FindDialog::Instance()->targetObject();
767 if (o != nullptr)
768 {
769 slotAddObject(o, sessionView);
770 }
771 }
772}
773
775{
776 bool accepted = false;
778 sessionView ? i18n("Batch add to observing session") : i18n("Batch add to observing wishlist"),
779 i18n("Specify a list of objects with one object on each line to add. The names must be understood to KStars, or if the internet resolver is enabled in settings, to the CDS Sesame resolver. Objects that are internet resolved will be added to the database."),
780 QString(),
781 &accepted);
782 bool resolve = Options::resolveNamesOnline();
783
784 if (accepted && !items.isEmpty())
785 {
786 QStringList failedObjects;
787 QStringList objectNames = items.split("\n");
788 for (QString objectName : objectNames)
789 {
790 objectName = FindDialog::processSearchText(objectName);
791 SkyObject *object = KStarsData::Instance()->objectNamed(objectName);
792 if (!object && resolve)
793 {
794 object = FindDialog::resolveAndAdd(m_manager, objectName);
795 }
796 if (!object)
797 {
798 failedObjects.append(objectName);
799 }
800 else
801 {
802 slotAddObject(object, sessionView);
803 }
804 }
805
806 if (!failedObjects.isEmpty())
807 {
808 QMessageBox msgBox =
809 {
810 QMessageBox::Icon::Warning,
811 i18np("Batch add: %1 object not found", "Batch add: %1 objects not found", failedObjects.size()),
812 i18np("%1 object could not be found in the database or resolved, and hence could not be added. See the details for more.",
813 "%1 objects could not be found in the database or resolved, and hence could not be added. See the details for more.",
814 failedObjects.size()),
816 this
817 };
818 msgBox.setDetailedText(failedObjects.join("\n"));
819 msgBox.exec();
820 }
821 }
822 Q_ASSERT(false); // Not implemented
823}
824
829
831{
832 QModelIndexList selectedItems;
833 // TODO: Think and see if there's a more efficient way to do this. I can't seem to think of any, but this code looks like it could be improved. - Akarsh
834 selectedItems =
835 (sessionView ?
836 m_SessionSortModel->mapSelectionToSource(ui->SessionView->selectionModel()->selection()).indexes() :
837 m_WishListSortModel->mapSelectionToSource(ui->WishListView->selectionModel()->selection()).indexes());
838
839 if (selectedItems.size())
840 {
842 foreach (const QModelIndex &i, selectedItems)
843 {
844 if (i.column() == 0)
845 {
846 SkyObject *o = static_cast<SkyObject *>(i.data(Qt::UserRole + 1).value<void *>());
847 Q_ASSERT(o);
848 avt->processObject(o);
849 }
850 }
851 avt->exec();
852 delete avt;
853 }
854}
855
856//FIXME: On close, we will need to close any open Details/AVT windows
857void ObservingList::slotClose()
858{
859 //Save the current User log text
861 ui->avt->removeAllPlotObjects();
864 hide();
865}
866
868{
869 if (LogObject && !ui->NotesEdit->toPlainText().isEmpty() &&
870 ui->NotesEdit->toPlainText() !=
871 i18n("Record here observation logs and/or data on %1.", getObjectName(LogObject)))
872 {
873 const auto &success = KStarsData::Instance()->updateUserLog(
874 LogObject->name(), ui->NotesEdit->toPlainText());
875
876 if (!success.first)
877 KSNotification::sorry(success.second, i18n("Could not update the user log."));
878
879 ui->NotesEdit->clear();
880 LogObject = nullptr;
881 }
882}
883
885{
886 QUrl fileURL = QFileDialog::getOpenFileUrl(KStars::Instance(), i18nc("@title:window", "Open Observing List"), QUrl(),
887 "KStars Observing List (*.obslist)");
888 QFile f;
889
890 if (fileURL.isValid())
891 {
892 f.setFileName(fileURL.toLocalFile());
893 //FIXME do we still need to do this?
894 /*
895 if ( ! fileURL.isLocalFile() ) {
896 //Save remote list to a temporary local file
897 QTemporaryFile tmpfile;
898 tmpfile.setAutoRemove(false);
899 tmpfile.open();
900 m_listFileName = tmpfile.fileName();
901 if( KIO::NetAccess::download( fileURL, m_listFileName, this ) )
902 f.setFileName( m_listFileName );
903
904 } else {
905 m_listFileName = fileURL.toLocalFile();
906 f.setFileName( m_listFileName );
907 }
908 */
909
910 if (!f.open(QIODevice::ReadOnly))
911 {
912 QString message = i18n("Could not open file %1", f.fileName());
913 KSNotification::sorry(message, i18n("Could Not Open File"));
914 return;
915 }
916 saveCurrentList(); //See if the current list needs to be saved before opening the new one
917 ui->tabWidget->setCurrentIndex(1); // FIXME: This is not robust -- asimha
918 slotChangeTab(1);
919
920 sessionList().clear();
921 TimeHash.clear();
922 m_CurrentObject = nullptr;
923 m_SessionModel->removeRows(0, m_SessionModel->rowCount());
924 SkyMap::Instance()->forceUpdate();
925 //First line is the name of the list. The rest of the file is
926 //object names, one per line. With the TimeHash value if present
927 QTextStream istream(&f);
928 QString input;
929 input = istream.readAll();
930 OAL::Log logObject;
931 logObject.readBegin(input);
932 //Set the New TimeHash
933 TimeHash = logObject.timeHash();
934 GeoLocation *geo_new = logObject.geoLocation();
935 if (!geo_new)
936 {
937 // FIXME: This is a very hackish solution -- if we
938 // encounter an invalid XML file, we know we won't read a
939 // GeoLocation successfully. It does not detect partially
940 // corrupt files. -- asimha
941 KSNotification::sorry(i18n("The specified file is invalid. We expect an XML file based on the OpenAstronomyLog schema."));
942 f.close();
943 return;
944 }
945 dt = logObject.dateTime();
946 //foreach (SkyObject *o, *(logObject.targetList()))
947 for (auto &o : logObject.targetList())
948 slotAddObject(o.data(), true);
949 //Update the location and user set times from file
950 slotUpdate();
951 //Newly-opened list should not trigger isModified flag
952 isModified = false;
953 f.close();
954 }
955 else if (!fileURL.toLocalFile().isEmpty())
956 {
957 KSNotification::sorry(i18n("The specified file is invalid"));
958 }
959}
960
962{
963 if ((ui->tabWidget->currentIndex() == 0 && obsList().isEmpty()) ||
964 (ui->tabWidget->currentIndex() == 1 && sessionList().isEmpty()))
965 return;
966
967 QString message = i18n("Are you sure you want to clear all objects?");
968 if (KMessageBox::warningContinueCancel(this, message, i18n("Clear all?")) == KMessageBox::Continue)
969 {
970 // Did I forget anything else to remove?
971 ui->avt->removeAllPlotObjects();
972 m_CurrentObject = LogObject = nullptr;
973
974 if (ui->tabWidget->currentIndex() == 0)
975 {
976 // IMPORTANT: Is this enough or we will have dangling pointers in memory?
977 ImagePreviewHash.clear();
978 obsList().clear();
979 m_WishListModel->setRowCount(0);
980 }
981 else
982 {
983 // IMPORTANT: Is this enough or we will have dangling pointers in memory?
984 sessionList().clear();
985 TimeHash.clear();
986 isModified = true; //Removing an object should trigger the modified flag
987 m_SessionModel->setRowCount(0);
988 SkyMap::Instance()->forceUpdate();
989 }
990 }
991}
992
994{
995 //Before loading a new list, do we need to save the current one?
996 //Assume that if the list is empty, then there's no need to save
997 if (sessionList().size())
998 {
999 if (isModified)
1000 {
1001 QString message = i18n("Do you want to save the current session?");
1002 if (KMessageBox::warningContinueCancel(this, message, i18n("Save Current session?"), KStandardGuiItem::save(),
1005 }
1006 }
1007}
1008
1010{
1011 if (sessionList().isEmpty())
1012 return;
1013
1014 QUrl fileURL = QFileDialog::getSaveFileUrl(KStars::Instance(), i18nc("@title:window", "Save Observing List"), QUrl(),
1015 "KStars Observing List (*.obslist)");
1016 if (fileURL.isValid())
1017 {
1018 m_listFileName = fileURL.toLocalFile();
1019 slotSaveSession(nativeSave);
1020 }
1021}
1022
1024{
1025 QFile f;
1026 // FIXME: Move wishlist into a database.
1027 // TODO: Support multiple wishlists.
1028
1029 QString fileContents;
1030 QTextStream ostream(
1031 &fileContents); // We first write to a QString to prevent truncating the file in case there is a crash.
1032 foreach (const QSharedPointer<SkyObject> o, obsList())
1033 {
1034 if (!o)
1035 {
1036 qWarning() << "Null entry in observing wishlist! Skipping!";
1037 continue;
1038 }
1039 if (o->name() == "star")
1040 {
1041 //ostream << o->name() << " " << o->ra0().Hours() << " " << o->dec0().Degrees() << Qt::endl;
1042 ostream << getObjectName(o.data(), false) << '\n';
1043 }
1044 else if (o->type() == SkyObject::STAR)
1045 {
1046 Q_ASSERT(dynamic_cast<const StarObject *>(o.data()));
1047 const QSharedPointer<StarObject> s = qSharedPointerCast<StarObject>(o);
1048 if (s->name() == s->gname())
1049 ostream << s->name2() << '\n';
1050 else
1051 ostream << s->name() << '\n';
1052 }
1053 else
1054 {
1055 ostream << o->name() << '\n';
1056 }
1057 }
1058 f.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("wishlist.obslist"));
1059 if (!f.open(QIODevice::WriteOnly))
1060 {
1061 qWarning() << "Cannot save wish list to file!"; // TODO: This should be presented as a message box to the user
1062 KMessageBox::error(this,
1063 i18n("Could not open the observing wishlist file %1 for writing. Your wishlist changes will not be saved. Check if the location is writable and not full.",
1064 f.fileName()), i18n("Could not save observing wishlist"));
1065 return;
1066 }
1067 QTextStream writeemall(&f);
1068 writeemall << fileContents;
1069 f.close();
1070}
1071
1073{
1074 QFile f;
1075 f.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("wishlist.obslist"));
1076 if (!f.open(QIODevice::ReadOnly))
1077 {
1078 qWarning(KSTARS) << "No WishList Saved yet";
1079 return;
1080 }
1081 QTextStream istream(&f);
1082 QString line;
1083
1084 QPointer<QProgressDialog> addingObjectsProgress = new QProgressDialog();
1085 addingObjectsProgress->setWindowTitle(i18nc("@title:window", "Observing List Wizard"));
1086 addingObjectsProgress->setLabelText(i18n("Please wait while loading observing wishlist..."));
1087
1088
1089 // Read the entire file in one pass so we can show better progress indication
1090 QStringList objects;
1091 while (!istream.atEnd())
1092 {
1093 objects.append(istream.readLine());
1094 }
1095 addingObjectsProgress->setMaximum(objects.size());
1096 addingObjectsProgress->setMinimum(0);
1097 addingObjectsProgress->show();
1098
1099 QStringList failedObjects;
1100 for (int idx = 0; idx < objects.size(); ++idx)
1101 {
1102 const auto &objectName = objects[idx];
1103
1104 if (addingObjectsProgress->wasCanceled())
1105 {
1106 QMessageBox msgBox =
1107 {
1108 QMessageBox::Icon::Warning,
1109 i18n("Canceling this will truncate your wishlist"),
1110 i18n("If you cancel this operation, your wishlist will be truncated and the following objects will be removed from the wishlist when you exit KStars. Are you sure this is okay?"),
1112 this
1113 };
1115 msgBox.setDetailedText(objects.mid(idx).join("\n") + "\n");
1116 if (msgBox.exec() == QMessageBox::Yes)
1117 break;
1118 else
1119 {
1120 addingObjectsProgress->reset();
1121 addingObjectsProgress->setValue(idx);
1122 addingObjectsProgress->show();
1123 }
1124
1125 }
1126
1127 SkyObject *o = KStarsData::Instance()->objectNamed(objectName);
1128
1129 //If we haven't identified the object, try interpreting the
1130 //name as a star's genetive name (with ascii letters)
1131 if (!o)
1132 o = KStarsData::Instance()->skyComposite()->findStarByGenetiveName(line);
1133
1134 if (o)
1135 {
1136 slotAddObject(o, false, true);
1137 }
1138 else
1139 {
1140 failedObjects.append(line);
1141 }
1142
1143 addingObjectsProgress->setValue(idx + 1);
1144 qApp->processEvents();
1145 }
1146 delete (addingObjectsProgress);
1147 f.close();
1148
1149 if (!failedObjects.isEmpty())
1150 {
1151 QMessageBox msgBox = {QMessageBox::Icon::Warning,
1152 i18np("Observing wishlist truncated: %1 object not found", "Observing wishlist truncated: %1 objects not found", failedObjects.size()),
1153 i18np("%1 object could not be found in the database, and will be removed from the observing wish list. We recommend that you copy its name as a backup so you can add it later.", "%1 objects could not be found in the database, and will be removed from the observing wish list. We recommend that you copy the detailed list as a backup, whereby you can later use the Batch Add feature in the Observation Planner to add them back using internet search.", failedObjects.size()),
1155 this
1156 };
1157 msgBox.setDetailedText(failedObjects.join("\n") + "\n");
1158 msgBox.exec();
1159 }
1160}
1161
1163{
1164 if (sessionList().isEmpty())
1165 {
1166 KSNotification::error(i18n("Cannot save an empty session list."));
1167 return;
1168 }
1169
1170 if (m_listFileName.isEmpty())
1171 {
1172 slotSaveSessionAs(nativeSave);
1173 return;
1174 }
1175 QFile f(m_listFileName);
1176 if (!f.open(QIODevice::WriteOnly))
1177 {
1178 QString message = i18n("Could not open file %1. Try a different filename?", f.fileName());
1179 if (KMessageBox::warningContinueCancel(nullptr, message, i18n("Could Not Open File"), KGuiItem(i18n("Try Different")),
1180 KGuiItem(i18n("Do Not Try"))) == KMessageBox::Continue)
1181 {
1182 m_listFileName.clear();
1183 slotSaveSessionAs(nativeSave);
1184 }
1185 return;
1186 }
1187 QTextStream ostream(&f);
1188 OAL::Log log;
1189 ostream << log.writeLog(nativeSave);
1190 f.close();
1191 isModified = false; //We've saved the session, so reset the modified flag.
1192}
1193
1195{
1197 if (wizard->exec() == QDialog::Accepted)
1198 {
1199 QPointer<QProgressDialog> addingObjectsProgress = new QProgressDialog();
1200 addingObjectsProgress->setWindowTitle(i18nc("@title:window", "Observing List Wizard"));
1201 addingObjectsProgress->setLabelText(i18n("Please wait while adding objects..."));
1202 addingObjectsProgress->setMaximum(wizard->obsList().size());
1203 addingObjectsProgress->setMinimum(0);
1204 addingObjectsProgress->setValue(0);
1205 addingObjectsProgress->show();
1206 int counter = 1;
1207 foreach (SkyObject *o, wizard->obsList())
1208 {
1209 slotAddObject(o);
1210 addingObjectsProgress->setValue(counter++);
1211 if (addingObjectsProgress->wasCanceled())
1212 break;
1213 qApp->processEvents();
1214 }
1215 delete addingObjectsProgress;
1216 }
1217
1218 delete wizard;
1219}
1220
1222{
1223 if (!o)
1224 return;
1225 float DayOffset = 0;
1226 if (TimeHash.value(o->name(), o->transitTime(dt, geo)).hour() > 12)
1227 DayOffset = 1;
1228
1229 QDateTime midnight = QDateTime(dt.date(), QTime());
1230 KStarsDateTime ut = geo->LTtoUT(KStarsDateTime(midnight));
1231 double h1 = geo->GSTtoLST(ut.gst()).Hours();
1232 if (h1 > 12.0)
1233 h1 -= 24.0;
1234
1235 ui->avt->setSecondaryLimits(h1, h1 + 24.0, -90.0, 90.0);
1236 ksal->setLocation(geo);
1237 ksal->setDate(ut);
1238 ui->avt->setGeoLocation(geo);
1239 ui->avt->setSunRiseSetTimes(ksal->getSunRise(), ksal->getSunSet());
1240 ui->avt->setDawnDuskTimes(ksal->getDawnAstronomicalTwilight(), ksal->getDuskAstronomicalTwilight());
1241 ui->avt->setMinMaxSunAlt(ksal->getSunMinAlt(), ksal->getSunMaxAlt());
1242 ui->avt->setMoonRiseSetTimes(ksal->getMoonRise(), ksal->getMoonSet());
1243 ui->avt->setMoonIllum(ksal->getMoonIllum());
1244 ui->avt->update();
1246 for (double h = -12.0; h <= 12.0; h += 0.5)
1247 {
1248 po->addPoint(h, findAltitude(o, (h + DayOffset * 24.0)));
1249 }
1250 ui->avt->removeAllPlotObjects();
1251 ui->avt->addPlotObject(po);
1252}
1253
1255{
1256 // Jasem 2015-09-05 Using correct procedure to find altitude
1257 SkyPoint sp = *p; // make a copy
1258 QDateTime midnight = QDateTime(dt.date(), QTime());
1259 KStarsDateTime ut = geo->LTtoUT(KStarsDateTime(midnight));
1260 KStarsDateTime targetDateTime = ut.addSecs(hour * 3600.0);
1261 dms LST = geo->GSTtoLST(targetDateTime.gst());
1262 sp.EquatorialToHorizontal(&LST, geo->lat());
1263 return sp.alt().Degrees();
1264}
1265
1267{
1268 noSelection = true;
1270 ui->NotesEdit->setEnabled(false);
1271 ui->TimeEdit->setEnabled(false);
1272 ui->SetTime->setEnabled(false);
1273 ui->SearchImage->setEnabled(false);
1274 ui->DeleteImage->setEnabled(false);
1275 m_CurrentObject = nullptr;
1276 sessionView = index != 0;
1278 ui->WizardButton->setEnabled(!sessionView); //wizard adds only to the Wish List
1279 ui->OALExport->setEnabled(sessionView);
1280 //Clear the selection in the Tables
1281 ui->WishListView->clearSelection();
1282 ui->SessionView->clearSelection();
1283 //Clear the user log text box.
1285 ui->NotesEdit->setPlainText("");
1286 ui->avt->removeAllPlotObjects();
1287}
1288
1290{
1292 if (ld->exec() == QDialog::Accepted)
1293 {
1294 geo = ld->selectedCity();
1295 ui->SetLocation->setText(geo->fullName());
1296 }
1297 delete ld;
1298}
1299
1301{
1302 dt.setDate(ui->DateEdit->date());
1303 ui->avt->removeAllPlotObjects();
1304 //Creating a copy of the lists, we can't use the original lists as they'll keep getting modified as the loop iterates
1305 QList<QSharedPointer<SkyObject>> _obsList = m_WishList, _SessionList = m_SessionList;
1306
1307 for (QSharedPointer<SkyObject> &o : _obsList)
1308 {
1309 if (o->name() != "star")
1310 {
1311 slotRemoveObject(o.data(), false, true);
1312 slotAddObject(o.data(), false, true);
1313 }
1314 }
1315 for (QSharedPointer<SkyObject> &obj : _SessionList)
1316 {
1317 if (obj->name() != "star")
1318 {
1319 slotRemoveObject(obj.data(), true, true);
1320 slotAddObject(obj.data(), true, true);
1321 }
1322 }
1323 SkyMap::Instance()->forceUpdate();
1324}
1325
1327{
1328 SkyObject *o = currentObject();
1329 slotRemoveObject(o, true);
1330 TimeHash[o->name()] = ui->TimeEdit->time();
1331 slotAddObject(o, true, true);
1332}
1333
1335{
1336 ui->SearchImage->setEnabled(false);
1337 //ui->ImagePreview->clearPreview();
1338 ui->ImagePreview->setPixmap(QPixmap());
1339
1341 bool ok = true;
1342
1343 int width = QInputDialog::getInt(this, i18n("Customized DSS Download"), i18n("Specify image width (arcminutes): "),
1344 15, 15, 75, 1, &ok);
1345 int height = QInputDialog::getInt(this, i18n("Customized DSS Download"),
1346 i18n("Specify image height (arcminutes): "), 15, 15, 75, 1, &ok);
1347 QStringList strList = (QStringList() << "poss2ukstu_blue"
1348 << "poss2ukstu_red"
1349 << "poss2ukstu_ir"
1350 << "poss1_blue"
1351 << "poss1_red"
1352 << "quickv"
1353 << "all");
1354 QString version =
1355 QInputDialog::getItem(this, i18n("Customized DSS Download"), i18n("Specify version: "), strList, 0, false, &ok);
1356
1357 QUrl srcUrl(KSDssDownloader::getDSSURL(currentObject()->ra0(), currentObject()->dec0(), width, height, "gif",
1358 version, &md));
1359
1360 delete m_dl;
1361 m_dl = new KSDssDownloader();
1362 connect(m_dl, SIGNAL(downloadComplete(bool)), SLOT(downloadReady(bool)));
1363 m_dl->startSingleDownload(srcUrl, getCurrentImagePath(), md);
1364}
1365
1367{
1368 dss = _dss;
1369 if (!o)
1370 o = currentObject();
1371 ui->SearchImage->setEnabled(false);
1372 setCurrentImage(o);
1373 QString currentImagePath = getCurrentImagePath();
1374 if (QFile::exists(currentImagePath))
1375 QFile::remove(currentImagePath);
1376 //QUrl url;
1377 dss = true;
1378 std::function<void(bool)> slot = std::bind(&ObservingList::downloadReady, this, std::placeholders::_1);
1379 new KSDssDownloader(o, currentImagePath, slot, this);
1380}
1381
1382void ObservingList::downloadReady(bool success)
1383{
1384 // set downloadJob to 0, but don't delete it - the job will be deleted automatically
1385 // downloadJob = 0;
1386
1387 delete m_dl;
1388 m_dl = nullptr; // required if we came from slotCustomDSS; does nothing otherwise
1389
1390 if (!success)
1391 {
1392 KSNotification::sorry(i18n("Failed to download DSS/SDSS image."));
1393 }
1394 else
1395 {
1396 /*
1397 if( QFile( QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(m_currentImageFileName) ).size() > 13000)
1398 //The default image is around 8689 bytes
1399 */
1400 //ui->ImagePreview->showPreview( QUrl::fromLocalFile( getCurrentImagePath() ) );
1401 ui->ImagePreview->setPixmap(QPixmap(getCurrentImagePath()).scaledToHeight(ui->ImagePreview->width()));
1403 ui->ImagePreview->show();
1404 ui->ImagePreview->setCursor(Qt::PointingHandCursor);
1405 ui->DeleteImage->setEnabled(true);
1406 }
1407 /*
1408 // FIXME: Implement a priority order SDSS > DSS in the DSS downloader
1409 else if( ! dss )
1410 slotGetImage( true );
1411 */
1412}
1413
1415{
1416 QString sanitizedName = o->name().remove(' ').remove('\'').remove('\"').toLower();
1417
1418 // JM: Always use .png across all platforms. No JPGs at all?
1419 m_currentImageFileName = "image-" + sanitizedName + ".png";
1420
1421 m_currentThumbImageFileName = "thumb-" + sanitizedName + ".png";
1422
1423 // Does full image exists in the path?
1424 QString currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentImageFileName);
1425
1426 // Let's try to fallback to thumb-* images if they exist
1427 if (currentImagePath.isEmpty())
1428 {
1429 currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentThumbImageFileName);
1430
1431 // If thumb image exists, let's use it
1432 if (currentImagePath.isEmpty() == false)
1433 m_currentImageFileName = m_currentThumbImageFileName;
1434 }
1435
1436 // 2017-04-14: Unnamed stars already unsupported in observing list
1437 /*
1438 if( o->name() == "star" )
1439 {
1440 QString RAString( o->ra0().toHMSString() );
1441 QString DecString( o->dec0().toDMSString() );
1442 m_currentImageFileName = "Image_J" + RAString.remove(' ').remove( ':' ) + DecString.remove(' ').remove( ':' ); // Note: Changed naming convention to standard 2016-08-25 asimha; old images shall have to be re-downloaded.
1443 // Unnecessary complication below:
1444 // QChar decsgn = ( (o->dec0().Degrees() < 0.0 ) ? '-' : '+' );
1445 // m_currentImageFileName = m_currentImageFileName.remove('+').remove('-') + decsgn;
1446 }
1447 */
1448
1449 // 2017-04-14 JM: If we use .png always, let us use it across all platforms.
1450 /*
1451 QString imagePath = getCurrentImagePath();
1452 if ( QFile::exists( imagePath)) // New convention -- append filename extension so file is usable on Windows etc.
1453 {
1454 QFile::rename( imagePath, imagePath + ".png" );
1455 }
1456 m_currentImageFileName += ".png";
1457 */
1458}
1459
1461{
1462 QString currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentImageFileName);
1463 if (QFile::exists(currentImagePath))
1464 {
1465 return currentImagePath;
1466 }
1467 else
1468 return QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(m_currentImageFileName);
1469}
1470
1472{
1473 ui->SearchImage->setEnabled(false);
1474 ui->DeleteImage->setEnabled(false);
1475 m_CurrentObject = nullptr;
1476 //Clear the selection in the Tables
1477 ui->WishListView->clearSelection();
1478 ui->SessionView->clearSelection();
1479
1480 foreach (QSharedPointer<SkyObject> o, getActiveList())
1481 {
1482 if (!o)
1483 continue; // FIXME: Why would we have null objects? But appears that we do.
1484 setCurrentImage(o.data());
1486 // QUrl url( ( Options::obsListPreferDSS() ) ? DSSUrl : SDSSUrl ); // FIXME: We have removed SDSS support!
1488 if (!o->isSolarSystem()) //TODO find a way for adding support for solar system images
1489 saveImage(url, img, o.data());
1490 }
1491}
1492
1493void ObservingList::saveImage(QUrl /*url*/, QString /*filename*/, const SkyObject *o)
1494{
1495 if (!o)
1496 o = currentObject();
1497 Q_ASSERT(o);
1499 {
1500 // Call the DSS downloader
1501 slotGetImage(true, o);
1502 }
1503}
1504
1506{
1508 QString currentImagePath = getCurrentImagePath();
1509 if (QFile::exists(currentImagePath))
1510 {
1511 QUrl url = QUrl::fromLocalFile(currentImagePath);
1512 iv = new ImageViewer(url);
1513 }
1514
1515 if (iv)
1516 iv->show();
1517}
1518
1520{
1521 if (KMessageBox::warningContinueCancel(nullptr, i18n("This will delete all saved images. Are you sure you want to do this?"),
1522 i18n("Delete All Images")) == KMessageBox::Cancel)
1523 return;
1524 ui->ImagePreview->setCursor(Qt::ArrowCursor);
1525 ui->SearchImage->setEnabled(false);
1526 ui->DeleteImage->setEnabled(false);
1527 m_CurrentObject = nullptr;
1528 //Clear the selection in the Tables
1529 ui->WishListView->clearSelection();
1530 ui->SessionView->clearSelection();
1531 //ui->ImagePreview->clearPreview();
1532 ui->ImagePreview->setPixmap(QPixmap());
1533 QDirIterator iterator(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
1534 while (iterator.hasNext())
1535 {
1536 // TODO: Probably, there should be a different directory for cached images in the observing list.
1537 if (iterator.fileName().contains("Image") && (!iterator.fileName().contains("dat")) &&
1538 (!iterator.fileName().contains("obslist")))
1539 {
1540 QFile file(iterator.filePath());
1541 file.remove();
1542 }
1543 iterator.next();
1544 }
1545}
1546
1548{
1549 ui->saveImages->setEnabled(!getActiveList().isEmpty());
1550}
1551
1552// FIXME: Is there a reason to implement these as an event filter,
1553// instead of as a signal-slot connection? Shouldn't we just use slots
1554// to subscribe to various events from the Table / Session view?
1555//
1556// NOTE: ui->ImagePreview is a QLabel, which has no clicked() event or
1557// public mouseReleaseEvent(), so eventFilter makes sense.
1559{
1560 if (obj == ui->ImagePreview)
1561 {
1562 if (event->type() == QEvent::MouseButtonRelease)
1563 {
1564 if (currentObject())
1565 {
1567 {
1568 if (!currentObject()->isSolarSystem())
1569 slotGetImage(Options::obsListPreferDSS());
1570 else
1571 slotSearchImage();
1572 }
1573 else
1575 }
1576 return true;
1577 }
1578 }
1579 if (obj == ui->WishListView->viewport() || obj == ui->SessionView->viewport())
1580 {
1581 bool sessionViewEvent = (obj == ui->SessionView->viewport());
1582
1583 if (event->type() == QEvent::MouseButtonRelease) // Mouse button release event
1584 {
1585 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
1586 QPoint pos(mouseEvent->globalX(), mouseEvent->globalY());
1587
1588 if (mouseEvent->button() == Qt::RightButton)
1589 {
1590 if (!noSelection)
1591 {
1592 pmenu->initPopupMenu(sessionViewEvent, !singleSelection, showScope);
1593 pmenu->popup(pos);
1594 }
1595 return true;
1596 }
1597 }
1598 }
1599
1600 if (obj == ui->WishListView || obj == ui->SessionView)
1601 {
1602 if (event->type() == QEvent::KeyPress)
1603 {
1604 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
1605 if (keyEvent->key() == Qt::Key_Delete)
1606 {
1608 return true;
1609 }
1610 }
1611 }
1612
1613 return false;
1614}
1615
1616void ObservingList::slotSearchImage()
1617{
1618 QPixmap *pm = new QPixmap(":/images/noimage.png");
1619 QPointer<ThumbnailPicker> tp = new ThumbnailPicker(currentObject(), *pm, this, 200, 200, i18n("Image Chooser"));
1620 if (tp->exec() == QDialog::Accepted)
1621 {
1622 QString currentImagePath = getCurrentImagePath();
1623 QFile f(currentImagePath);
1624
1625 //If a real image was set, save it.
1626 if (tp->imageFound())
1627 {
1628 const auto image = *tp->image();
1629 image.save(f.fileName(), "PNG");
1630 //ui->ImagePreview->showPreview( QUrl::fromLocalFile( f.fileName() ) );
1633 ui->ImagePreview->setPixmap(image.scaledToHeight(ui->ImagePreview->width()));
1634 ui->ImagePreview->repaint();
1635 }
1636 }
1637 delete pm;
1638 delete tp;
1639}
1640
1642{
1644 ImagePreviewHash.remove(m_CurrentObject);
1646}
1647
1649{
1650 QFileInfo const f(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(
1651 m_currentThumbImageFileName));
1652 if (!f.exists())
1653 {
1656 img.save(f.filePath());
1657 }
1658}
1659
1660QString ObservingList::getTime(const SkyObject *o) const
1661{
1662 return TimeHash.value(o->name(), QTime(30, 0, 0)).toString("h:mm:ss AP");
1663}
1664
1665QTime ObservingList::scheduledTime(SkyObject *o) const
1666{
1667 return TimeHash.value(o->name(), o->transitTime(dt, geo));
1668}
1669
1670void ObservingList::setTime(const SkyObject *o, QTime t)
1671{
1672 TimeHash.insert(o->name(), t);
1673}
1674
1676{
1677 slotSaveSessionAs(false);
1678}
1679
1680void ObservingList::slotAddVisibleObj()
1681{
1682 KStarsDateTime lt = dt;
1683 lt.setTime(QTime(8, 0, 0));
1684 QPointer<WUTDialog> w = new WUTDialog(KStars::Instance(), sessionView, geo, lt);
1685 w->init();
1686 QModelIndexList selectedItems;
1687 selectedItems =
1688 m_WishListSortModel->mapSelectionToSource(ui->WishListView->selectionModel()->selection()).indexes();
1689 if (selectedItems.size())
1690 {
1691 foreach (const QModelIndex &i, selectedItems)
1692 {
1693 foreach (QSharedPointer<SkyObject> o, obsList())
1694 if (getObjectName(o.data()) == i.data().toString() && w->checkVisibility(o.data()))
1696 o.data(),
1697 true); // FIXME: Better if there is a QSharedPointer override for this, although the check will ensure that we don't duplicate.
1698 }
1699 }
1700 delete w;
1701}
1702
1704{
1706 {
1707 if (getObjectName(o.data(), false) == name)
1708 return o.data();
1709 }
1710 return nullptr;
1711}
1712
1714{
1715 ui->tabWidget->setCurrentIndex(1);
1716 ui->SessionView->selectionModel()->clear();
1717 for (int irow = m_SessionModel->rowCount() - 1; irow >= 0; --irow)
1718 {
1719 QModelIndex mSortIndex = m_SessionSortModel->index(irow, 0);
1720 QModelIndex mIndex = m_SessionSortModel->mapToSource(mSortIndex);
1721 int idxrow = mIndex.row();
1722 if (m_SessionModel->item(idxrow, 0)->text() == getObjectName(o))
1723 ui->SessionView->selectRow(idxrow);
1725 }
1726}
1727
1729{
1730 ui->ImagePreview->setPixmap(m_NoImagePixmap);
1731 ui->ImagePreview->update();
1732}
1733
1735{
1736 QString finalObjectName;
1737 if (o->name() == "star")
1738 {
1739 const StarObject *s = dynamic_cast<const StarObject *>(o);
1740
1741 // JM: Enable HD Index stars to be added to the observing list.
1742 if (s != nullptr && s->getHDIndex() != 0)
1743 finalObjectName = QString("HD %1").arg(QString::number(s->getHDIndex()));
1744 }
1745 else
1746 finalObjectName = translated ? o->translatedName() : o->name();
1747
1748 return finalObjectName;
1749}
1750
1752{
1753 // FIXME: Update upon gaining visibility, do not update when not visible
1755 // qCDebug(KSTARS) << "Updating altitudes in observation planner @ JD - J2000 = " << double( now.djd() - J2000 );
1756 for (int irow = m_WishListModel->rowCount() - 1; irow >= 0; --irow)
1757 {
1758 QModelIndex idx = m_WishListSortModel->mapToSource(m_WishListSortModel->index(irow, 0));
1759 SkyObject *o = static_cast<SkyObject *>(idx.data(Qt::UserRole + 1).value<void *>());
1760 Q_ASSERT(o);
1761 SkyPoint p = o->recomputeHorizontalCoords(now, geo);
1762 idx =
1763 m_WishListSortModel->mapToSource(m_WishListSortModel->index(irow, m_WishListSortModel->columnCount() - 1));
1764 QStandardItem *replacement = m_altCostHelper(p);
1765 m_WishListModel->setData(idx, replacement->data(Qt::DisplayRole), Qt::DisplayRole);
1766 m_WishListModel->setData(idx, replacement->data(Qt::UserRole), Qt::UserRole);
1767 delete replacement;
1768 }
1769 emit m_WishListModel->dataChanged(
1770 m_WishListModel->index(0, m_WishListModel->columnCount() - 1),
1771 m_WishListModel->index(m_WishListModel->rowCount() - 1, m_WishListModel->columnCount() - 1));
1772}
1773
1774QSharedPointer<SkyObject> ObservingList::findObject(const SkyObject *o, bool session)
1775{
1776 const QList<QSharedPointer<SkyObject>> &list = (session ? sessionList() : obsList());
1777 const QString &target = getObjectName(o);
1778 foreach (QSharedPointer<SkyObject> obj, list)
1779 {
1780 if (getObjectName(obj.data()) == target)
1781 return obj;
1782 }
1783 return QSharedPointer<SkyObject>(); // null pointer
1784}
the Altitude vs.
Definition altvstime.h:41
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition cachingdms.h:19
DetailDialog is a window showing detailed information for a selected object.
static CatalogObject * resolveAndAdd(CatalogsDB::DBManager &db_manager, const QString &query)
Resolves an object using the internet and adds it to the database.
SkyObject * targetObject()
Definition finddialog.h:53
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
Definition geolocation.h:28
QString fullName() const
const CachingDms * lat() const
Definition geolocation.h:70
void addPoint(const QPointF &p, const QString &label=QString(), double barWidth=0.0)
A class that implements methods to find sun rise, sun set, twilight begin / end times,...
Definition ksalmanac.h:27
Helps download a DSS image.
void startSingleDownload(const QUrl srcUrl, const QString &destFileName, KSDssImage::Metadata &md)
Stateful single-download of a supplied URL.
static QString getDSSURL(const SkyPoint *const p, const QString &version="all", struct KSDssImage::Metadata *md=nullptr)
High-level method to create a URL to obtain a DSS image for a given SkyPoint.
Provides a class to hold a DSS Image along with its metadata.
Definition ksdssimage.h:21
There are several time-dependent values used in position calculations, that are not specific to an ob...
Definition ksnumbers.h:43
SkyObject * objectNamed(const QString &name)
Find object by name.
std::pair< bool, QString > updateUserLog(const QString &name, const QString &newLog)
Update the user log of the object with the name to contain newLog (find and replace).
const SkyObjectUserdata::Data & getUserData(const QString &name)
Get a reference to the user data of an object with the name name.
GeoLocation * geo()
Definition kstarsdata.h:230
SkyMapComposite * skyComposite()
Definition kstarsdata.h:166
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addSecs(double s) const
void setDate(const QDate &d)
Assign the Date according to a QDate object.
static KStarsDateTime currentDateTimeUtc()
static KStarsDateTime currentDateTime()
long double djd() const
void setTime(const QTime &t)
Assign the Time according to a QTime object.
This is the main window for KStars.
Definition kstars.h:91
static KStars * Instance()
Definition kstars.h:123
void slotEyepieceView(SkyPoint *sp, const QString &imagePath=QString())
Show the eyepiece view tool.
Dialog for changing the geographic location of the observer.
The Popup Menu for the observing list in KStars.
Wizard for constructing observing lists.
void slotUpdateAltitudes()
Recalculate and update the values of the altitude in the wishlist for the current time.
void saveThumbImage()
saves a thumbnail image for the details dialog from the downloaded image
void slotLoadWishList()
Load the Wish list from disk.
void saveCurrentList()
If the current list has unsaved changes, ask the user about saving it.
void slotSaveSessionAs(bool nativeSave=true)
save the current observing session plan to disk, specify filename.
void slotOALExport()
Export a target list to the oal compliant format.
QString getCurrentImagePath()
Returns a path to the current image, or a writable image.
QList< QSharedPointer< SkyObject > > & sessionList()
void slotFind()
Open the Find Dialog.
void setDefaultImage()
set the default image in the image preview.
void setCurrentImage(const SkyObject *o)
Sets the image parameters for the current object o The passed object for setting the parameters.
void slotUpdate()
Updates the tableviews for the new geolocation and date.
QString getObjectName(const SkyObject *o, bool translated=true)
get object name.
void slotImageViewer()
Shows the image in a ImageViewer window.
QList< QSharedPointer< SkyObject > > & obsList()
void slotSaveAllImages()
Downloads the images of all the objects in the session list Note: This downloads the SDSS image,...
void slotAddToSession()
Add the object to the Session List.
void slotAVT()
Show the Altitude vs Time for selecteld objects.
void slotWizard()
construct a new observing list using the wizard.
void setSaveImagesButton()
decides on whether to enable the SaveImages button or not
void slotAddObject(const SkyObject *o=nullptr, bool session=false, bool update=false)
add a new object to list o pointer to the object to add to the list session flag toggle adding the ob...
void slotOpenList()
load an observing list from disk.
void slotGetImage(bool _dss=false, const SkyObject *o=nullptr)
Downloads the corresponding DSS or SDSS image from the web and displays it.
void slotLocation()
Opens the Location dialog to set the GeoLocation for the sessionlist.
void slotRemoveSelectedObjects()
Remove skyobjects which are highlighted in the observing list tool from the observing list.
bool contains(const SkyObject *o, bool session=false)
void slotAddToEkosScheduler()
slotAddToEkosScheduler Add object to Ekos scheduler
void slotClearList()
slotClearList Remove all objects from current list
void slotDeleteAllImages()
Removes all the save DSS/SDSS images from the disk.
void slotBatchAdd()
Batch add from a list of objects.
SkyObject * currentObject() const
void saveImage(QUrl url, QString filename, const SkyObject *o=nullptr)
saves the image synchronously from a given URL into a given file url the url from which the image has...
void slotWUT()
Open the WUT dialog.
void slotEyepieceView()
Show the eyepiece field view.
void slotCustomDSS()
Present the user with options to get the right DSS image for the job.
void selectObject(const SkyObject *o)
make a selection in the session view
void saveCurrentUserLog()
Save the user log text to a file.
SkyObject * findObjectByName(QString name)
return the object with the name as the passed QString from the Session List, return null otherwise
void slotCenterObject()
center the selected object in the display
void slotDeleteCurrentImage()
Remove the current image.
void slotSlewToObject()
slew the telescope to the selected object
double findAltitude(SkyPoint *p, double hour=0)
Return the altitude of the given SkyObject for the given hour.
void slotSetTime()
Takes the time from the QTimeEdit box and sets it as the time parameter in the tableview of the Sessi...
void slotDetails()
Show the details window for the selected object.
void slotNewSelection()
Tasks needed when changing the selected object Save the user log of the previous selected object,...
void plot(SkyObject *o)
Plot the SkyObject's Altitude vs Time in the AVTPlotWidget.
void slotChangeTab(int index)
toggle the setEnabled flags according to current view set the m_currentItem to nullptr and clear sele...
bool eventFilter(QObject *obj, QEvent *event) override
This is the declaration of the event filter function which is installed on the KImageFilePreview and ...
void slotSaveList()
save the current observing list to disk.
void slotSaveSession(bool nativeSave=true)
save the current session
void slotRemoveObject(const SkyObject *o=nullptr, bool session=false, bool update=false)
Remove skyobject from the observing list.
Sort best observation times by reimplementing lessThan() to work on the transit times of objects.
void setClickedPoint(const SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
Definition skymap.cpp:1012
void setClickedObject(SkyObject *o)
Set the ClickedObject pointer to the argument.
Definition skymap.cpp:366
void forceUpdate(bool now=false)
Recalculates the positions of objects in the sky, and then repaints the sky map.
Definition skymap.cpp:1177
SkyObject * clickedObject() const
Retrieve the object nearest to a mouse click event.
Definition skymap.h:244
void slotCenter()
Center the display at the point ClickedPoint.
Definition skymap.cpp:380
Provides all necessary information about an object in the sky: its coordinates, name(s),...
Definition skyobject.h:42
SkyPoint recomputeHorizontalCoords(const KStarsDateTime &dt, const GeoLocation *geo) const
Like recomputeCoords, but also calls EquatorialToHorizontal before returning.
virtual SkyObject * clone() const
Create copy of object.
Definition skyobject.cpp:50
QString translatedName() const
Definition skyobject.h:148
virtual QString name(void) const
Definition skyobject.h:145
QTime transitTime(const KStarsDateTime &dt, const GeoLocation *geo) const
The same iteration technique described in riseSetTime() is used here.
The sky coordinates of a point in the sky.
Definition skypoint.h:45
const CachingDms & ra0() const
Definition skypoint.h:251
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
Definition skypoint.cpp:77
const dms & az() const
Definition skypoint.h:275
const dms & alt() const
Definition skypoint.h:281
const CachingDms & dec0() const
Definition skypoint.h:257
This is a subclass of SkyObject.
Definition starobject.h:33
int getHDIndex() const
Definition starobject.h:248
Dialog for modifying an object's thumbnail image.
What's up tonight dialog is a window which lists all sky objects that will be visible during the next...
Definition wutdialog.h:40
An angle, stored as degrees, but expressible in many ways.
Definition dms.h:38
double Hours() const
Definition dms.h:168
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition dms.cpp:287
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
Definition dms.cpp:378
const double & Degrees() const
Definition dms.h:141
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT CopyJob * move(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KGuiItem save()
KGuiItem discard()
bool removeRow(int row, const QModelIndex &parent)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QDate date() const const
void accepted()
virtual int exec()
QString filePath(const QString &fileName) const const
QString fileName() const const
QString filePath() const const
bool hasNext() const const
QString next()
MouseButtonRelease
bool exists() const const
bool remove()
QUrl getOpenFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
void clear()
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
bool remove(const Key &key)
T value(const Key &key) const const
QIcon fromTheme(const QString &name)
bool save(QIODevice *device, const char *format, int quality) const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int getInt(QWidget *parent, const QString &title, const QString &label, int value, int min, int max, int step, bool *ok, Qt::WindowFlags flags)
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current, bool editable, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
QString getMultiLineText(QWidget *parent, const QString &title, const QString &label, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
QModelIndexList indexes() const const
void append(QList< T > &&value)
void clear()
bool isEmpty() const const
void removeAt(qsizetype i)
qsizetype size() const const
QStatusBar * statusBar() const const
void setDetailedText(const QString &text)
virtual int exec() override
void setDefaultButton(QPushButton *button)
int column() const const
QVariant data(int role) const const
int row() const const
int globalX() const const
int globalY() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QPixmap scaledToHeight(int height, Qt::TransformationMode mode) const const
T * data() const const
Qt::MouseButton button() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
virtual QItemSelection mapSelectionToSource(const QItemSelection &proxySelection) const const override
virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const const override
virtual QVariant data(int role) const const
virtual void setData(const QVariant &value, int role)
QString text() const const
QStandardItem * item(int row, int column) const const
virtual int rowCount(const QModelIndex &parent) const const override
void showMessage(const QString &message, int timeout)
QString arg(Args &&... args) const const
void clear()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QChar * data()
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString toLower() const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
QString join(QChar separator) const const
KeepAspectRatio
ArrowCursor
StrongFocus
UserRole
Key_Delete
RightButton
FastTransformation
WA_LayoutUsesWidgetRect
bool atEnd() const const
QString readAll()
QString readLine(qint64 maxlen)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void start()
QUrl fromLocalFile(const QString &localFile)
bool isValid() const const
QString toLocalFile() const const
QVariant fromValue(T &&value)
QString toString() const const
void setCursor(const QCursor &)
void setEnabled(bool)
virtual bool event(QEvent *event) override
void hide()
void repaint()
void show()
void update()
Structure to hold some DSS image metadata.
QString version
Used for DSS – Indicates which version of scans to pull.
Definition ksdssimage.h:65
float height
Height in arcminutes.
Definition ksdssimage.h:77
float width
Width in arcminutes.
Definition ksdssimage.h:79
char band
Photometric band (UBVRI...) Use "?" for unknown.
Definition ksdssimage.h:81
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.