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

KDE's Doxygen guidelines are available online.