1 /*
2 * Copyright (C) 2012 Alexander Wolf
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
17 */
18
19 #include "StelProjector.hpp"
20 #include "StelPainter.hpp"
21 #include "StelApp.hpp"
22 #include "StelCore.hpp"
23 #include "StelGui.hpp"
24 #include "StelGuiItems.hpp"
25 #include "StelLocaleMgr.hpp"
26 #include "StelModuleMgr.hpp"
27 #include "StelObjectMgr.hpp"
28 #include "StelTextureMgr.hpp"
29 #include "StelJsonParser.hpp"
30 #include "StelFileMgr.hpp"
31 #include "StelUtils.hpp"
32 #include "StelTranslator.hpp"
33 #include "LabelMgr.hpp"
34 #include "Pulsar.hpp"
35 #include "Pulsars.hpp"
36 #include "PulsarsDialog.hpp"
37 #include "StelProgressController.hpp"
38
39 #include <QNetworkAccessManager>
40 #include <QNetworkReply>
41 #include <QKeyEvent>
42 #include <QDebug>
43 #include <QFileInfo>
44 #include <QFile>
45 #include <QTimer>
46 #include <QVariantMap>
47 #include <QVariant>
48 #include <QList>
49 #include <QSharedPointer>
50 #include <QStringList>
51 #include <QDir>
52 #include <QSettings>
53 #include <stdexcept>
54
55 #define CATALOG_FORMAT_VERSION 2 /* Version of format of catalog */
56
57 /*
58 This method is the one called automatically by the StelModuleMgr just
59 after loading the dynamic library
60 */
getStelModule() const61 StelModule* PulsarsStelPluginInterface::getStelModule() const
62 {
63 return new Pulsars();
64 }
65
getPluginInfo() const66 StelPluginInfo PulsarsStelPluginInterface::getPluginInfo() const
67 {
68 Q_INIT_RESOURCE(Pulsars);
69
70 StelPluginInfo info;
71 info.id = "Pulsars";
72 info.displayedName = N_("Pulsars");
73 info.authors = "Alexander Wolf";
74 info.contact = STELLARIUM_DEV_URL;
75 info.description = N_("This plugin plots the position of various pulsars, with object information about each one.");
76 info.version = PULSARS_PLUGIN_VERSION;
77 info.license = PULSARS_PLUGIN_LICENSE;
78 return info;
79 }
80
81 /*
82 Constructor
83 */
Pulsars()84 Pulsars::Pulsars()
85 : PsrCount(0)
86 , updateState(CompleteNoUpdates)
87 , networkManager(Q_NULLPTR)
88 , downloadReply(Q_NULLPTR)
89 , updateTimer(Q_NULLPTR)
90 , updatesEnabled(false)
91 , updateFrequencyDays(0)
92 , enableAtStartup(false)
93 , flagShowPulsars(false)
94 , flagShowPulsarsButton(false)
95 , OnIcon(Q_NULLPTR)
96 , OffIcon(Q_NULLPTR)
97 , GlowIcon(Q_NULLPTR)
98 , toolbarButton(Q_NULLPTR)
99 , progressBar(Q_NULLPTR)
100 {
101 setObjectName("Pulsars");
102 configDialog = new PulsarsDialog();
103 conf = StelApp::getInstance().getSettings();
104 setFontSize(StelApp::getInstance().getScreenFontSize());
105 connect(&StelApp::getInstance(), SIGNAL(screenFontSizeChanged(int)), this, SLOT(setFontSize(int)));
106 }
107
108 /*
109 Destructor
110 */
~Pulsars()111 Pulsars::~Pulsars()
112 {
113 delete configDialog;
114
115 if (GlowIcon)
116 delete GlowIcon;
117 if (OnIcon)
118 delete OnIcon;
119 if (OffIcon)
120 delete OffIcon;
121 }
122
deinit()123 void Pulsars::deinit()
124 {
125 psr.clear();
126 Pulsar::markerTexture.clear();
127 texPointer.clear();
128 }
129
130 /*
131 Reimplementation of the getCallOrder method
132 */
getCallOrder(StelModuleActionName actionName) const133 double Pulsars::getCallOrder(StelModuleActionName actionName) const
134 {
135 if (actionName==StelModule::ActionDraw)
136 return StelApp::getInstance().getModuleMgr().getModule("ConstellationMgr")->getCallOrder(actionName)+10.;
137 return 0;
138 }
139
140
141 /*
142 Init our module
143 */
init()144 void Pulsars::init()
145 {
146 upgradeConfigIni();
147
148 try
149 {
150 StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::getUserDir()+"/modules/Pulsars");
151
152 // If no settings in the main config file, create with defaults
153 if (!conf->childGroups().contains("Pulsars"))
154 {
155 qDebug() << "[Pulsars] No Pulsars section exists in main config file - creating with defaults";
156 restoreDefaultConfigIni();
157 }
158
159 // populate settings from main config file.
160 readSettingsFromConfig();
161
162 jsonCatalogPath = StelFileMgr::findFile("modules/Pulsars", static_cast<StelFileMgr::Flags>(StelFileMgr::Directory|StelFileMgr::Writable)) + "/pulsars.json";
163 if (jsonCatalogPath.isEmpty())
164 return;
165
166 texPointer = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/pointeur2.png");
167 Pulsar::markerTexture = StelApp::getInstance().getTextureManager().createTexture(":/Pulsars/pulsar.png");
168
169 // key bindings and other actions
170 addAction("actionShow_Pulsars", N_("Pulsars"), N_("Show pulsars"), "pulsarsVisible", "Ctrl+Alt+P");
171 addAction("actionShow_Pulsars_dialog", N_("Pulsars"), N_("Show settings dialog"), configDialog, "visible", ""); // Allow assign shortkey
172
173 GlowIcon = new QPixmap(":/graphicGui/miscGlow32x32.png");
174 OnIcon = new QPixmap(":/Pulsars/btPulsars-on.png");
175 OffIcon = new QPixmap(":/Pulsars/btPulsars-off.png");
176
177 setFlagShowPulsars(getEnableAtStartup());
178 setFlagShowPulsarsButton(flagShowPulsarsButton);
179 }
180 catch (std::runtime_error &e)
181 {
182 qWarning() << "[Pulsars] init error:" << e.what();
183 return;
184 }
185
186 // If the json file does not already exist, create it from the resource in the Qt resource
187 if(QFileInfo(jsonCatalogPath).exists())
188 {
189 if (!checkJsonFileFormat() || getJsonFileFormatVersion()<CATALOG_FORMAT_VERSION)
190 {
191 restoreDefaultJsonFile();
192 }
193 }
194 else
195 {
196 qDebug() << "[Pulsars] pulsars.json does not exist - copying default file to" << QDir::toNativeSeparators(jsonCatalogPath);
197 restoreDefaultJsonFile();
198 }
199
200 qDebug() << "[Pulsars] Loading catalog file:" << QDir::toNativeSeparators(jsonCatalogPath);
201
202 readJsonFile();
203
204 // Set up download manager and the update schedule
205 networkManager = StelApp::getInstance().getNetworkAccessManager();
206 updateState = CompleteNoUpdates;
207 updateTimer = new QTimer(this);
208 updateTimer->setSingleShot(false); // recurring check for update
209 updateTimer->setInterval(13000); // check once every 13 seconds to see if it is time for an update
210 connect(updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdate()));
211 updateTimer->start();
212
213 connect(this, SIGNAL(jsonUpdateComplete(void)), this, SLOT(reloadCatalog()));
214 connect(StelApp::getInstance().getCore(), SIGNAL(configurationDataSaved()), this, SLOT(saveSettings()));
215
216 GETSTELMODULE(StelObjectMgr)->registerStelObjectMgr(this);
217 }
218
219 /*
220 Draw our module.
221 */
draw(StelCore * core)222 void Pulsars::draw(StelCore* core)
223 {
224 if (!flagShowPulsars)
225 return;
226
227 StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
228 StelPainter painter(prj);
229 painter.setFont(font);
230
231 for (const auto& pulsar : qAsConst(psr))
232 {
233 if (pulsar && pulsar->initialized)
234 pulsar->draw(core, &painter);
235 }
236
237 if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer())
238 drawPointer(core, painter);
239 }
240
drawPointer(StelCore * core,StelPainter & painter)241 void Pulsars::drawPointer(StelCore* core, StelPainter& painter)
242 {
243 const StelProjectorP prj = core->getProjection(StelCore::FrameJ2000);
244
245 const QList<StelObjectP> newSelected = GETSTELMODULE(StelObjectMgr)->getSelectedObject("Pulsar");
246 if (!newSelected.empty())
247 {
248 const StelObjectP obj = newSelected[0];
249 Vec3d pos=obj->getJ2000EquatorialPos(core);
250
251 Vec3f screenpos;
252 // Compute 2D pos and return if outside screen
253 if (!painter.getProjector()->project(pos.toVec3f(), screenpos))
254 return;
255
256 painter.setColor(obj->getInfoColor());
257 texPointer->bind();
258 painter.setBlending(true);
259 painter.drawSprite2dMode(screenpos[0], screenpos[1], 13.f, StelApp::getInstance().getTotalRunTime()*40.);
260 }
261 }
262
searchAround(const Vec3d & av,double limitFov,const StelCore * core) const263 QList<StelObjectP> Pulsars::searchAround(const Vec3d& av, double limitFov, const StelCore* core) const
264 {
265 QList<StelObjectP> result;
266
267 if (!flagShowPulsars)
268 return result;
269
270 Vec3d v(av);
271 v.normalize();
272 const double cosLimFov = cos(limitFov * M_PI/180.);
273 Vec3d equPos;
274
275 for (const auto& pulsar : psr)
276 {
277 if (pulsar->initialized)
278 {
279 equPos = pulsar->getJ2000EquatorialPos(core);
280 equPos.normalize();
281 if (equPos.dot(v) >= cosLimFov)
282 {
283 result.append(qSharedPointerCast<StelObject>(pulsar));
284 }
285 }
286 }
287
288 return result;
289 }
290
searchByName(const QString & englishName) const291 StelObjectP Pulsars::searchByName(const QString& englishName) const
292 {
293 if (!flagShowPulsars)
294 return Q_NULLPTR;
295
296 for (const auto& pulsar : psr)
297 {
298 if (pulsar->getEnglishName().toUpper() == englishName.toUpper() || pulsar->getDesignation().toUpper() == englishName.toUpper())
299 return qSharedPointerCast<StelObject>(pulsar);
300 }
301
302 return Q_NULLPTR;
303 }
304
searchByNameI18n(const QString & nameI18n) const305 StelObjectP Pulsars::searchByNameI18n(const QString& nameI18n) const
306 {
307 if (!flagShowPulsars)
308 return Q_NULLPTR;
309
310 for (const auto& pulsar : psr)
311 {
312 if (pulsar->getNameI18n().toUpper() == nameI18n.toUpper() || pulsar->getDesignation().toUpper() == nameI18n.toUpper())
313 return qSharedPointerCast<StelObject>(pulsar);
314 }
315
316 return Q_NULLPTR;
317 }
318
listMatchingObjects(const QString & objPrefix,int maxNbItem,bool useStartOfWords) const319 QStringList Pulsars::listMatchingObjects(const QString& objPrefix, int maxNbItem, bool useStartOfWords) const
320 {
321 QStringList result;
322 if (flagShowPulsars && maxNbItem>0)
323 {
324 QStringList names;
325 for (const auto& pulsar : psr)
326 {
327 if (!pulsar->getNameI18n().isEmpty())
328 names << pulsar->getNameI18n();
329 if (!pulsar->getEnglishName().isEmpty())
330 names << pulsar->getEnglishName();
331 names << pulsar->getDesignation();
332 }
333
334 QString fullMatch = "";
335 for (const auto& name : qAsConst(names))
336 {
337 if (!matchObjectName(name, objPrefix, useStartOfWords))
338 continue;
339
340 if (name==objPrefix)
341 fullMatch = name;
342 else
343 result.append(name);
344
345 if (result.size() >= maxNbItem)
346 break;
347 }
348
349 result.sort();
350 if (!fullMatch.isEmpty())
351 result.prepend(fullMatch);
352 }
353 return result;
354 }
355
listAllObjects(bool inEnglish) const356 QStringList Pulsars::listAllObjects(bool inEnglish) const
357 {
358 QStringList result;
359 if (!flagShowPulsars)
360 return result;
361
362 if (inEnglish)
363 {
364 for (const auto& pulsar : psr)
365 {
366 if (!pulsar->getEnglishName().isEmpty())
367 result << pulsar->getEnglishName();
368 result << pulsar->getDesignation();
369 }
370 }
371 else
372 {
373 for (const auto& pulsar : psr)
374 {
375 if (!pulsar->getNameI18n().isEmpty())
376 result << pulsar->getNameI18n();
377 result << pulsar->getDesignation();
378 }
379 }
380 return result;
381 }
382
383 /*
384 Replace the JSON file with the default from the compiled-in resource
385 */
restoreDefaultJsonFile(void)386 void Pulsars::restoreDefaultJsonFile(void)
387 {
388 if (QFileInfo(jsonCatalogPath).exists())
389 backupJsonFile(true);
390
391 QFile src(":/Pulsars/pulsars.json");
392 if (!src.copy(jsonCatalogPath))
393 {
394 qWarning() << "[Pulsars] Cannot copy JSON resource to" + QDir::toNativeSeparators(jsonCatalogPath);
395 }
396 else
397 {
398 qDebug() << "[Pulsars] Copied default pulsars.json to" << QDir::toNativeSeparators(jsonCatalogPath);
399 // The resource is read only, and the new file inherits this... make sure the new file
400 // is writable by the Stellarium process so that updates can be done.
401 QFile dest(jsonCatalogPath);
402 dest.setPermissions(dest.permissions() | QFile::WriteOwner);
403
404 // Make sure that in the case where an online update has previously been done, but
405 // the json file has been manually removed, that an update is schreduled in a timely
406 // manner
407 conf->remove("Pulsars/last_update");
408 lastUpdate = QDateTime::fromString("2012-05-24T12:00:00", Qt::ISODate);
409 }
410 }
411
412 /*
413 Creates a backup of the pulsars.json file called pulsars.json.old
414 */
backupJsonFile(bool deleteOriginal)415 bool Pulsars::backupJsonFile(bool deleteOriginal)
416 {
417 QFile old(jsonCatalogPath);
418 if (!old.exists())
419 {
420 qWarning() << "[Pulsars] No file to backup";
421 return false;
422 }
423
424 QString backupPath = jsonCatalogPath + ".old";
425 if (QFileInfo(backupPath).exists())
426 QFile(backupPath).remove();
427
428 if (old.copy(backupPath))
429 {
430 if (deleteOriginal)
431 {
432 if (!old.remove())
433 {
434 qWarning() << "[Pulsars] WARNING - could not remove old pulsars.json file";
435 return false;
436 }
437 }
438 }
439 else
440 {
441 qWarning() << "[Pulsars] WARNING - failed to copy pulsars.json to pulsars.json.old";
442 return false;
443 }
444
445 return true;
446 }
447
448 /*
449 Read the JSON file and create list of pulsars.
450 */
readJsonFile(void)451 void Pulsars::readJsonFile(void)
452 {
453 setPSRMap(loadPSRMap());
454 }
455
456 /*
457 Parse JSON file and load pulsars to map
458 */
loadPSRMap(QString path)459 QVariantMap Pulsars::loadPSRMap(QString path)
460 {
461 if (path.isEmpty())
462 path = jsonCatalogPath;
463
464 QVariantMap map;
465 QFile jsonFile(path);
466 if (!jsonFile.open(QIODevice::ReadOnly))
467 qWarning() << "[Pulsars] Cannot open" << QDir::toNativeSeparators(path);
468 else
469 {
470 try
471 {
472 map = StelJsonParser::parse(jsonFile.readAll()).toMap();
473 jsonFile.close();
474 }
475 catch (std::runtime_error &e)
476 {
477 qDebug() << "[Pulsars] File format is wrong! Error: " << e.what();
478 return QVariantMap();
479 }
480 }
481 return map;
482 }
483
484 /*
485 Set items for list of struct from data map
486 */
setPSRMap(const QVariantMap & map)487 void Pulsars::setPSRMap(const QVariantMap& map)
488 {
489 psr.clear();
490 PsrCount = 0;
491 QVariantMap psrMap = map.value("pulsars").toMap();
492 for (auto psrKey : psrMap.keys())
493 {
494 QVariantMap psrData = psrMap.value(psrKey).toMap();
495 psrData["designation"] = psrKey;
496
497 PsrCount++;
498
499 PulsarP pulsar(new Pulsar(psrData));
500 if (pulsar->initialized)
501 psr.append(pulsar);
502 }
503 }
504
getJsonFileFormatVersion(void)505 int Pulsars::getJsonFileFormatVersion(void)
506 {
507 int jsonVersion = -1;
508 QFile jsonPSRCatalogFile(jsonCatalogPath);
509 if (!jsonPSRCatalogFile.open(QIODevice::ReadOnly))
510 {
511 qWarning() << "[Pulsars] Cannot open" << QDir::toNativeSeparators(jsonCatalogPath);
512 return jsonVersion;
513 }
514
515 QVariantMap map;
516 try
517 {
518 map = StelJsonParser::parse(&jsonPSRCatalogFile).toMap();
519 jsonPSRCatalogFile.close();
520 }
521 catch (std::runtime_error &e)
522 {
523 qDebug() << "[Pulsars] File format is wrong! Error: " << e.what();
524 return jsonVersion;
525 }
526 if (map.contains("version"))
527 {
528 jsonVersion = map.value("version").toInt();
529 }
530 qDebug() << "[Pulsars] Version of the format of the catalog:" << jsonVersion;
531 return jsonVersion;
532 }
533
checkJsonFileFormat()534 bool Pulsars::checkJsonFileFormat()
535 {
536 QFile jsonPSRCatalogFile(jsonCatalogPath);
537 if (!jsonPSRCatalogFile.open(QIODevice::ReadOnly))
538 {
539 qWarning() << "[Pulsars] Cannot open" << QDir::toNativeSeparators(jsonCatalogPath);
540 return false;
541 }
542
543 QVariantMap map;
544 try
545 {
546 map = StelJsonParser::parse(&jsonPSRCatalogFile).toMap();
547 jsonPSRCatalogFile.close();
548 }
549 catch (std::runtime_error& e)
550 {
551 qDebug() << "[Pulsars] File format is wrong! Error:" << e.what();
552 return false;
553 }
554
555 return true;
556 }
557
getByID(const QString & id) const558 PulsarP Pulsars::getByID(const QString& id) const
559 {
560 for (const auto& pulsar : psr)
561 {
562 if (pulsar->initialized && pulsar->designation == id)
563 return pulsar;
564 }
565 return PulsarP();
566 }
567
configureGui(bool show)568 bool Pulsars::configureGui(bool show)
569 {
570 if (show)
571 configDialog->setVisible(true);
572 return true;
573 }
574
restoreDefaults(void)575 void Pulsars::restoreDefaults(void)
576 {
577 restoreDefaultConfigIni();
578 restoreDefaultJsonFile();
579 readJsonFile();
580 readSettingsFromConfig();
581 }
582
restoreDefaultConfigIni(void)583 void Pulsars::restoreDefaultConfigIni(void)
584 {
585 conf->beginGroup("Pulsars");
586
587 // delete all existing Pulsars settings...
588 conf->remove("");
589
590 conf->setValue("distribution_enabled", false);
591 conf->setValue("enable_at_startup", false);
592 conf->setValue("updates_enabled", true);
593 conf->setValue("url", "https://stellarium.org/json/pulsars.json");
594 conf->setValue("update_frequency_days", 100);
595 conf->setValue("flag_show_pulsars_button", true);
596 conf->setValue("marker_color", "0.4,0.5,1.0");
597 conf->setValue("glitch_color", "0.2,0.3,1.0");
598 conf->setValue("use_separate_colors", false);
599 conf->setValue("filter_enabled", false);
600 conf->setValue("filter_value", "150.00");
601 conf->endGroup();
602 }
603
readSettingsFromConfig(void)604 void Pulsars::readSettingsFromConfig(void)
605 {
606 conf->beginGroup("Pulsars");
607
608 updateUrl = conf->value("url", "https://stellarium.org/json/pulsars.json").toString();
609 updateFrequencyDays = conf->value("update_frequency_days", 100).toInt();
610 lastUpdate = QDateTime::fromString(conf->value("last_update", "2012-05-24T12:00:00").toString(), Qt::ISODate);
611 updatesEnabled = conf->value("updates_enabled", true).toBool();
612 setDisplayMode(conf->value("distribution_enabled", false).toBool());
613 setGlitchFlag(conf->value("use_separate_colors", false).toBool());
614 setFilteredMode(conf->value("filter_enabled", false).toBool());
615 setFilterValue(conf->value("filter_value", 150.f).toFloat());
616 setMarkerColor(Vec3f(conf->value("marker_color", "0.4,0.5,1.0").toString()));
617 setGlitchColor(Vec3f(conf->value("glitch_color", "0.2,0.3,1.0").toString()));
618 enableAtStartup = conf->value("enable_at_startup", false).toBool();
619 flagShowPulsarsButton = conf->value("flag_show_pulsars_button", true).toBool();
620
621 conf->endGroup();
622 }
623
saveSettingsToConfig(void)624 void Pulsars::saveSettingsToConfig(void)
625 {
626 conf->beginGroup("Pulsars");
627
628 conf->setValue("url", updateUrl);
629 conf->setValue("update_frequency_days", updateFrequencyDays);
630 conf->setValue("updates_enabled", updatesEnabled);
631 conf->setValue("distribution_enabled", getDisplayMode());
632 conf->setValue("use_separate_colors", getGlitchFlag());
633 conf->setValue("filter_enabled", getFilteredMode());
634 conf->setValue("filter_value", QString::number(getFilterValue(), 'f', 2));
635 conf->setValue("enable_at_startup", enableAtStartup);
636 conf->setValue("flag_show_pulsars_button", flagShowPulsarsButton);
637 conf->setValue("marker_color", getMarkerColor().toStr());
638 conf->setValue("glitch_color", getGlitchColor().toStr());
639
640 conf->endGroup();
641 }
642
getSecondsToUpdate(void)643 int Pulsars::getSecondsToUpdate(void)
644 {
645 QDateTime nextUpdate = lastUpdate.addSecs(updateFrequencyDays * 3600 * 24);
646 return static_cast<int>(QDateTime::currentDateTime().secsTo(nextUpdate));
647 }
648
checkForUpdate(void)649 void Pulsars::checkForUpdate(void)
650 {
651 if (updatesEnabled && lastUpdate.addSecs(updateFrequencyDays * 3600 * 24) <= QDateTime::currentDateTime() && networkManager->networkAccessible()==QNetworkAccessManager::Accessible)
652 updateJSON();
653 }
654
updateJSON(void)655 void Pulsars::updateJSON(void)
656 {
657 if (updateState==Pulsars::Updating)
658 {
659 qWarning() << "[Pulsars] Already updating... will not start again current update is complete.";
660 return;
661 }
662
663 qDebug() << "[Pulsars] Updating pulsars catalog...";
664 startDownload(updateUrl);
665 }
666
deleteDownloadProgressBar()667 void Pulsars::deleteDownloadProgressBar()
668 {
669 disconnect(this, SLOT(updateDownloadProgress(qint64,qint64)));
670
671 if (progressBar)
672 {
673 StelApp::getInstance().removeProgressBar(progressBar);
674 progressBar = Q_NULLPTR;
675 }
676 }
677
startDownload(QString urlString)678 void Pulsars::startDownload(QString urlString)
679 {
680 QUrl url(urlString);
681 if (!url.isValid() || url.isRelative() || !url.scheme().startsWith("http", Qt::CaseInsensitive))
682 {
683 qWarning() << "[Pulsars] Invalid URL:" << urlString;
684 return;
685 }
686
687 if (progressBar == Q_NULLPTR)
688 progressBar = StelApp::getInstance().addProgressBar();
689 progressBar->setValue(0);
690 progressBar->setRange(0, 0);
691
692 connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
693 QNetworkRequest request;
694 request.setUrl(QUrl(updateUrl));
695 request.setRawHeader("User-Agent", StelUtils::getUserAgentString().toUtf8());
696 request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
697 downloadReply = networkManager->get(request);
698 connect(downloadReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64)));
699
700 updateState = Pulsars::Updating;
701 emit(updateStateChanged(updateState));
702 }
703
updateDownloadProgress(qint64 bytesReceived,qint64 bytesTotal)704 void Pulsars::updateDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
705 {
706 if (progressBar == Q_NULLPTR)
707 return;
708
709 int currentValue = 0;
710 int endValue = 0;
711
712 if (bytesTotal > -1 && bytesReceived <= bytesTotal)
713 {
714 //Round to the greatest possible derived unit
715 while (bytesTotal > 1024)
716 {
717 bytesReceived = static_cast<qint64>(std::floor(bytesReceived / 1024.));
718 bytesTotal = static_cast<qint64>(std::floor(bytesTotal / 1024.));
719 }
720 currentValue = static_cast<int>(bytesReceived);
721 endValue = static_cast<int>(bytesTotal);
722 }
723
724 progressBar->setValue(currentValue);
725 progressBar->setRange(0, endValue);
726 }
727
downloadComplete(QNetworkReply * reply)728 void Pulsars::downloadComplete(QNetworkReply *reply)
729 {
730 if (reply == Q_NULLPTR)
731 return;
732
733 disconnect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadComplete(QNetworkReply*)));
734 deleteDownloadProgressBar();
735
736 if (reply->error() || reply->bytesAvailable()==0)
737 {
738 qWarning() << "[Pulsars] Download error: While trying to access"
739 << reply->url().toString()
740 << "the following error occured:"
741 << reply->errorString();
742
743 reply->deleteLater();
744 downloadReply = Q_NULLPTR;
745 return;
746 }
747
748 // download completed successfully.
749 try
750 {
751 QString jsonFilePath = StelFileMgr::findFile("modules/Pulsars", StelFileMgr::Flags(StelFileMgr::Writable|StelFileMgr::Directory)) + "/pulsars.json";
752 QFile jsonFile(jsonFilePath);
753 if (jsonFile.exists())
754 jsonFile.remove();
755
756 if (jsonFile.open(QIODevice::WriteOnly | QIODevice::Text))
757 {
758 jsonFile.write(reply->readAll());
759 jsonFile.close();
760 }
761
762 updateState = Pulsars::CompleteUpdates;
763
764 lastUpdate = QDateTime::currentDateTime();
765 conf->setValue("Pulsars/last_update", lastUpdate.toString(Qt::ISODate));
766 }
767 catch (std::runtime_error &e)
768 {
769 qWarning() << "[Pulsars] Cannot write JSON data to file:" << e.what();
770 updateState = Pulsars::DownloadError;
771 }
772
773 emit(updateStateChanged(updateState));
774 emit(jsonUpdateComplete());
775
776 reply->deleteLater();
777 downloadReply = Q_NULLPTR;
778
779 readJsonFile();
780 }
781
782
displayMessage(const QString & message,const QString hexColor)783 void Pulsars::displayMessage(const QString& message, const QString hexColor)
784 {
785 messageIDs << GETSTELMODULE(LabelMgr)->labelScreen(message, 30, 30 + (20*messageIDs.count()), true, 16, hexColor, false, 9000);
786 }
787
upgradeConfigIni(void)788 void Pulsars::upgradeConfigIni(void)
789 {
790 // Upgrade settings for Pulsars plugin
791 if (conf->contains("Pulsars/flag_show_pulsars"))
792 {
793 bool b = conf->value("Pulsars/flag_show_pulsars", false).toBool();
794 if (!conf->contains("Pulsars/enable_at_startup"))
795 conf->setValue("Pulsars/enable_at_startup", b);
796 conf->remove("Pulsars/flag_show_pulsars");
797 }
798 }
799
800 // Define whether the button toggling pulsars should be visible
setFlagShowPulsarsButton(bool b)801 void Pulsars::setFlagShowPulsarsButton(bool b)
802 {
803 StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
804 if (gui!=Q_NULLPTR)
805 {
806 if (b==true) {
807 if (toolbarButton==Q_NULLPTR) {
808 // Create the pulsars button
809 toolbarButton = new StelButton(Q_NULLPTR, *OnIcon, *OffIcon, *GlowIcon, "actionShow_Pulsars", false, "actionShow_Pulsars_dialog");
810 }
811 gui->getButtonBar()->addButton(toolbarButton, "065-pluginsGroup");
812 } else {
813 gui->getButtonBar()->hideButton("actionShow_Pulsars");
814 }
815 }
816 flagShowPulsarsButton = b;
817 }
818
getDisplayMode() const819 bool Pulsars::getDisplayMode() const
820 {
821 return Pulsar::distributionMode;
822 }
823
setDisplayMode(bool b)824 void Pulsars::setDisplayMode(bool b)
825 {
826 Pulsar::distributionMode=b;
827 }
828
getGlitchFlag() const829 bool Pulsars::getGlitchFlag() const
830 {
831 return Pulsar::glitchFlag;
832 }
833
setGlitchFlag(bool b)834 void Pulsars::setGlitchFlag(bool b)
835 {
836 Pulsar::glitchFlag=b;
837 }
838
getFilteredMode() const839 bool Pulsars::getFilteredMode() const
840 {
841 return Pulsar::filteredMode;
842 }
843
setFilteredMode(bool b)844 void Pulsars::setFilteredMode(bool b)
845 {
846 Pulsar::filteredMode=b;
847 }
848
getFilterValue() const849 float Pulsars::getFilterValue() const
850 {
851 return Pulsar::filterValue;
852 }
853
setFilterValue(float v)854 void Pulsars::setFilterValue(float v)
855 {
856 Pulsar::filterValue=v;
857 }
858
getMarkerColor() const859 Vec3f Pulsars::getMarkerColor() const
860 {
861 return Pulsar::markerColor;
862 }
863
setMarkerColor(const Vec3f & c)864 void Pulsars::setMarkerColor(const Vec3f &c)
865 {
866 Pulsar::markerColor = c;
867 emit markerColorChanged(c);
868 }
869
getGlitchColor() const870 Vec3f Pulsars::getGlitchColor() const
871 {
872 return Pulsar::glitchColor;
873 }
874
setGlitchColor(const Vec3f & c)875 void Pulsars::setGlitchColor(const Vec3f &c)
876 {
877 Pulsar::glitchColor = c;
878 emit glitchColorChanged(c);
879 }
880
reloadCatalog(void)881 void Pulsars::reloadCatalog(void)
882 {
883 bool hasSelection = false;
884 StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
885 // Whether any pulsar are selected? Save the current selection...
886 const QList<StelObjectP> selectedObject = objMgr->getSelectedObject("Pulsar");
887 if (!selectedObject.isEmpty())
888 {
889 // ... unselect current pulsar.
890 hasSelection = true;
891 objMgr->unSelect();
892 }
893
894 readJsonFile();
895
896 if (hasSelection)
897 {
898 // Restore selection...
899 StelObjectP obj = selectedObject[0];
900 objMgr->findAndSelect(obj->getEnglishName(), obj->getType());
901 }
902 }
903
setFlagShowPulsars(bool b)904 void Pulsars::setFlagShowPulsars(bool b)
905 {
906 if (b!=flagShowPulsars)
907 {
908 flagShowPulsars=b;
909 emit flagPulsarsVisibilityChanged(b);
910 emit StelApp::getInstance().getCore()->updateSearchLists();
911 }
912 }
913