Kstars

kswizard.cpp
1/*
2 SPDX-FileCopyrightText: 2004 Jason Harris <kstars@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "kswizard.h"
8
9#include "geolocation.h"
10#include "kspaths.h"
11#include "kstars.h"
12#include "kstarsdata.h"
13#include "ksnotification.h"
14#include "ksutils.h"
15#include "Options.h"
16#include "widgets/dmsbox.h"
17
18#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
19#include <KNSWidgets/dialog.h>
20#else
21#include <kns3/downloaddialog.h>
22#endif
23
24#include <QDesktopServices>
25#include <QFile>
26#include <QLineEdit>
27#include <QPixmap>
28#include <QPushButton>
29#include <QStackedWidget>
30#include <QStandardPaths>
31
32namespace
33{
34bool hasPrefix(QString str, QString prefix)
35{
36 if (prefix.isEmpty())
37 return true;
38 return str.startsWith(prefix, Qt::CaseInsensitive);
39}
40}
41
42WizWelcomeUI::WizWelcomeUI(QWidget *parent) : QFrame(parent)
43{
44 setupUi(this);
45}
46
47WizLocationUI::WizLocationUI(QWidget *parent) : QFrame(parent)
48{
49 setupUi(this);
50}
51
52WizDownloadUI::WizDownloadUI(QWidget *parent) : QFrame(parent)
53{
54 setupUi(this);
55}
56
57#ifdef Q_OS_MACOS
58WizDataUI::WizDataUI(QWidget *parent) : QFrame(parent)
59{
60 setupUi(this);
61}
62#endif
63
65{
66 wizardStack = new QStackedWidget(this);
67 adjustSize();
68
69 setWindowTitle(i18nc("@title:window", "Startup Wizard"));
70
71 QVBoxLayout *mainLayout = new QVBoxLayout;
72 mainLayout->addWidget(wizardStack);
73 setLayout(mainLayout);
74
75 buttonBox = new QDialogButtonBox(Qt::Horizontal);
76 nextB = new QPushButton(i18n("&Next >"));
77 nextB->setDefault(true);
78 backB = new QPushButton(i18n("< &Back"));
79 backB->setEnabled(false);
80 completeB = new QPushButton(i18n("Done"));
81
82 buttonBox->addButton(backB, QDialogButtonBox::ActionRole);
83 buttonBox->addButton(nextB, QDialogButtonBox::ActionRole);
84 buttonBox->addButton(completeB, QDialogButtonBox::AcceptRole);
85 completeB->setVisible(false);
86
87 mainLayout->addWidget(buttonBox);
88
89 welcome = new WizWelcomeUI(wizardStack);
90#ifdef Q_OS_MACOS
91 data = new WizDataUI(wizardStack);
92#endif
93 location = new WizLocationUI(wizardStack);
94 WizDownloadUI *download = new WizDownloadUI(wizardStack);
95
96 wizardStack->addWidget(welcome);
97#ifdef Q_OS_MACOS
98 wizardStack->addWidget(data);
99#endif
100 wizardStack->addWidget(location);
101 wizardStack->addWidget(download);
102 wizardStack->setCurrentWidget(welcome);
103
104 //Load images into banner frames.
105 QPixmap im;
106 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzstars.png")))
107 welcome->Banner->setPixmap(im);
108 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() +
109 "/wzstars.png"))
110 welcome->Banner->setPixmap(im);
111 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzgeo.png")))
112 location->Banner->setPixmap(im);
113 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() + "/wzgeo.png"))
114 location->Banner->setPixmap(im);
115 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzdownload.png")))
116 download->Banner->setPixmap(im);
117 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() +
118 "/wzdownload.png"))
119 download->Banner->setPixmap(im);
120
121#ifdef Q_OS_MACOS
122 if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzdownload.png")))
123 data->Banner->setPixmap(im);
124 else if (im.load(QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath() +
125 "/wzdownload.png"))
126 data->Banner->setPixmap(im);
127
128 data->dataPath->setText(
130 "kstars");
131 slotUpdateDataButtons();
132
133 connect(data->copyKStarsData, SIGNAL(clicked()), this, SLOT(slotOpenOrCopyKStarsDataDirectory()));
134 connect(data->installGSC, SIGNAL(clicked()), this, SLOT(slotInstallGSC()));
135
136 gscMonitor = new QProgressIndicator(data);
137 data->GSCLayout->addWidget(gscMonitor);
138 data->downloadProgress->setValue(0);
139
140 data->downloadProgress->setEnabled(false);
141 data->downloadProgress->setVisible(false);
142
143 data->gscInstallCancel->setVisible(false);
144 data->gscInstallCancel->setEnabled(false);
145
146#endif
147
148 //connect signals/slots
149 connect(nextB, SIGNAL(clicked()), this, SLOT(slotNextPage()));
150 connect(backB, SIGNAL(clicked()), this, SLOT(slotPrevPage()));
151 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
152 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
153
154 connect(location->CityListBox, SIGNAL(itemSelectionChanged()), this, SLOT(slotChangeCity()));
155 connect(location->CityFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities()));
156 connect(location->ProvinceFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities()));
157 connect(location->CountryFilter, SIGNAL(textChanged(QString)), this, SLOT(slotFilterCities()));
158 connect(download->DownloadButton, SIGNAL(clicked()), this, SLOT(slotDownload()));
159
160 //Initialize Geographic Location page
161 if (KStars::Instance())
162 initGeoPage();
163}
164
165void KSWizard::setButtonsEnabled()
166{
167 nextB->setEnabled(wizardStack->currentIndex() < wizardStack->count() - 1);
168 backB->setEnabled(wizardStack->currentIndex() > 0);
169 completeB->setVisible(wizardStack->currentIndex() == wizardStack->count() - 1);
170
171#ifdef Q_OS_MACOS
172 if ((wizardStack->currentWidget() == data) && (!dataDirExists()))
173 {
174 nextB->setEnabled(false);
175 }
176#endif
177}
178
179void KSWizard::slotNextPage()
180{
181 wizardStack->setCurrentIndex(wizardStack->currentIndex() + 1);
182 setButtonsEnabled();
183}
184
185void KSWizard::slotPrevPage()
186{
187 wizardStack->setCurrentIndex(wizardStack->currentIndex() - 1);
188 setButtonsEnabled();
189}
190
191void KSWizard::initGeoPage()
192{
193 KStarsData *data = KStarsData::Instance();
194 location->LongBox->setReadOnly(true);
195 location->LatBox->setReadOnly(true);
196
197 //Populate the CityListBox
198 //flag the ID of the current City
199 foreach (GeoLocation *loc, data->getGeoList())
200 {
201 location->CityListBox->addItem(loc->fullName());
202 filteredCityList.append(loc);
203 if (loc->fullName() == data->geo()->fullName())
204 {
205 Geo = loc;
206 }
207 }
208
209 //Sort alphabetically
210 location->CityListBox->sortItems();
211 //preset to current city
212 QList<QListWidgetItem*> locations = location->CityListBox->findItems(QString(data->geo()->fullName()), Qt::MatchExactly);
213 if (locations.isEmpty() == false)
214 location->CityListBox->setCurrentItem(locations[0]);
215}
216
217void KSWizard::slotChangeCity()
218{
219 if (location->CityListBox->currentItem())
220 {
221 for (auto &city : filteredCityList)
222 {
223 if (city->fullName() == location->CityListBox->currentItem()->text())
224 {
225 Geo = city;
226 break;
227 }
228 }
229 location->LongBox->show(Geo->lng());
230 location->LatBox->show(Geo->lat());
231 }
232}
233
234void KSWizard::slotFilterCities()
235{
236 location->CityListBox->clear();
237 //Do NOT delete members of filteredCityList!
238 filteredCityList.clear();
239
240 foreach (GeoLocation *loc, KStarsData::Instance()->getGeoList())
241 {
242 if (hasPrefix(loc->translatedName(), location->CityFilter->text()) &&
243 hasPrefix(loc->translatedCountry(), location->CountryFilter->text()) &&
244 hasPrefix(loc->translatedProvince(), location->ProvinceFilter->text()))
245 {
246 location->CityListBox->addItem(loc->fullName());
247 filteredCityList.append(loc);
248 }
249 }
250 location->CityListBox->sortItems();
251
252 if (location->CityListBox->count() > 0) // set first item in list as selected
253 location->CityListBox->setCurrentItem(location->CityListBox->item(0));
254}
255
256void KSWizard::slotDownload()
257{
258 //FIX ME, this doesn't work
259 //KNSWidgets::Dialog dlg;
260 //dlg.exec();
261}
262
263void KSWizard::slotOpenOrCopyKStarsDataDirectory()
264{
265#ifdef Q_OS_MACOS
266 QString dataLocation =
268 if (dataLocation.isEmpty())
269 {
270 QDir dataSourceDir = QDir(QCoreApplication::applicationDirPath() + "/../Resources/kstars").absolutePath();
271 if (! dataSourceDir.exists()) //If there is no default data directory in the app bundle
272 {
273 KSNotification::sorry(i18n("There was no default data directory found in the app bundle."));
274 return;
275 }
276 QDir writableDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
277 writableDir.mkpath(".");
278 dataLocation =
280 if (dataLocation.isEmpty()) //If there *still* is not a kstars data directory
281 {
282 KSNotification::sorry(i18n("There was a problem creating the data directory ~/Library/Application Support/."));
283 return;
284 }
285 KSUtils::copyRecursively(dataSourceDir.absolutePath(), dataLocation);
286 //This will update the next, ok, and copy kstars dir buttons.
287 slotUpdateDataButtons();
288 }
289 else
290 {
294 }
295
296#endif
297}
298
299void KSWizard::slotInstallGSC()
300{
301#ifdef Q_OS_MACOS
302
304
305 QString location =
307 gscZipPath = location + "/gsc.zip";
308
309 data->downloadProgress->setVisible(true);
310 data->downloadProgress->setEnabled(true);
311
312 data->gscInstallCancel->setVisible(true);
313 data->gscInstallCancel->setEnabled(true);
314
315 QString gscURL = "http://www.indilib.org/jdownloads/Mac/gsc.zip";
316
317 QNetworkReply *response = manager->get(QNetworkRequest(QUrl(gscURL)));
318
319 QMetaObject::Connection *cancelConnection = new QMetaObject::Connection();
320 QMetaObject::Connection *replyConnection = new QMetaObject::Connection();
321 QMetaObject::Connection *percentConnection = new QMetaObject::Connection();
322
323 *percentConnection = connect(response, &QNetworkReply::downloadProgress,
324 [ = ](qint64 bytesReceived, qint64 bytesTotal)
325 {
326 data->downloadProgress->setValue(bytesReceived);
327 data->downloadProgress->setMaximum(bytesTotal);
328 });
329
330 *cancelConnection = connect(data->gscInstallCancel, &QPushButton::clicked,
331 [ = ]()
332 {
333 qDebug() << Q_FUNC_INFO << "Download Cancelled.";
334
335 if(cancelConnection)
336 disconnect(*cancelConnection);
337 if(replyConnection)
338 disconnect(*replyConnection);
339
340 if(response)
341 {
342 response->abort();
343 response->deleteLater();
344 }
345
346 data->downloadProgress->setVisible(false);
347 data->downloadProgress->setEnabled(false);
348
349 data->gscInstallCancel->setVisible(false);
350 data->gscInstallCancel->setEnabled(false);
351
352 if(manager)
353 manager->deleteLater();
354
355 });
356
357 *replyConnection = connect(response, &QNetworkReply::finished, this,
358 [ = ]()
359 {
360 if(response)
361 {
362
363 if(cancelConnection)
364 disconnect(*cancelConnection);
365 if(replyConnection)
366 disconnect(*replyConnection);
367
368 data->downloadProgress->setVisible(false);
369 data->downloadProgress->setEnabled(false);
370
371 data->gscInstallCancel->setVisible(false);
372 data->gscInstallCancel->setEnabled(false);
373
374
375 response->deleteLater();
376 if(manager)
377 manager->deleteLater();
378 if (response->error() != QNetworkReply::NoError)
379 return;
380
381 QByteArray responseData = response->readAll();
382
383 QFile file(gscZipPath);
384 if (QFileInfo(QFileInfo(file).path()).isWritable())
385 {
386 if (!file.open(QIODevice::WriteOnly))
387 {
388 KSNotification::error( i18n("File write error."));
389 return;
390 }
391 else
392 {
393 file.write(responseData.data(), responseData.size());
394 file.close();
395 slotExtractGSC();
396 }
397 }
398 else
399 {
400 KSNotification::error( i18n("Data folder permissions error."));
401 }
402 }
403 });
404
405#endif
406}
407
408void KSWizard::slotExtractGSC()
409{
410#ifdef Q_OS_MACOS
413 QProcess *gscExtractor = new QProcess();
414 connect(gscExtractor, SIGNAL(finished(int)), this, SLOT(slotGSCInstallerFinished()));
415 connect(gscExtractor, SIGNAL(finished(int)), this, SLOT(gscExtractor.deleteLater()));
416 gscExtractor->setWorkingDirectory(location);
417 gscExtractor->start("unzip", QStringList() << "-ao"
418 << "gsc.zip");
419 gscMonitor->startAnimation();
420#endif
421}
422
423void KSWizard::slotGSCInstallerFinished()
424{
425#ifdef Q_OS_MACOS
426 if (downloadMonitor)
427 {
428 downloadMonitor->stop();
429 delete downloadMonitor;
430 }
431 data->downloadProgress->setEnabled(false);
432 data->downloadProgress->setValue(0);
433 data->downloadProgress->setVisible(false);
434 gscMonitor->stopAnimation();
435 slotUpdateDataButtons();
436 if (QFile(gscZipPath).exists())
437 QFile(gscZipPath).remove();
438#endif
439}
440
441#ifdef Q_OS_MACOS
442bool KSWizard::dataDirExists()
443{
444 QString dataLocation =
446 return !dataLocation.isEmpty();
447}
448
449bool KSWizard::GSCExists()
450{
451 QString GSCLocation =
453 return !GSCLocation.isEmpty();
454}
455
456#endif
457
458void KSWizard::slotUpdateDataButtons()
459{
460#ifdef Q_OS_MACOS
461 data->dataDirFound->setChecked(dataDirExists());
462 if (dataDirExists())
463 {
464 data->copyKStarsData->setText("Open KStars Data Directory");
465 data->foundFeedback1->setText("The KStars Data Directory called kstars is located at:");
466 data->foundFeedback2->setText("Your data directory was found. If you have any problems with it, you can "
467 "always delete this data directory and KStars will give you a new data "
468 "directory. You can click this button to open the data directory, just be "
469 "careful not to delete any important files.");
470 }
471 else
472 {
473 data->foundFeedback1->setText("The KStars Data Directory called kstars should be located at:");
474 data->foundFeedback2->setText("<html><head/><body><p>Your data directory was not found. You can click the "
475 "button below to copy a default KStars data directory to the correct location, "
476 "or if you have a KStars directory already some place else, you can exit KStars "
477 "and copy it to that location yourself.</p></body></html>");
478 }
479 bool ifGSCExists = GSCExists();
480 data->GSCFound->setChecked(ifGSCExists);
481 data->installGSC->setDisabled(ifGSCExists || !dataDirExists());
482 if (ifGSCExists)
483 data->GSCFeedback->setText("GSC was found on your system. To use it, just take an image in the CCD simulator. "
484 "To uninstall, just delete the gsc folder from your data directory above.");
485 setButtonsEnabled();
486#endif
487}
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
const CachingDms * lng() const
Definition geolocation.h:64
QString translatedCountry() const
QString translatedName() const
QString translatedProvince() const
KSWizard(QWidget *parent=nullptr)
Constructor.
Definition kswizard.cpp:64
KStarsData is the backbone of KStars.
Definition kstarsdata.h:72
QList< GeoLocation * > & getGeoList()
Definition kstarsdata.h:236
GeoLocation * geo()
Definition kstarsdata.h:230
static KStars * Instance()
Definition kstars.h:123
The QProgressIndicator class lets an application display a progress indicator to show that a long tas...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
QVariant location(const QVariant &res)
QString path(const QString &relativePath)
void clicked(bool checked)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
char * data()
qsizetype size() const const
QString applicationDirPath()
bool openUrl(const QUrl &url)
virtual void accept()
void accepted()
void finished(int result)
virtual void reject()
void rejected()
QPushButton * addButton(StandardButton button)
QString absolutePath() const const
bool exists() const const
bool remove()
QByteArray readAll()
void append(QList< T > &&value)
bool isEmpty() const const
QNetworkReply * get(const QNetworkRequest &request)
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
NetworkError error() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
bool load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
void setWorkingDirectory(const QString &dir)
void start(OpenMode mode)
void setDefault(bool)
int addWidget(QWidget *widget)
QWidget * currentWidget() const const
void setCurrentWidget(QWidget *widget)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
CaseInsensitive
MatchExactly
Horizontal
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl fromLocalFile(const QString &localFile)
void adjustSize()
void setEnabled(bool)
void setLayout(QLayout *layout)
void show()
virtual void setVisible(bool visible)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:10 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.