Kstars

opsastrometryindexfiles.cpp
1
2#include "opsastrometryindexfiles.h"
3
4#include "align.h"
5#include "kstars.h"
6#include "ksutils.h"
7#include "Options.h"
8#include "ksnotification.h"
9
10#include <KConfigDialog>
11#include <KMessageBox>
12
13namespace Ekos
14{
15OpsAstrometryIndexFiles::OpsAstrometryIndexFiles(Align *parent) : QDialog(KStars::Instance())
16{
17 setupUi(this);
18
19 downloadSpeed = 100;
20 actualdownloadSpeed = downloadSpeed;
21 alignModule = parent;
22 manager = new QNetworkAccessManager();
23
24 indexURL->setText("http://broiler.astrometry.net/~dstn/");
25
26 //Get a pointer to the KConfigDialog
27 // m_ConfigDialog = KConfigDialog::exists( "alignsettings" );
28 connect(openIndexFileDirectory, SIGNAL(clicked()), this, SLOT(slotOpenIndexFileDirectory()));
30 {
31 indexURL->text();
32 });
33
34
35 astrometryIndex[2.8] = "00";
36 astrometryIndex[4.0] = "01";
37 astrometryIndex[5.6] = "02";
38 astrometryIndex[8] = "03";
39 astrometryIndex[11] = "04";
40 astrometryIndex[16] = "05";
41 astrometryIndex[22] = "06";
42 astrometryIndex[30] = "07";
43 astrometryIndex[42] = "08";
44 astrometryIndex[60] = "09";
45 astrometryIndex[85] = "10";
46 astrometryIndex[120] = "11";
47 astrometryIndex[170] = "12";
48 astrometryIndex[240] = "13";
49 astrometryIndex[340] = "14";
50 astrometryIndex[480] = "15";
51 astrometryIndex[680] = "16";
52 astrometryIndex[1000] = "17";
53 astrometryIndex[1400] = "18";
54 astrometryIndex[2000] = "19";
55
57
58 connect(indexLocations, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
59 &OpsAstrometryIndexFiles::slotUpdate);
60
61 for (auto &checkBox : checkboxes)
62 {
63 connect(checkBox, &QCheckBox::clicked, this, &OpsAstrometryIndexFiles::downloadOrDeleteIndexFiles);
64 }
65
69
70 for (auto &bar : progressBars)
71 {
72 if(bar->objectName().contains("progress"))
73 {
74 bar->setVisible(false);
75 bar->setTextVisible(false);
76 }
77 }
78
79 for (auto &button : qButtons)
80 {
81 if(button->objectName().contains("cancel"))
82 {
83 button->setVisible(false);
84 }
85 }
86
87 for (QLabel * label : qLabels)
88 {
89 if(label->text().contains("info") || label->text().contains("perc"))
90 {
91 label->setVisible(false);
92 }
93 }
94
96 {
97 QString dir = QFileDialog::getExistingDirectory(this, "Load Index File Directory",
101 if (dir.isEmpty())
102 return;
103 addDirectoryToList(dir);
104 });
106 {
107 if(indexLocations->currentIndex() != 0)
108 removeDirectoryFromList(indexLocations->currentText());
109 });
110
111
112}
113
114void OpsAstrometryIndexFiles::showEvent(QShowEvent *)
115{
116 updateIndexDirectoryList();
117
118}
119
120void OpsAstrometryIndexFiles::updateIndexDirectoryList()
121{
122 // This is needed because they might have directories stored in the config file.
123 // So we can't just use the options folder list.
124 QStringList astrometryDataDirs = KSUtils::getAstrometryDataDirs();
125
126 indexLocations->clear();
127 if(astrometryDataDirs.count() > 1)
128 indexLocations->addItem("All Sources");
130 slotUpdate();
131}
132
133void OpsAstrometryIndexFiles::addDirectoryToList(QString directory)
134{
135 QDir dir(directory);
136 if(!dir.exists())
137 return;
138 QString directoryPath = dir.absolutePath();
139
140 QStringList indexFileDirs = Options::astrometryIndexFolderList();
141 if(indexFileDirs.contains(directoryPath))
142 return;
144 Options::setAstrometryIndexFolderList(indexFileDirs);
145 updateIndexDirectoryList();
146}
147
148void OpsAstrometryIndexFiles::removeDirectoryFromList(QString directory)
149{
150 QStringList indexFileDirs = Options::astrometryIndexFolderList();
151 if(indexFileDirs.contains(directory))
152 {
153 indexFileDirs.removeOne(directory);
154 Options::setAstrometryIndexFolderList(indexFileDirs);
155 updateIndexDirectoryList();
156 }
157}
158
159void OpsAstrometryIndexFiles::slotUpdate()
160{
162
163 for (auto &checkBox : checkboxes)
164 {
165 checkBox->setChecked(false);
166 }
167
168 if(indexLocations->count() == 0)
169 return;
170
171 double fov_w, fov_h, fov_pixscale;
172
173 // Values in arcmins. Scale in arcsec per pixel
174 alignModule->getFOVScale(fov_w, fov_h, fov_pixscale);
175
176 double fov_check = qMax(fov_w, fov_h);
177
178 FOVOut->setText(QString("%1' x %2'").arg(QString::number(fov_w, 'f', 2), QString::number(fov_h, 'f', 2)));
179
180 QStringList nameFilter("*.fits");
181
182 QStringList astrometryDataDirs = Options::astrometryIndexFolderList();
183
184 bool allDirsSelected = (indexLocations->currentIndex() == 0 && astrometryDataDirs.count() > 1);
186
188
190 {
191 folderDetails->setText(i18n("Downloads Disabled, this is not a directory, it is a list of all index files."));
192 folderIsWriteable = false;
194 openIndexFileDirectory->setEnabled(false);
195 }
196 else
197 {
198 QString folderPath = indexLocations->currentText();
201 folderDetails->setText(i18n("Downloads Enabled, the directory exists and is writeable."));
202 else
203 folderDetails->setText(i18n("Downloads Disabled, directory permissions issue."));
205 folderDetails->setText(i18n("Downloads Disabled, directory does not exist."));
207 openIndexFileDirectory->setEnabled(true);
208 }
209 folderDetails->setCursorPosition(0);
210
211 //This loop checks all the folders that are supposed to be checked for the files
212 //It checks the box if it finds them
214 {
215 QDir directory(astrometryDataDir);
216 QStringList indexList = directory.entryList(nameFilter);
217
218 for (auto &indexName : indexList)
219 {
220 if (fileCountMatches(directory, indexName))
221 {
222 indexName = indexName.replace('-', '_').left(10);
224 if (indexCheckBox)
225 indexCheckBox->setChecked(true);
226 }
227 }
228 }
229
230 for (auto &checkBox : checkboxes)
231 {
232 checkBox->setEnabled(folderIsWriteable);
233 checkBox->setIcon(QIcon(":/icons/astrometry-optional.svg"));
234 checkBox->setToolTip(i18n("Optional"));
235 checkBox->setStyleSheet("");
236 }
237
238 float last_skymarksize = 2;
239
240 for (auto &skymarksize : astrometryIndex.keys())
241 {
242 QString indexName1 = "index_41" + astrometryIndex.value(skymarksize);
243 QString indexName2 = "index_42" + astrometryIndex.value(skymarksize);
244 QString indexName3 = "index_52" + astrometryIndex.value(skymarksize);
248 if ((skymarksize >= 0.40 * fov_check && skymarksize <= 0.9 * fov_check) ||
250 {
251 if (indexCheckBox1)
252 {
253 indexCheckBox1->setIcon(QIcon(":/icons/astrometry-required.svg"));
254 indexCheckBox1->setToolTip(i18n("Required"));
255 }
256 if (indexCheckBox2)
257 {
258 indexCheckBox2->setIcon(QIcon(":/icons/astrometry-required.svg"));
259 indexCheckBox2->setToolTip(i18n("Required"));
260 }
261 if (indexCheckBox3)
262 {
263 indexCheckBox3->setIcon(QIcon(":/icons/astrometry-required.svg"));
264 indexCheckBox3->setToolTip(i18n("Required"));
265 }
266 }
267 else if (skymarksize >= 0.10 * fov_check && skymarksize <= fov_check)
268 {
269 if (indexCheckBox1)
270 {
271 indexCheckBox1->setIcon(QIcon(":/icons/astrometry-recommended.svg"));
272 indexCheckBox1->setToolTip(i18n("Recommended"));
273 }
274 if (indexCheckBox2)
275 {
276 indexCheckBox2->setIcon(QIcon(":/icons/astrometry-recommended.svg"));
277 indexCheckBox2->setToolTip(i18n("Recommended"));
278 }
279 if (indexCheckBox3)
280 {
281 indexCheckBox3->setIcon(QIcon(":/icons/astrometry-recommended.svg"));
282 indexCheckBox3->setToolTip(i18n("Recommended"));
283 }
284 }
285
287 }
288
289 //This loop goes over all the directories and adds a stylesheet to change the look of the checkbox text
290 //if the File is installed in any directory. Note that this indicator is then used below in the
291 //Index File download function to check if they really want to do install a file that is installed.
293 {
294 QDir directory(astrometryDataDir);
295 QStringList indexList = directory.entryList(nameFilter);
296
297 for (auto &indexName : indexList)
298 {
299 if (fileCountMatches(directory, indexName))
300 {
301 indexName = indexName.replace('-', '_').left(10);
303 if (indexCheckBox)
304 indexCheckBox->setStyleSheet("QCheckBox{font-weight: bold; color:green}");
305 }
306 }
307 }
308}
309
310int OpsAstrometryIndexFiles::indexFileCount(QString indexName)
311{
312 int count = 0;
313 if(indexName.contains("4207") || indexName.contains("4206") || indexName.contains("4205"))
314 count = 12;
315 else if(indexName.contains("4204") || indexName.contains("4203") || indexName.contains("4202")
316 || indexName.contains("4201") || indexName.contains("4200") || indexName.contains("5206")
317 || indexName.contains("5205") || indexName.contains("5204") || indexName.contains("5203")
318 || indexName.contains("5202") || indexName.contains("5201") || indexName.contains("5200"))
319 count = 48;
320 else
321 count = 1;
322 return count;
323}
324
325bool OpsAstrometryIndexFiles::fileCountMatches(QDir directory, QString indexName)
326{
327 QString indexNameMatch = indexName.left(10) + "*.fits";
329 return list.count() == indexFileCount(indexName);
330}
331
332void OpsAstrometryIndexFiles::slotOpenIndexFileDirectory()
333{
334 if(indexLocations->count() == 0)
335 return;
338}
339
340bool OpsAstrometryIndexFiles::astrometryIndicesAreAvailable()
341{
342 QUrl indexUrl = QUrl(this->indexURL->text());
344 QTimer timeout(this);
345 timeout.setInterval(5000);
346 timeout.setSingleShot(true);
347 timeout.start();
348 while (!response->isFinished())
349 {
350 if (!timeout.isActive())
351 {
352 response->deleteLater();
353 return false;
354 }
355 qApp->processEvents();
356 }
357
358 timeout.stop();
359 bool wasSuccessful = (response->error() == QNetworkReply::NoError);
360 response->deleteLater();
361
362 return wasSuccessful;
363}
364
365void OpsAstrometryIndexFiles::downloadIndexFile(const QString &URL, const QString &fileN, QCheckBox *checkBox,
366 int currentIndex, int maxIndex, double fileSize)
367{
369 downloadTime.start();
370
371 QString indexString = QString::number(currentIndex);
372 if (currentIndex < 10)
373 indexString = '0' + indexString;
374
375 QString indexSeriesName = checkBox->text().remove('&');
376 QProgressBar *indexDownloadProgress = findChild<QProgressBar *>(indexSeriesName.replace('-', '_').left(10) + "_progress");
377 QLabel *indexDownloadInfo = findChild<QLabel *>(indexSeriesName.replace('-', '_').left(10) + "_info");
378 QPushButton *indexDownloadCancel = findChild<QPushButton *>(indexSeriesName.replace('-', '_').left(10) + "_cancel");
379 QLabel *indexDownloadPerc = findChild<QLabel *>(indexSeriesName.replace('-', '_').left(10) + "_perc");
380
381 setDownloadInfoVisible(indexSeriesName, checkBox, true);
382
384 {
386 indexDownloadProgress->setValue(currentIndex * 100 / maxIndex);
387 indexDownloadInfo->setText("(" + QString::number(currentIndex) + '/' + QString::number(maxIndex + 1) + ") ");
388 }
389
391
392 indexURL.replace('*', indexString);
393
395
396 //Shut it down after too much time elapses.
397 //If the filesize is less than 4 MB, it sets the timeout for 1 minute or 60000 ms.
398 //If it's larger, it assumes a bad download rate of 1 Mbps (100 bytes/ms)
399 //and the calculation estimates the time in milliseconds it would take to download.
400 int timeout = 60000;
401 if(fileSize > 4000000)
402 timeout = fileSize / downloadSpeed;
403 //qDebug()<<"Filesize: "<< fileSize << ", timeout: " << timeout;
404
408
410 {
412 [ = ](qint64 bytesReceived, qint64 bytesTotal)
413 {
415 {
417 indexDownloadProgress->setMaximum(bytesTotal);
418 }
419 indexDownloadPerc->setText(QString::number(bytesReceived * 100 / bytesTotal) + '%');
420 });
421
422 }
423
424 timeoutTimer.disconnect();
425 connect(&timeoutTimer, &QTimer::timeout, this, [&]()
426 {
427 KSNotification::error(
428 i18n("Download Timed out. Either the network is not fast enough, the file is not accessible, or you are not connected."));
430 if(response)
431 {
432 response->abort();
433 response->deleteLater();
434 }
435 setDownloadInfoVisible(indexSeriesName, checkBox, false);
436 });
437 timeoutTimer.start(timeout);
438
440 [ = ]()
441 {
442 qDebug() << Q_FUNC_INFO << "Download Cancelled.";
443 timeoutTimer.stop();
445 if(response)
446 {
447 response->abort();
448 response->deleteLater();
449 }
450 setDownloadInfoVisible(indexSeriesName, checkBox, false);
451 });
452
454 [ = ]()
455 {
456 timeoutTimer.stop();
457 if(response)
458 {
460 setDownloadInfoVisible(indexSeriesName, checkBox, false);
461 response->deleteLater();
462 if (response->error() != QNetworkReply::NoError)
463 return;
464
465 QByteArray responseData = response->readAll();
467
468 indexFileN.replace('*', indexString);
469
470 QFile file(indexFileN);
471 if (QFileInfo(QFileInfo(file).path()).isWritable())
472 {
473 if (!file.open(QIODevice::WriteOnly))
474 {
475 KSNotification::error(i18n("File Write Error"));
476 slotUpdate();
477 return;
478 }
479 else
480 {
481 file.write(responseData.data(), responseData.size());
482 file.close();
483 int downloadedFileSize = QFileInfo(file).size();
484 int dtime = downloadTime.elapsed();
485 actualdownloadSpeed = (actualdownloadSpeed + (downloadedFileSize / dtime)) / 2;
486 qDebug() << Q_FUNC_INFO << "Filesize: " << downloadedFileSize << ", time: " << dtime << ", inst speed: " <<
488 ", averaged speed: " << actualdownloadSpeed;
489
490 }
491 }
492 else
493 {
494 KSNotification::error(i18n("Astrometry Folder Permissions Error"));
495 }
496
497 if (currentIndex == maxIndex)
498 {
499 slotUpdate();
500 }
501 else
502 downloadIndexFile(URL, fileN, checkBox, currentIndex + 1, maxIndex, fileSize);
503 }
504 });
505}
506
507void OpsAstrometryIndexFiles::setDownloadInfoVisible(QString indexSeriesName, QCheckBox *checkBox, bool set)
508{
509 Q_UNUSED(checkBox);
510
511 QProgressBar *indexDownloadProgress = findChild<QProgressBar *>(indexSeriesName.replace('-', '_').left(10) + "_progress");
512 QLabel *indexDownloadInfo = findChild<QLabel *>(indexSeriesName.replace('-', '_').left(10) + "_info");
513 QPushButton *indexDownloadCancel = findChild<QPushButton *>(indexSeriesName.replace('-', '_').left(10) + "_cancel");
514 QLabel *indexDownloadPerc = findChild<QLabel *>(indexSeriesName.replace('-', '_').left(10) + "_perc");
516 indexDownloadProgress->setVisible(set);
518 indexDownloadInfo->setVisible(set);
520 indexDownloadCancel->setVisible(set);
522 indexDownloadPerc->setVisible(set);
523}
524void OpsAstrometryIndexFiles::disconnectDownload(QMetaObject::Connection *cancelConnection,
526{
528 disconnect(*cancelConnection);
530 disconnect(*replyConnection);
532 disconnect(*percentConnection);
533}
534
535void OpsAstrometryIndexFiles::downloadOrDeleteIndexFiles(bool checked)
536{
538
539 if (indexLocations->count() == 0)
540 return;
541
544 {
545 KSNotification::sorry(
546 i18n("The selected Index File directory does not exist. Please either create it or choose another."));
547 return;
548 }
549
550 if (checkBox)
551 {
552 QString indexSeriesName = checkBox->text().remove('&');
553 QString filePath = astrometryDataDir + '/' + indexSeriesName;
555
556 if (checked)
557 {
558 if(!checkBox->styleSheet().isEmpty()) //This means that the checkbox has a stylesheet so the index file was installed someplace.
559 {
561 nullptr, i18n("The file %1 already exists in another directory. Are you sure you want to download it to this directory as well?",
563 i18n("Install File(s)"), KStandardGuiItem::cont(),
564 KStandardGuiItem::cancel(), "install_index_files_warning"))
565 {
566 slotUpdate();
567 return;
568 }
569 }
570 checkBox->setChecked(!checked);
571 if (astrometryIndicesAreAvailable())
572 {
574 QString URL;
575
576 if (this->indexURL->text().endsWith("/"))
577 {
578 BASE_URL = this->indexURL->text();
579 }
580 else
581 {
582 BASE_URL = this->indexURL->text() + "/";
583 }
584
585 if (indexSeriesName.startsWith(QLatin1String("index-41")))
586 URL = BASE_URL + "4100/" + indexSeriesName;
587 else if (indexSeriesName.startsWith(QLatin1String("index-42")))
588 URL = BASE_URL + "4200/" + indexSeriesName;
589 else if (indexSeriesName.startsWith(QLatin1String("index-52")))
590 URL = "https://portal.nersc.gov/project/cosmo/temp/dstn/index-5200/LITE/" + indexSeriesName;
591
592 int maxIndex = indexFileCount(indexSeriesName) - 1;
593
594 double fileSize = 1E11 * qPow(astrometryIndex.key(fileNumString),
595 -1.909); //This estimates the file size based on skymark size obtained from the index number.
596 if(maxIndex != 0)
597 fileSize /= maxIndex; //FileSize is divided between multiple files for some index series.
598 downloadIndexFile(URL, filePath, checkBox, 0, maxIndex, fileSize);
599 }
600 else
601 {
602 KSNotification::sorry(i18n("Could not contact Astrometry Index Server."));
603 }
604 }
605 else
606 {
608 nullptr, i18n("Are you sure you want to delete these index files? %1", indexSeriesName),
609 i18n("Delete File(s)"), KStandardGuiItem::cont(),
610 KStandardGuiItem::cancel(), "delete_index_files_warning"))
611 {
612 if (QFileInfo(astrometryDataDir).isWritable())
613 {
614 QStringList nameFilter("*.fits");
615 QDir directory(astrometryDataDir);
616 QStringList indexList = directory.entryList(nameFilter);
617 for (auto &fileName : indexList)
618 {
619 if (fileName.contains(indexSeriesName.left(10)))
620 {
621 if (!directory.remove(fileName))
622 {
623 KSNotification::error(i18n("File Delete Error"));
624 slotUpdate();
625 return;
626 }
627 slotUpdate();
628 }
629 }
630 }
631 else
632 {
633 KSNotification::error(i18n("Astrometry Folder Permissions Error"));
634 slotUpdate();
635 }
636 }
637 }
638 }
639}
640}
This is the main window for KStars.
Definition kstars.h:91
QString i18n(const char *text, const TYPE &arg...)
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
QString path(const QString &relativePath)
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)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KGuiItem cont()
KGuiItem cancel()
QString label(StandardShortcut id)
void setChecked(bool)
void clicked(bool checked)
char * data()
qsizetype size() const const
void currentIndexChanged(int index)
bool openUrl(const QUrl &url)
QStringList entryList(Filters filters, SortFlags sort) const const
QString homePath()
bool remove(const QString &fileName)
QString getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, Options options)
bool exists() const const
bool isWritable() const const
qint64 size() const const
void textChanged(const QString &text)
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
QObject * sender() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString number(double n, char format, int precision)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
QUrl fromLocalFile(const QString &localFile)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.