File indexing completed on 2024-04-14 14:08:59
0001 /* 0002 SPDX-FileCopyrightText: 2004 Jason Harris <kstars@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kswizard.h" 0008 0009 #include "geolocation.h" 0010 #include "kspaths.h" 0011 #include "kstars.h" 0012 #include "kstarsdata.h" 0013 #include "ksnotification.h" 0014 #include "ksutils.h" 0015 #include "Options.h" 0016 #include "widgets/dmsbox.h" 0017 0018 #include <kns3/downloaddialog.h> 0019 0020 #include <QDesktopServices> 0021 #include <QFile> 0022 #include <QLineEdit> 0023 #include <QPixmap> 0024 #include <QPushButton> 0025 #include <QStackedWidget> 0026 #include <QStandardPaths> 0027 0028 namespace 0029 { 0030 bool hasPrefix(QString str, QString prefix) 0031 { 0032 if (prefix.isEmpty()) 0033 return true; 0034 return str.startsWith(prefix, Qt::CaseInsensitive); 0035 } 0036 } 0037 0038 WizWelcomeUI::WizWelcomeUI(QWidget *parent) : QFrame(parent) 0039 { 0040 setupUi(this); 0041 } 0042 0043 WizLocationUI::WizLocationUI(QWidget *parent) : QFrame(parent) 0044 { 0045 setupUi(this); 0046 } 0047 0048 WizDownloadUI::WizDownloadUI(QWidget *parent) : QFrame(parent) 0049 { 0050 setupUi(this); 0051 } 0052 0053 #ifdef Q_OS_OSX 0054 WizDataUI::WizDataUI(QWidget *parent) : QFrame(parent) 0055 { 0056 setupUi(this); 0057 } 0058 #endif 0059 0060 KSWizard::KSWizard(QWidget *parent) : QDialog(parent) 0061 { 0062 wizardStack = new QStackedWidget(this); 0063 adjustSize(); 0064 0065 setWindowTitle(i18nc("@title:window", "Startup Wizard")); 0066 0067 QVBoxLayout *mainLayout = new QVBoxLayout; 0068 mainLayout->addWidget(wizardStack); 0069 setLayout(mainLayout); 0070 0071 buttonBox = new QDialogButtonBox(Qt::Horizontal); 0072 nextB = new QPushButton(i18n("&Next >")); 0073 nextB->setDefault(true); 0074 backB = new QPushButton(i18n("< &Back")); 0075 backB->setEnabled(false); 0076 completeB = new QPushButton(i18n("Done")); 0077 0078 buttonBox->addButton(backB, QDialogButtonBox::ActionRole); 0079 buttonBox->addButton(nextB, QDialogButtonBox::ActionRole); 0080 buttonBox->addButton(completeB, QDialogButtonBox::AcceptRole); 0081 completeB->setVisible(false); 0082 0083 mainLayout->addWidget(buttonBox); 0084 0085 welcome = new WizWelcomeUI(wizardStack); 0086 #ifdef Q_OS_OSX 0087 data = new WizDataUI(wizardStack); 0088 #endif 0089 location = new WizLocationUI(wizardStack); 0090 WizDownloadUI *download = new WizDownloadUI(wizardStack); 0091 0092 wizardStack->addWidget(welcome); 0093 #ifdef Q_OS_OSX 0094 wizardStack->addWidget(data); 0095 #endif 0096 wizardStack->addWidget(location); 0097 wizardStack->addWidget(download); 0098 wizardStack->setCurrentWidget(welcome); 0099 0100 //Load images into banner frames. 0101 QPixmap im; 0102 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzstars.png"))) 0103 welcome->Banner->setPixmap(im); 0104 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() + 0105 "/wzstars.png")) 0106 welcome->Banner->setPixmap(im); 0107 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzgeo.png"))) 0108 location->Banner->setPixmap(im); 0109 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() + "/wzgeo.png")) 0110 location->Banner->setPixmap(im); 0111 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzdownload.png"))) 0112 download->Banner->setPixmap(im); 0113 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() + 0114 "/wzdownload.png")) 0115 download->Banner->setPixmap(im); 0116 0117 #ifdef Q_OS_OSX 0118 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzdownload.png"))) 0119 data->Banner->setPixmap(im); 0120 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() + 0121 "/wzdownload.png")) 0122 data->Banner->setPixmap(im); 0123 0124 data->dataPath->setText( 0125 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(), QStandardPaths::LocateDirectory) + 0126 "kstars"); 0127 slotUpdateDataButtons(); 0128 0129 connect(data->copyKStarsData, SIGNAL(clicked()), this, SLOT(slotOpenOrCopyKStarsDataDirectory())); 0130 connect(data->installGSC, SIGNAL(clicked()), this, SLOT(slotInstallGSC())); 0131 0132 gscMonitor = new QProgressIndicator(data); 0133 data->GSCLayout->addWidget(gscMonitor); 0134 data->downloadProgress->setValue(0); 0135 0136 data->downloadProgress->setEnabled(false); 0137 data->downloadProgress->setVisible(false); 0138 0139 data->gscInstallCancel->setVisible(false); 0140 data->gscInstallCancel->setEnabled(false); 0141 0142 #endif 0143 0144 //connect signals/slots 0145 connect(nextB, SIGNAL(clicked()), this, SLOT(slotNextPage())); 0146 connect(backB, SIGNAL(clicked()), this, SLOT(slotPrevPage())); 0147 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); 0148 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); 0149 0150 connect(location->CityListBox, SIGNAL(itemSelectionChanged()), this, SLOT(slotChangeCity())); 0151 connect(location->CityFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities())); 0152 connect(location->ProvinceFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities())); 0153 connect(location->CountryFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities())); 0154 connect(download->DownloadButton, SIGNAL(clicked()), this, SLOT(slotDownload())); 0155 0156 //Initialize Geographic Location page 0157 if (KStars::Instance()) 0158 initGeoPage(); 0159 } 0160 0161 void KSWizard::setButtonsEnabled() 0162 { 0163 nextB->setEnabled(wizardStack->currentIndex() < wizardStack->count() - 1); 0164 backB->setEnabled(wizardStack->currentIndex() > 0); 0165 completeB->setVisible(wizardStack->currentIndex() == wizardStack->count() - 1); 0166 0167 #ifdef Q_OS_OSX 0168 if ((wizardStack->currentWidget() == data) && (!dataDirExists())) 0169 { 0170 nextB->setEnabled(false); 0171 } 0172 #endif 0173 } 0174 0175 void KSWizard::slotNextPage() 0176 { 0177 wizardStack->setCurrentIndex(wizardStack->currentIndex() + 1); 0178 setButtonsEnabled(); 0179 } 0180 0181 void KSWizard::slotPrevPage() 0182 { 0183 wizardStack->setCurrentIndex(wizardStack->currentIndex() - 1); 0184 setButtonsEnabled(); 0185 } 0186 0187 void KSWizard::initGeoPage() 0188 { 0189 KStarsData *data = KStarsData::Instance(); 0190 location->LongBox->setReadOnly(true); 0191 location->LatBox->setReadOnly(true); 0192 0193 //Populate the CityListBox 0194 //flag the ID of the current City 0195 foreach (GeoLocation *loc, data->getGeoList()) 0196 { 0197 location->CityListBox->addItem(loc->fullName()); 0198 filteredCityList.append(loc); 0199 if (loc->fullName() == data->geo()->fullName()) 0200 { 0201 Geo = loc; 0202 } 0203 } 0204 0205 //Sort alphabetically 0206 location->CityListBox->sortItems(); 0207 //preset to current city 0208 QList<QListWidgetItem*> locations = location->CityListBox->findItems(QString(data->geo()->fullName()), Qt::MatchExactly); 0209 if (locations.isEmpty() == false) 0210 location->CityListBox->setCurrentItem(locations[0]); 0211 } 0212 0213 void KSWizard::slotChangeCity() 0214 { 0215 if (location->CityListBox->currentItem()) 0216 { 0217 for (auto &city : filteredCityList) 0218 { 0219 if (city->fullName() == location->CityListBox->currentItem()->text()) 0220 { 0221 Geo = city; 0222 break; 0223 } 0224 } 0225 location->LongBox->show(Geo->lng()); 0226 location->LatBox->show(Geo->lat()); 0227 } 0228 } 0229 0230 void KSWizard::slotFilterCities() 0231 { 0232 location->CityListBox->clear(); 0233 //Do NOT delete members of filteredCityList! 0234 filteredCityList.clear(); 0235 0236 foreach (GeoLocation *loc, KStarsData::Instance()->getGeoList()) 0237 { 0238 if (hasPrefix(loc->translatedName(), location->CityFilter->text()) && 0239 hasPrefix(loc->translatedCountry(), location->CountryFilter->text()) && 0240 hasPrefix(loc->translatedProvince(), location->ProvinceFilter->text())) 0241 { 0242 location->CityListBox->addItem(loc->fullName()); 0243 filteredCityList.append(loc); 0244 } 0245 } 0246 location->CityListBox->sortItems(); 0247 0248 if (location->CityListBox->count() > 0) // set first item in list as selected 0249 location->CityListBox->setCurrentItem(location->CityListBox->item(0)); 0250 } 0251 0252 void KSWizard::slotDownload() 0253 { 0254 KNS3::DownloadDialog dlg; 0255 dlg.exec(); 0256 } 0257 0258 void KSWizard::slotOpenOrCopyKStarsDataDirectory() 0259 { 0260 #ifdef Q_OS_OSX 0261 QString dataLocation = 0262 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory); 0263 if (dataLocation.isEmpty()) 0264 { 0265 QDir dataSourceDir = QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath(); 0266 if (! dataSourceDir.exists()) //If there is no default data directory in the app bundle 0267 { 0268 KSNotification::sorry(i18n("There was no default data directory found in the app bundle.")); 0269 return; 0270 } 0271 QDir writableDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)); 0272 writableDir.mkpath("."); 0273 dataLocation = 0274 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory); 0275 if (dataLocation.isEmpty()) //If there *still* is not a kstars data directory 0276 { 0277 KSNotification::sorry(i18n("There was a problem creating the data directory ~/Library/Application Support/.")); 0278 return; 0279 } 0280 KSUtils::copyRecursively(dataSourceDir.absolutePath(), dataLocation); 0281 //This will update the next, ok, and copy kstars dir buttons. 0282 slotUpdateDataButtons(); 0283 } 0284 else 0285 { 0286 QUrl path = QUrl::fromLocalFile( 0287 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory)); 0288 QDesktopServices::openUrl(path); 0289 } 0290 0291 #endif 0292 } 0293 0294 void KSWizard::slotInstallGSC() 0295 { 0296 #ifdef Q_OS_OSX 0297 0298 QNetworkAccessManager *manager = new QNetworkAccessManager(); 0299 0300 QString location = 0301 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory); 0302 gscZipPath = location + "/gsc.zip"; 0303 0304 data->downloadProgress->setVisible(true); 0305 data->downloadProgress->setEnabled(true); 0306 0307 data->gscInstallCancel->setVisible(true); 0308 data->gscInstallCancel->setEnabled(true); 0309 0310 QString gscURL = "http://www.indilib.org/jdownloads/Mac/gsc.zip"; 0311 0312 QNetworkReply *response = manager->get(QNetworkRequest(QUrl(gscURL))); 0313 0314 QMetaObject::Connection *cancelConnection = new QMetaObject::Connection(); 0315 QMetaObject::Connection *replyConnection = new QMetaObject::Connection(); 0316 QMetaObject::Connection *percentConnection = new QMetaObject::Connection(); 0317 0318 *percentConnection = connect(response, &QNetworkReply::downloadProgress, 0319 [ = ](qint64 bytesReceived, qint64 bytesTotal) 0320 { 0321 data->downloadProgress->setValue(bytesReceived); 0322 data->downloadProgress->setMaximum(bytesTotal); 0323 }); 0324 0325 *cancelConnection = connect(data->gscInstallCancel, &QPushButton::clicked, 0326 [ = ]() 0327 { 0328 qDebug() << Q_FUNC_INFO << "Download Cancelled."; 0329 0330 if(cancelConnection) 0331 disconnect(*cancelConnection); 0332 if(replyConnection) 0333 disconnect(*replyConnection); 0334 0335 if(response) 0336 { 0337 response->abort(); 0338 response->deleteLater(); 0339 } 0340 0341 data->downloadProgress->setVisible(false); 0342 data->downloadProgress->setEnabled(false); 0343 0344 data->gscInstallCancel->setVisible(false); 0345 data->gscInstallCancel->setEnabled(false); 0346 0347 if(manager) 0348 manager->deleteLater(); 0349 0350 }); 0351 0352 *replyConnection = connect(response, &QNetworkReply::finished, this, 0353 [ = ]() 0354 { 0355 if(response) 0356 { 0357 0358 if(cancelConnection) 0359 disconnect(*cancelConnection); 0360 if(replyConnection) 0361 disconnect(*replyConnection); 0362 0363 data->downloadProgress->setVisible(false); 0364 data->downloadProgress->setEnabled(false); 0365 0366 data->gscInstallCancel->setVisible(false); 0367 data->gscInstallCancel->setEnabled(false); 0368 0369 0370 response->deleteLater(); 0371 if(manager) 0372 manager->deleteLater(); 0373 if (response->error() != QNetworkReply::NoError) 0374 return; 0375 0376 QByteArray responseData = response->readAll(); 0377 0378 QFile file(gscZipPath); 0379 if (QFileInfo(QFileInfo(file).path()).isWritable()) 0380 { 0381 if (!file.open(QIODevice::WriteOnly)) 0382 { 0383 KSNotification::error( i18n("File write error.")); 0384 return; 0385 } 0386 else 0387 { 0388 file.write(responseData.data(), responseData.size()); 0389 file.close(); 0390 slotExtractGSC(); 0391 } 0392 } 0393 else 0394 { 0395 KSNotification::error( i18n("Data folder permissions error.")); 0396 } 0397 } 0398 }); 0399 0400 #endif 0401 } 0402 0403 void KSWizard::slotExtractGSC() 0404 { 0405 #ifdef Q_OS_OSX 0406 QString location = 0407 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory); 0408 QProcess *gscExtractor = new QProcess(); 0409 connect(gscExtractor, SIGNAL(finished(int)), this, SLOT(slotGSCInstallerFinished())); 0410 connect(gscExtractor, SIGNAL(finished(int)), this, SLOT(gscExtractor.deleteLater())); 0411 gscExtractor->setWorkingDirectory(location); 0412 gscExtractor->start("unzip", QStringList() << "-ao" 0413 << "gsc.zip"); 0414 gscMonitor->startAnimation(); 0415 #endif 0416 } 0417 0418 void KSWizard::slotGSCInstallerFinished() 0419 { 0420 #ifdef Q_OS_OSX 0421 if (downloadMonitor) 0422 { 0423 downloadMonitor->stop(); 0424 delete downloadMonitor; 0425 } 0426 data->downloadProgress->setEnabled(false); 0427 data->downloadProgress->setValue(0); 0428 data->downloadProgress->setVisible(false); 0429 gscMonitor->stopAnimation(); 0430 slotUpdateDataButtons(); 0431 if (QFile(gscZipPath).exists()) 0432 QFile(gscZipPath).remove(); 0433 #endif 0434 } 0435 0436 #ifdef Q_OS_OSX 0437 bool KSWizard::dataDirExists() 0438 { 0439 QString dataLocation = 0440 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory); 0441 return !dataLocation.isEmpty(); 0442 } 0443 0444 bool KSWizard::GSCExists() 0445 { 0446 QString GSCLocation = 0447 QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars/gsc", QStandardPaths::LocateDirectory); 0448 return !GSCLocation.isEmpty(); 0449 } 0450 0451 #endif 0452 0453 void KSWizard::slotUpdateDataButtons() 0454 { 0455 #ifdef Q_OS_OSX 0456 data->dataDirFound->setChecked(dataDirExists()); 0457 if (dataDirExists()) 0458 { 0459 data->copyKStarsData->setText("Open KStars Data Directory"); 0460 data->foundFeedback1->setText("The KStars Data Directory called kstars is located at:"); 0461 data->foundFeedback2->setText("Your data directory was found. If you have any problems with it, you can " 0462 "always delete this data directory and KStars will give you a new data " 0463 "directory. You can click this button to open the data directory, just be " 0464 "careful not to delete any important files."); 0465 } 0466 else 0467 { 0468 data->foundFeedback1->setText("The KStars Data Directory called kstars should be located at:"); 0469 data->foundFeedback2->setText("<html><head/><body><p>Your data directory was not found. You can click the " 0470 "button below to copy a default KStars data directory to the correct location, " 0471 "or if you have a KStars directory already some place else, you can exit KStars " 0472 "and copy it to that location yourself.</p></body></html>"); 0473 } 0474 bool ifGSCExists = GSCExists(); 0475 data->GSCFound->setChecked(ifGSCExists); 0476 data->installGSC->setDisabled(ifGSCExists || !dataDirExists()); 0477 if (ifGSCExists) 0478 data->GSCFeedback->setText("GSC was found on your system. To use it, just take an image in the CCD simulator. " 0479 "To uninstall, just delete the gsc folder from your data directory above."); 0480 setButtonsEnabled(); 0481 #endif 0482 }