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 {
789 objectName = FindDialog::processSearchText(objectName);
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 for (double h = -12.0; h <= 12.0; h += 0.5)
1241 {
1242 po->addPoint(h, findAltitude(o, (h + DayOffset * 24.0)));
1243 }
1244 ui->avt->removeAllPlotObjects();
1245 ui->avt->addPlotObject(po);
1246}
1247
1248double ObservingList::findAltitude(SkyPoint *p, double hour)
1249{
1250 // Jasem 2015-09-05 Using correct procedure to find altitude
1251 SkyPoint sp = *p; // make a copy
1252 QDateTime midnight = QDateTime(dt.date(), QTime());
1253 KStarsDateTime ut = geo->LTtoUT(KStarsDateTime(midnight));
1254 KStarsDateTime targetDateTime = ut.addSecs(hour * 3600.0);
1255 dms LST = geo->GSTtoLST(targetDateTime.gst());
1256 sp.EquatorialToHorizontal(&LST, geo->lat());
1257 return sp.alt().Degrees();
1258}
1259
1261{
1262 noSelection = true;
1264 ui->NotesEdit->setEnabled(false);
1265 ui->TimeEdit->setEnabled(false);
1266 ui->SetTime->setEnabled(false);
1267 ui->SearchImage->setEnabled(false);
1268 ui->DeleteImage->setEnabled(false);
1269 m_CurrentObject = nullptr;
1270 sessionView = index != 0;
1272 ui->WizardButton->setEnabled(!sessionView); //wizard adds only to the Wish List
1273 ui->OALExport->setEnabled(sessionView);
1274 //Clear the selection in the Tables
1275 ui->WishListView->clearSelection();
1276 ui->SessionView->clearSelection();
1277 //Clear the user log text box.
1279 ui->NotesEdit->setPlainText("");
1280 ui->avt->removeAllPlotObjects();
1281}
1282
1284{
1286 if (ld->exec() == QDialog::Accepted)
1287 {
1288 geo = ld->selectedCity();
1289 ui->SetLocation->setText(geo->fullName());
1290 }
1291 delete ld;
1292}
1293
1295{
1296 dt.setDate(ui->DateEdit->date());
1297 ui->avt->removeAllPlotObjects();
1298 //Creating a copy of the lists, we can't use the original lists as they'll keep getting modified as the loop iterates
1299 QList<QSharedPointer<SkyObject>> _obsList = m_WishList, _SessionList = m_SessionList;
1300
1301 for (QSharedPointer<SkyObject> &o : _obsList)
1302 {
1303 if (o->name() != "star")
1304 {
1305 slotRemoveObject(o.data(), false, true);
1306 slotAddObject(o.data(), false, true);
1307 }
1308 }
1309 for (QSharedPointer<SkyObject> &obj : _SessionList)
1310 {
1311 if (obj->name() != "star")
1312 {
1313 slotRemoveObject(obj.data(), true, true);
1314 slotAddObject(obj.data(), true, true);
1315 }
1316 }
1317 SkyMap::Instance()->forceUpdate();
1318}
1319
1321{
1322 SkyObject *o = currentObject();
1323 slotRemoveObject(o, true);
1324 TimeHash[o->name()] = ui->TimeEdit->time();
1325 slotAddObject(o, true, true);
1326}
1327
1329{
1330 ui->SearchImage->setEnabled(false);
1331 //ui->ImagePreview->clearPreview();
1332 ui->ImagePreview->setPixmap(QPixmap());
1333
1335 bool ok = true;
1336
1337 int width = QInputDialog::getInt(this, i18n("Customized DSS Download"), i18n("Specify image width (arcminutes): "),
1338 15, 15, 75, 1, &ok);
1339 int height = QInputDialog::getInt(this, i18n("Customized DSS Download"),
1340 i18n("Specify image height (arcminutes): "), 15, 15, 75, 1, &ok);
1341 QStringList strList = (QStringList() << "poss2ukstu_blue"
1342 << "poss2ukstu_red"
1343 << "poss2ukstu_ir"
1344 << "poss1_blue"
1345 << "poss1_red"
1346 << "quickv"
1347 << "all");
1348 QString version =
1349 QInputDialog::getItem(this, i18n("Customized DSS Download"), i18n("Specify version: "), strList, 0, false, &ok);
1350
1351 QUrl srcUrl(KSDssDownloader::getDSSURL(currentObject()->ra0(), currentObject()->dec0(), width, height, "gif",
1352 version, &md));
1353
1354 delete m_dl;
1355 m_dl = new KSDssDownloader();
1356 connect(m_dl, SIGNAL(downloadComplete(bool)), SLOT(downloadReady(bool)));
1357 m_dl->startSingleDownload(srcUrl, getCurrentImagePath(), md);
1358}
1359
1361{
1362 dss = _dss;
1363 if (!o)
1364 o = currentObject();
1365 ui->SearchImage->setEnabled(false);
1366 setCurrentImage(o);
1367 QString currentImagePath = getCurrentImagePath();
1368 if (QFile::exists(currentImagePath))
1369 QFile::remove(currentImagePath);
1370 //QUrl url;
1371 dss = true;
1372 std::function<void(bool)> slot = std::bind(&ObservingList::downloadReady, this, std::placeholders::_1);
1373 new KSDssDownloader(o, currentImagePath, slot, this);
1374}
1375
1376void ObservingList::downloadReady(bool success)
1377{
1378 // set downloadJob to 0, but don't delete it - the job will be deleted automatically
1379 // downloadJob = 0;
1380
1381 delete m_dl;
1382 m_dl = nullptr; // required if we came from slotCustomDSS; does nothing otherwise
1383
1384 if (!success)
1385 {
1386 KSNotification::sorry(i18n("Failed to download DSS/SDSS image."));
1387 }
1388 else
1389 {
1390 /*
1391 if( QFile( QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(m_currentImageFileName) ).size() > 13000)
1392 //The default image is around 8689 bytes
1393 */
1394 //ui->ImagePreview->showPreview( QUrl::fromLocalFile( getCurrentImagePath() ) );
1395 ui->ImagePreview->setPixmap(QPixmap(getCurrentImagePath()).scaledToHeight(ui->ImagePreview->width()));
1397 ui->ImagePreview->show();
1398 ui->ImagePreview->setCursor(Qt::PointingHandCursor);
1399 ui->DeleteImage->setEnabled(true);
1400 }
1401 /*
1402 // FIXME: Implement a priority order SDSS > DSS in the DSS downloader
1403 else if( ! dss )
1404 slotGetImage( true );
1405 */
1406}
1407
1409{
1410 QString sanitizedName = o->name().remove(' ').remove('\'').remove('\"').toLower();
1411
1412 // JM: Always use .png across all platforms. No JPGs at all?
1413 m_currentImageFileName = "image-" + sanitizedName + ".png";
1414
1415 m_currentThumbImageFileName = "thumb-" + sanitizedName + ".png";
1416
1417 // Does full image exists in the path?
1418 QString currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentImageFileName);
1419
1420 // Let's try to fallback to thumb-* images if they exist
1421 if (currentImagePath.isEmpty())
1422 {
1423 currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentThumbImageFileName);
1424
1425 // If thumb image exists, let's use it
1426 if (currentImagePath.isEmpty() == false)
1427 m_currentImageFileName = m_currentThumbImageFileName;
1428 }
1429
1430 // 2017-04-14: Unnamed stars already unsupported in observing list
1431 /*
1432 if( o->name() == "star" )
1433 {
1434 QString RAString( o->ra0().toHMSString() );
1435 QString DecString( o->dec0().toDMSString() );
1436 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.
1437 // Unnecessary complication below:
1438 // QChar decsgn = ( (o->dec0().Degrees() < 0.0 ) ? '-' : '+' );
1439 // m_currentImageFileName = m_currentImageFileName.remove('+').remove('-') + decsgn;
1440 }
1441 */
1442
1443 // 2017-04-14 JM: If we use .png always, let us use it across all platforms.
1444 /*
1445 QString imagePath = getCurrentImagePath();
1446 if ( QFile::exists( imagePath)) // New convention -- append filename extension so file is usable on Windows etc.
1447 {
1448 QFile::rename( imagePath, imagePath + ".png" );
1449 }
1450 m_currentImageFileName += ".png";
1451 */
1452}
1453
1455{
1456 QString currentImagePath = KSPaths::locate(QStandardPaths::AppLocalDataLocation, m_currentImageFileName);
1457 if (QFile::exists(currentImagePath))
1458 {
1459 return currentImagePath;
1460 }
1461 else
1462 return QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(m_currentImageFileName);
1463}
1464
1466{
1467 ui->SearchImage->setEnabled(false);
1468 ui->DeleteImage->setEnabled(false);
1469 m_CurrentObject = nullptr;
1470 //Clear the selection in the Tables
1471 ui->WishListView->clearSelection();
1472 ui->SessionView->clearSelection();
1473
1474 foreach (QSharedPointer<SkyObject> o, getActiveList())
1475 {
1476 if (!o)
1477 continue; // FIXME: Why would we have null objects? But appears that we do.
1478 setCurrentImage(o.data());
1480 // QUrl url( ( Options::obsListPreferDSS() ) ? DSSUrl : SDSSUrl ); // FIXME: We have removed SDSS support!
1482 if (!o->isSolarSystem()) //TODO find a way for adding support for solar system images
1483 saveImage(url, img, o.data());
1484 }
1485}
1486
1487void ObservingList::saveImage(QUrl /*url*/, QString /*filename*/, const SkyObject *o)
1488{
1489 if (!o)
1490 o = currentObject();
1491 Q_ASSERT(o);
1493 {
1494 // Call the DSS downloader
1495 slotGetImage(true, o);
1496 }
1497}
1498
1500{
1502 QString currentImagePath = getCurrentImagePath();
1503 if (QFile::exists(currentImagePath))
1504 {
1505 QUrl url = QUrl::fromLocalFile(currentImagePath);
1506 iv = new ImageViewer(url);
1507 }
1508
1509 if (iv)
1510 iv->show();
1511}
1512
1514{
1515 if (KMessageBox::warningContinueCancel(nullptr, i18n("This will delete all saved images. Are you sure you want to do this?"),
1516 i18n("Delete All Images")) == KMessageBox::Cancel)
1517 return;
1518 ui->ImagePreview->setCursor(Qt::ArrowCursor);
1519 ui->SearchImage->setEnabled(false);
1520 ui->DeleteImage->setEnabled(false);
1521 m_CurrentObject = nullptr;
1522 //Clear the selection in the Tables
1523 ui->WishListView->clearSelection();
1524 ui->SessionView->clearSelection();
1525 //ui->ImagePreview->clearPreview();
1526 ui->ImagePreview->setPixmap(QPixmap());
1527 QDirIterator iterator(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
1528 while (iterator.hasNext())
1529 {
1530 // TODO: Probably, there should be a different directory for cached images in the observing list.
1531 if (iterator.fileName().contains("Image") && (!iterator.fileName().contains("dat")) &&
1532 (!iterator.fileName().contains("obslist")))
1533 {
1534 QFile file(iterator.filePath());
1535 file.remove();
1536 }
1537 iterator.next();
1538 }
1539}
1540
1542{
1543 ui->saveImages->setEnabled(!getActiveList().isEmpty());
1544}
1545
1546// FIXME: Is there a reason to implement these as an event filter,
1547// instead of as a signal-slot connection? Shouldn't we just use slots
1548// to subscribe to various events from the Table / Session view?
1549//
1550// NOTE: ui->ImagePreview is a QLabel, which has no clicked() event or
1551// public mouseReleaseEvent(), so eventFilter makes sense.
1553{
1554 if (obj == ui->ImagePreview)
1555 {
1556 if (event->type() == QEvent::MouseButtonRelease)
1557 {
1558 if (currentObject())
1559 {
1561 {
1562 if (!currentObject()->isSolarSystem())
1563 slotGetImage(Options::obsListPreferDSS());
1564 else
1565 slotSearchImage();
1566 }
1567 else
1569 }
1570 return true;
1571 }
1572 }
1573 if (obj == ui->WishListView->viewport() || obj == ui->SessionView->viewport())
1574 {
1575 bool sessionViewEvent = (obj == ui->SessionView->viewport());
1576
1577 if (event->type() == QEvent::MouseButtonRelease) // Mouse button release event
1578 {
1579 QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
1580 QPoint pos(mouseEvent->globalX(), mouseEvent->globalY());
1581
1582 if (mouseEvent->button() == Qt::RightButton)
1583 {
1584 if (!noSelection)
1585 {
1586 pmenu->initPopupMenu(sessionViewEvent, !singleSelection, showScope);
1587 pmenu->popup(pos);
1588 }
1589 return true;
1590 }
1591 }
1592 }
1593
1594 if (obj == ui->WishListView || obj == ui->SessionView)
1595 {
1596 if (event->type() == QEvent::KeyPress)
1597 {
1598 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
1599 if (keyEvent->key() == Qt::Key_Delete)
1600 {
1602 return true;
1603 }
1604 }
1605 }
1606
1607 return false;
1608}
1609
1610void ObservingList::slotSearchImage()
1611{
1612 QPixmap *pm = new QPixmap(":/images/noimage.png");
1613 QPointer<ThumbnailPicker> tp = new ThumbnailPicker(currentObject(), *pm, this, 200, 200, i18n("Image Chooser"));
1614 if (tp->exec() == QDialog::Accepted)
1615 {
1616 QString currentImagePath = getCurrentImagePath();
1617 QFile f(currentImagePath);
1618
1619 //If a real image was set, save it.
1620 if (tp->imageFound())
1621 {
1622 const auto image = *tp->image();
1623 image.save(f.fileName(), "PNG");
1624 //ui->ImagePreview->showPreview( QUrl::fromLocalFile( f.fileName() ) );
1627 ui->ImagePreview->setPixmap(image.scaledToHeight(ui->ImagePreview->width()));
1628 ui->ImagePreview->repaint();
1629 }
1630 }
1631 delete pm;
1632 delete tp;
1633}
1634
1636{
1638 ImagePreviewHash.remove(m_CurrentObject);
1640}
1641
1643{
1644 QFileInfo const f(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(
1645 m_currentThumbImageFileName));
1646 if (!f.exists())
1647 {
1650 img.save(f.filePath());
1651 }
1652}
1653
1654QString ObservingList::getTime(const SkyObject *o) const
1655{
1656 return TimeHash.value(o->name(), QTime(30, 0, 0)).toString("h:mm:ss AP");
1657}
1658
1659QTime ObservingList::scheduledTime(SkyObject *o) const
1660{
1661 return TimeHash.value(o->name(), o->transitTime(dt, geo));
1662}
1663
1664void ObservingList::setTime(const SkyObject *o, QTime t)
1665{
1666 TimeHash.insert(o->name(), t);
1667}
1668
1670{
1671 slotSaveSessionAs(false);
1672}
1673
1674void ObservingList::slotAddVisibleObj()
1675{
1676 KStarsDateTime lt = dt;
1677 lt.setTime(QTime(8, 0, 0));
1678 QPointer<WUTDialog> w = new WUTDialog(KStars::Instance(), sessionView, geo, lt);
1679 w->init();
1680 QModelIndexList selectedItems;
1681 selectedItems =
1682 m_WishListSortModel->mapSelectionToSource(ui->WishListView->selectionModel()->selection()).indexes();
1683 if (selectedItems.size())
1684 {
1685 foreach (const QModelIndex &i, selectedItems)
1686 {
1687 foreach (QSharedPointer<SkyObject> o, obsList())
1688 if (getObjectName(o.data()) == i.data().toString() && w->checkVisibility(o.data()))
1690 o.data(),
1691 true); // FIXME: Better if there is a QSharedPointer override for this, although the check will ensure that we don't duplicate.
1692 }
1693 }
1694 delete w;
1695}
1696
1698{
1700 {
1701 if (getObjectName(o.data(), false) == name)
1702 return o.data();
1703 }
1704 return nullptr;
1705}
1706
1708{
1709 ui->tabWidget->setCurrentIndex(1);
1710 ui->SessionView->selectionModel()->clear();
1711 for (int irow = m_SessionModel->rowCount() - 1; irow >= 0; --irow)
1712 {
1713 QModelIndex mSortIndex = m_SessionSortModel->index(irow, 0);
1714 QModelIndex mIndex = m_SessionSortModel->mapToSource(mSortIndex);
1715 int idxrow = mIndex.row();
1716 if (m_SessionModel->item(idxrow, 0)->text() == getObjectName(o))
1717 ui->SessionView->selectRow(idxrow);
1719 }
1720}
1721
1723{
1724 ui->ImagePreview->setPixmap(m_NoImagePixmap);
1725 ui->ImagePreview->update();
1726}
1727
1729{
1730 QString finalObjectName;
1731 if (o->name() == "star")
1732 {
1733 const StarObject *s = dynamic_cast<const StarObject *>(o);
1734
1735 // JM: Enable HD Index stars to be added to the observing list.
1736 if (s != nullptr && s->getHDIndex() != 0)
1737 finalObjectName = QString("HD %1").arg(QString::number(s->getHDIndex()));
1738 }
1739 else
1740 finalObjectName = translated ? o->translatedName() : o->name();
1741
1742 return finalObjectName;
1743}
1744
1746{
1747 // FIXME: Update upon gaining visibility, do not update when not visible
1748 KStarsDateTime now = KStarsDateTime::currentDateTimeUtc();
1749 // qCDebug(KSTARS) << "Updating altitudes in observation planner @ JD - J2000 = " << double( now.djd() - J2000 );
1750 for (int irow = m_WishListModel->rowCount() - 1; irow >= 0; --irow)
1751 {
1752 QModelIndex idx = m_WishListSortModel->mapToSource(m_WishListSortModel->index(irow, 0));
1753 SkyObject *o = static_cast<SkyObject *>(idx.data(Qt::UserRole + 1).value<void *>());
1754 Q_ASSERT(o);
1755 SkyPoint p = o->recomputeHorizontalCoords(now, geo);
1756 idx =
1757 m_WishListSortModel->mapToSource(m_WishListSortModel->index(irow, m_WishListSortModel->columnCount() - 1));
1758 QStandardItem *replacement = m_altCostHelper(p);
1759 m_WishListModel->setData(idx, replacement->data(Qt::DisplayRole), Qt::DisplayRole);
1760 m_WishListModel->setData(idx, replacement->data(Qt::UserRole), Qt::UserRole);
1761 delete replacement;
1762 }
1763 emit m_WishListModel->dataChanged(
1764 m_WishListModel->index(0, m_WishListModel->columnCount() - 1),
1765 m_WishListModel->index(m_WishListModel->rowCount() - 1, m_WishListModel->columnCount() - 1));
1766}
1767
1768QSharedPointer<SkyObject> ObservingList::findObject(const SkyObject *o, bool session)
1769{
1770 const QList<QSharedPointer<SkyObject>> &list = (session ? sessionList() : obsList());
1771 const QString &target = getObjectName(o);
1772 foreach (QSharedPointer<SkyObject> obj, list)
1773 {
1774 if (getObjectName(obj.data()) == target)
1775 return obj;
1776 }
1777 return QSharedPointer<SkyObject>(); // null pointer
1778}
the Altitude vs.
Definition altvstime.h:41
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:232
SkyMapComposite * skyComposite()
Definition kstarsdata.h:168
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
static KStarsDateTime currentDateTimeUtc()
static KStarsDateTime currentDateTime()
void setTime(const QTime &t)
Assign the Time according to a QTime object.
This is the main window for KStars.
Definition kstars.h:89
static KStars * Instance()
Definition kstars.h:121
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.
void setClickedPoint(const SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
Definition skymap.cpp:1008
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:1173
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:149
virtual QString name(void) const
Definition skyobject.h:146
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
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
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
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 Mon Nov 18 2024 12:16:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.