Kstars

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

KDE's Doxygen guidelines are available online.