File indexing completed on 2024-04-21 14:45:57

0001 /*
0002     SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 
0008 #include "opships.h"
0009 
0010 #include "kstars.h"
0011 #include "hipsmanager.h"
0012 #include "Options.h"
0013 #include "skymap.h"
0014 #include "auxiliary/ksnotification.h"
0015 #include "auxiliary/filedownloader.h"
0016 #include "auxiliary/kspaths.h"
0017 
0018 #include <KConfigDialog>
0019 
0020 #include <QCheckBox>
0021 #include <QComboBox>
0022 #include <QFileDialog>
0023 #include <QPushButton>
0024 #include <QStringList>
0025 
0026 // Qt version calming
0027 #include <qtkeepemptyparts.h>
0028 
0029 static const QStringList hipsKeys = { "ID", "obs_title", "obs_description", "hips_order", "hips_frame", "hips_tile_width", "hips_tile_format", "hips_service_url", "moc_sky_fraction"};
0030 
0031 OpsHIPSDisplay::OpsHIPSDisplay() : QFrame(KStars::Instance())
0032 {
0033     setupUi(this);
0034 }
0035 
0036 OpsHIPSCache::OpsHIPSCache() : QFrame(KStars::Instance())
0037 {
0038     setupUi(this);
0039 
0040     connect(selectDirectoryB, &QPushButton::clicked, this, [this]()
0041     {
0042         QString dir = QFileDialog::getExistingDirectory(this, i18nc("@title:window", "HiPS Offline Storage"),
0043                       kcfg_HIPSOfflinePath->text());
0044 
0045         if (dir.isEmpty())
0046             return;
0047 
0048         kcfg_HIPSOfflinePath->setText(dir);
0049 
0050         QDir hipsDirectory(dir);
0051         auto orders = hipsDirectory.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
0052         HIPSManager::Instance()->setOfflineLevels(orders);
0053         HIPSManager::Instance()->setCurrentSource("DSS Colored");
0054     });
0055 }
0056 
0057 OpsHIPS::OpsHIPS() : QFrame(KStars::Instance())
0058 {
0059     setupUi(this);
0060 
0061     //Get a pointer to the KConfigDialog
0062     m_ConfigDialog = KConfigDialog::exists("hipssettings");
0063 
0064     QString path = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(
0065                        QLatin1String("hips_previews/"));
0066     QDir dir;
0067     dir.mkpath(path);
0068 
0069     connect(refreshSourceB, SIGNAL(clicked()), this, SLOT(slotRefresh()));
0070 
0071     connect(sourcesList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(slotItemUpdated(QListWidgetItem*)));
0072     connect(sourcesList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotItemClicked(QListWidgetItem*)));
0073 
0074     if (sourcesList->count() == 0)
0075         slotRefresh();
0076 }
0077 
0078 void OpsHIPS::slotRefresh()
0079 {
0080     downloadJob = new FileDownloader();
0081 
0082     downloadJob->setProgressDialogEnabled(true, i18n("HiPS Update"), i18n("Downloading HiPS sources..."));
0083 
0084     QObject::connect(downloadJob, SIGNAL(downloaded()), this, SLOT(downloadReady()));
0085     QObject::connect(downloadJob, SIGNAL(error(QString)), this, SLOT(downloadError(QString)));
0086 
0087     downloadJob->get(
0088         QUrl("http://alasky.unistra.fr/MocServer/query?hips_service_url=*&dataproduct_type=!catalog&dataproduct_type=!cube&&moc_sky_fraction=1&get=record"));
0089 }
0090 
0091 void OpsHIPS::downloadReady()
0092 {
0093     sources.clear();
0094 
0095     QTextStream stream(downloadJob->downloadedData());
0096 
0097     QStringList hipsTitles;
0098 
0099     QMap<QString, QString> oneSource;
0100     while (stream.atEnd() == false)
0101     {
0102         QString line = stream.readLine();
0103         if (line.isEmpty())
0104         {
0105             sources.append(oneSource);
0106             oneSource.clear();
0107             continue;
0108         }
0109 
0110         QStringList keyvalue = line.split('=', Qt::KeepEmptyParts);
0111         QString key   = keyvalue[0].simplified();
0112         if (hipsKeys.contains(key) == false)
0113             continue;
0114         QString value = keyvalue[1].simplified();
0115         oneSource[key] = value;
0116         if (key == "obs_title")
0117             hipsTitles << value;
0118     }
0119 
0120     // Get existing database sources
0121     QList<QMap<QString, QString>> dbSources;
0122     KStarsData::Instance()->userdb()->GetAllHIPSSources(dbSources);
0123 
0124     // Get existing database titles
0125     QStringList dbTitles;
0126     for (QMap<QString, QString> oneSource : dbSources)
0127         dbTitles << oneSource["obs_title"];
0128 
0129     // Add all titles to list widget
0130     sourcesList->addItems(hipsTitles);
0131     QListWidgetItem* item = nullptr;
0132 
0133     // Make sources checkable and check sources that already exist in the database
0134     sourcesList->blockSignals(true);
0135     for(int i = 0; i < sourcesList->count(); ++i)
0136     {
0137         item = sourcesList->item(i);
0138         item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
0139         item->setCheckState(dbTitles.contains(item->text()) ? Qt::Checked : Qt::Unchecked);
0140 
0141         if (item->text() == Options::hIPSSource())
0142         {
0143             item->setSelected(true);
0144             sourcesList->scrollToItem(item);
0145             slotItemClicked(item);
0146         }
0147     }
0148     sourcesList->blockSignals(false);
0149 
0150     // Delete job later
0151     downloadJob->deleteLater();
0152 }
0153 
0154 void OpsHIPS::downloadError(const QString &errorString)
0155 {
0156     KSNotification::error(i18n("Error downloading HiPS sources: %1", errorString));
0157     downloadJob->deleteLater();
0158 }
0159 
0160 void OpsHIPS::slotItemUpdated(QListWidgetItem *item)
0161 {
0162     for(QMap<QString, QString> &oneSource : sources)
0163     {
0164         if (oneSource.value("obs_title") == item->text())
0165         {
0166             if (item->checkState() == Qt::Checked)
0167                 KStarsData::Instance()->userdb()->AddHIPSSource(oneSource);
0168             else
0169                 KStarsData::Instance()->userdb()->DeleteHIPSSource(oneSource.value("ID"));
0170             break;
0171         }
0172     }
0173 }
0174 
0175 void OpsHIPS::slotItemClicked(QListWidgetItem *item)
0176 {
0177     for(QMap<QString, QString> &oneSource : sources)
0178     {
0179         if (oneSource.value("obs_title") == item->text())
0180         {
0181             sourceDescription->setText(oneSource.value("obs_description"));
0182             // Get stored preview, if not found, it will be downloaded.
0183             setPreview(oneSource.value("ID"), oneSource.value("hips_service_url"));
0184             break;
0185         }
0186     }
0187 }
0188 
0189 void OpsHIPS::setPreview(const QString &id, const QString &url)
0190 {
0191     uint hash = qHash(id);
0192     QString previewName = QString("%1.jpg").arg(hash);
0193 
0194     QString currentPreviewPath = QDir(KSPaths::locate(QStandardPaths::AppLocalDataLocation,
0195                                       QLatin1String("hips_previews"))).filePath(previewName);
0196     if (currentPreviewPath.isEmpty() == false)
0197     {
0198         sourceImage->setPixmap(QPixmap(currentPreviewPath));
0199     }
0200     else
0201     {
0202         currentPreviewPath = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(
0203                                  QLatin1String("hips_previews/") + previewName);
0204 
0205         previewJob = new FileDownloader();
0206         connect(previewJob, SIGNAL(downloaded()), this, SLOT(previewReady()));
0207 
0208         previewJob->setDownloadedFileURL(QUrl::fromLocalFile(currentPreviewPath));
0209 
0210         previewJob->get(QUrl(url + QLatin1String("/preview.jpg")));
0211     }
0212 }
0213 
0214 void OpsHIPS::previewReady()
0215 {
0216     QString previewFile = previewJob->getDownloadedFileURL().toLocalFile();
0217     QFileInfo previewInfo(previewFile);
0218     // If less than 1kb then it's junk
0219     if (previewInfo.size() < 1024)
0220     {
0221         sourceImage->setPixmap(QPixmap(":/images/noimage.png"));
0222         QFile::remove(previewFile);
0223     }
0224     else
0225         sourceImage->setPixmap(QPixmap(previewFile));
0226 }
0227