1 /*
2 * Stellarium
3 * Copyright (C) 2006 Fabien Chereau
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "StelApp.hpp"
21
22 #include "StelCore.hpp"
23 #include "StelMainView.hpp"
24 #include "StelSplashScreen.hpp"
25 #include "StelUtils.hpp"
26 #include "StelTextureMgr.hpp"
27 #include "StelObjectMgr.hpp"
28 #include "ConstellationMgr.hpp"
29 #include "AsterismMgr.hpp"
30 #include "HipsMgr.hpp"
31 #include "NebulaMgr.hpp"
32 #include "LandscapeMgr.hpp"
33 #include "CustomObjectMgr.hpp"
34 #include "HighlightMgr.hpp"
35 #include "GridLinesMgr.hpp"
36 #include "MilkyWay.hpp"
37 #include "ZodiacalLight.hpp"
38 #include "LabelMgr.hpp"
39 #include "MarkerMgr.hpp"
40 #include "SolarSystem.hpp"
41 #include "NomenclatureMgr.hpp"
42 #include "SporadicMeteorMgr.hpp"
43 #include "StarMgr.hpp"
44 #include "StelIniParser.hpp"
45 #include "StelProjector.hpp"
46 #include "StelLocationMgr.hpp"
47 #include "ToastMgr.hpp"
48 #include "StelActionMgr.hpp"
49 #include "StelPropertyMgr.hpp"
50 #include "StelProgressController.hpp"
51 #include "StelModuleMgr.hpp"
52 #include "StelLocaleMgr.hpp"
53 #include "StelSkyCultureMgr.hpp"
54 #include "StelFileMgr.hpp"
55 #include "StelJsonParser.hpp"
56 #include "StelSkyLayerMgr.hpp"
57 #include "StelAudioMgr.hpp"
58 #include "StelVideoMgr.hpp"
59 #include "SpecialMarkersMgr.hpp"
60 #include "StelViewportEffect.hpp"
61 #include "StelGuiBase.hpp"
62 #include "StelPainter.hpp"
63 #ifdef ENABLE_SCRIPTING
64 #include "StelScriptMgr.hpp"
65 #include "StelMainScriptAPIProxy.hpp"
66 #endif
67
68
69 #include <cstdlib>
70 #include <iostream>
71 #include <QDebug>
72 #include <QFile>
73 #include <QFileInfo>
74 #include <QMouseEvent>
75 #include <QNetworkAccessManager>
76 #include <QNetworkDiskCache>
77 #include <QNetworkProxy>
78 #include <QNetworkReply>
79 #include <QOpenGLContext>
80 #include <QOpenGLFramebufferObject>
81 #include <QString>
82 #include <QStringList>
83 #include <QSysInfo>
84 #include <QTextStream>
85 #include <QTimer>
86 #include <QDir>
87 #include <QCoreApplication>
88 #include <QGuiApplication>
89 #include <QScreen>
90 #include <QDateTime>
91 #include <QRegularExpression>
92 #ifdef ENABLE_SPOUT
93 #include <QMessageBox>
94 #include "SpoutSender.hpp"
95 #endif
96
97 #ifdef USE_STATIC_PLUGIN_HELLOSTELMODULE
98 Q_IMPORT_PLUGIN(HelloStelModuleStelPluginInterface)
99 #endif
100
101 #ifdef USE_STATIC_PLUGIN_SIMPLEDRAWLINE
102 Q_IMPORT_PLUGIN(SimpleDrawLineStelPluginInterface)
103 #endif
104
105 #ifdef USE_STATIC_PLUGIN_ANGLEMEASURE
106 Q_IMPORT_PLUGIN(AngleMeasureStelPluginInterface)
107 #endif
108
109 #ifdef USE_STATIC_PLUGIN_ARCHAEOLINES
110 Q_IMPORT_PLUGIN(ArchaeoLinesStelPluginInterface)
111 #endif
112
113 #ifdef USE_STATIC_PLUGIN_CALENDARS
114 Q_IMPORT_PLUGIN(CalendarsStelPluginInterface)
115 #endif
116
117 #ifdef USE_STATIC_PLUGIN_SATELLITES
118 Q_IMPORT_PLUGIN(SatellitesStelPluginInterface)
119 #endif
120
121 #ifdef USE_STATIC_PLUGIN_TEXTUSERINTERFACE
122 Q_IMPORT_PLUGIN(TextUserInterfaceStelPluginInterface)
123 #endif
124
125 #ifdef USE_STATIC_PLUGIN_OCULARS
126 Q_IMPORT_PLUGIN(OcularsStelPluginInterface)
127 #endif
128
129 #ifdef USE_STATIC_PLUGIN_OCULUS
130 Q_IMPORT_PLUGIN(OculusStelPluginInterface)
131 #endif
132
133 #ifdef USE_STATIC_PLUGIN_TELESCOPECONTROL
134 Q_IMPORT_PLUGIN(TelescopeControlStelPluginInterface)
135 #endif
136
137 #ifdef USE_STATIC_PLUGIN_SOLARSYSTEMEDITOR
138 Q_IMPORT_PLUGIN(SolarSystemEditorStelPluginInterface)
139 #endif
140
141 #ifdef USE_STATIC_PLUGIN_METEORSHOWERS
142 Q_IMPORT_PLUGIN(MeteorShowersStelPluginInterface)
143 #endif
144
145 #ifdef USE_STATIC_PLUGIN_NAVSTARS
146 Q_IMPORT_PLUGIN(NavStarsStelPluginInterface)
147 #endif
148
149 #ifdef USE_STATIC_PLUGIN_NOVAE
150 Q_IMPORT_PLUGIN(NovaeStelPluginInterface)
151 #endif
152
153 #ifdef USE_STATIC_PLUGIN_SUPERNOVAE
154 Q_IMPORT_PLUGIN(SupernovaeStelPluginInterface)
155 #endif
156
157 #ifdef USE_STATIC_PLUGIN_QUASARS
158 Q_IMPORT_PLUGIN(QuasarsStelPluginInterface)
159 #endif
160
161 #ifdef USE_STATIC_PLUGIN_PULSARS
162 Q_IMPORT_PLUGIN(PulsarsStelPluginInterface)
163 #endif
164
165 #ifdef USE_STATIC_PLUGIN_EXOPLANETS
166 Q_IMPORT_PLUGIN(ExoplanetsStelPluginInterface)
167 #endif
168
169 #ifdef USE_STATIC_PLUGIN_EQUATIONOFTIME
170 Q_IMPORT_PLUGIN(EquationOfTimeStelPluginInterface)
171 #endif
172
173 #ifdef USE_STATIC_PLUGIN_POINTERCOORDINATES
174 Q_IMPORT_PLUGIN(PointerCoordinatesStelPluginInterface)
175 #endif
176
177 #ifdef USE_STATIC_PLUGIN_OBSERVABILITY
178 Q_IMPORT_PLUGIN(ObservabilityStelPluginInterface)
179 #endif
180
181 #ifdef USE_STATIC_PLUGIN_SCENERY3D
182 Q_IMPORT_PLUGIN(Scenery3dStelPluginInterface)
183 #endif
184
185 #ifdef USE_STATIC_PLUGIN_REMOTECONTROL
186 Q_IMPORT_PLUGIN(RemoteControlStelPluginInterface)
187 #endif
188
189 #ifdef USE_STATIC_PLUGIN_REMOTESYNC
190 Q_IMPORT_PLUGIN(RemoteSyncStelPluginInterface)
191 #endif
192
193 #ifdef USE_STATIC_PLUGIN_VTS
194 Q_IMPORT_PLUGIN(VtsStelPluginInterface)
195 #endif
196
197 #ifdef USE_STATIC_PLUGIN_ONLINEQUERIES
198 Q_IMPORT_PLUGIN(OnlineQueriesPluginInterface)
199 #endif
200
201 // Initialize static variables
202 StelApp* StelApp::singleton = Q_NULLPTR;
203 qint64 StelApp::startMSecs = 0;
204 double StelApp::animationScale = 1.;
205
initStatic()206 void StelApp::initStatic()
207 {
208 StelApp::startMSecs = QDateTime::currentMSecsSinceEpoch();
209 }
210
deinitStatic()211 void StelApp::deinitStatic()
212 {
213 StelApp::startMSecs = 0;
214 }
215
216 /*************************************************************************
217 Create and initialize the main Stellarium application.
218 *************************************************************************/
StelApp(StelMainView * parent)219 StelApp::StelApp(StelMainView *parent)
220 : QObject(parent)
221 , mainWin(parent)
222 , core(Q_NULLPTR)
223 , moduleMgr(Q_NULLPTR)
224 , localeMgr(Q_NULLPTR)
225 , skyCultureMgr(Q_NULLPTR)
226 , actionMgr(Q_NULLPTR)
227 , propMgr(Q_NULLPTR)
228 , textureMgr(Q_NULLPTR)
229 , stelObjectMgr(Q_NULLPTR)
230 , planetLocationMgr(Q_NULLPTR)
231 , networkAccessManager(Q_NULLPTR)
232 , audioMgr(Q_NULLPTR)
233 , videoMgr(Q_NULLPTR)
234 , skyImageMgr(Q_NULLPTR)
235 #ifdef ENABLE_SCRIPTING
236 , scriptAPIProxy(Q_NULLPTR)
237 , scriptMgr(Q_NULLPTR)
238 #endif
239 , stelGui(Q_NULLPTR)
240 , devicePixelsPerPixel(1.)
241 , globalScalingRatio(1.f)
242 , fps(0)
243 , frame(0)
244 , frameTimeAccum(0.)
245 , flagNightVision(false)
246 , confSettings(Q_NULLPTR)
247 , initialized(false)
248 , saveProjW(-1.)
249 , saveProjH(-1.)
250 , nbDownloadedFiles(0)
251 , totalDownloadedSize(0)
252 , nbUsedCache(0)
253 , totalUsedCacheSize(0)
254 , screenFontSize(13)
255 , renderBuffer(Q_NULLPTR)
256 , viewportEffect(Q_NULLPTR)
257 , gl(Q_NULLPTR)
258 , flagShowDecimalDegrees(false)
259 , flagUseAzimuthFromSouth(false)
260 , flagUseFormattingOutput(false)
261 , flagUseCCSDesignation(false)
262 , flagOverwriteInfoColor(false)
263 , overwriteInfoColor(Vec3f(1.f))
264 , daylightInfoColor(Vec3f(0.f))
265 #ifdef ENABLE_SPOUT
266 , spoutSender(Q_NULLPTR)
267 #endif
268 , currentFbo(0)
269 {
270 setObjectName("StelApp");
271
272 // Can't create 2 StelApp instances
273 Q_ASSERT(!singleton);
274 singleton = this;
275
276 moduleMgr = new StelModuleMgr();
277 }
278
279 /*************************************************************************
280 Deinitialize and destroy the main Stellarium application.
281 *************************************************************************/
~StelApp()282 StelApp::~StelApp()
283 {
284 qDebug() << qPrintable(QString("Downloaded %1 files (%2 kbytes) in a session of %3 sec (average of %4 kB/s + %5 files from cache (%6 kB)).").arg(nbDownloadedFiles).arg(totalDownloadedSize/1024).arg(getTotalRunTime()).arg(static_cast<double>(totalDownloadedSize/1024)/getTotalRunTime()).arg(nbUsedCache).arg(totalUsedCacheSize/1024));
285
286 stelObjectMgr->unSelect();
287 moduleMgr->unloadModule("StelVideoMgr", false); // We need to delete it afterward
288 moduleMgr->unloadModule("StelSkyLayerMgr", false); // We need to delete it afterward
289 moduleMgr->unloadModule("StelObjectMgr", false);// We need to delete it afterward
290 StelModuleMgr* tmp = moduleMgr;
291 moduleMgr = new StelModuleMgr(); // Create a secondary instance to avoid crashes at other deinit
292 delete tmp; tmp=Q_NULLPTR;
293 delete skyImageMgr; skyImageMgr=Q_NULLPTR;
294 delete core; core=Q_NULLPTR;
295 delete skyCultureMgr; skyCultureMgr=Q_NULLPTR;
296 delete localeMgr; localeMgr=Q_NULLPTR;
297 delete audioMgr; audioMgr=Q_NULLPTR;
298 delete videoMgr; videoMgr=Q_NULLPTR;
299 delete stelObjectMgr; stelObjectMgr=Q_NULLPTR; // Delete the module by hand afterward
300 delete textureMgr; textureMgr=Q_NULLPTR;
301 delete planetLocationMgr; planetLocationMgr=Q_NULLPTR;
302 delete moduleMgr; moduleMgr=Q_NULLPTR; // Delete the secondary instance
303 delete actionMgr; actionMgr = Q_NULLPTR;
304 delete propMgr; propMgr = Q_NULLPTR;
305 delete renderBuffer; renderBuffer = Q_NULLPTR;
306
307 Q_ASSERT(singleton);
308 singleton = Q_NULLPTR;
309 }
310
setupNetworkProxy()311 void StelApp::setupNetworkProxy()
312 {
313 QString proxyHost = confSettings->value("proxy/host_name").toString();
314 QString proxyPort = confSettings->value("proxy/port").toString();
315 QString proxyUser = confSettings->value("proxy/user").toString();
316 QString proxyPass = confSettings->value("proxy/password").toString();
317 QString proxyType = confSettings->value("proxy/type").toString();
318
319 bool useSocksProxy = proxyType.contains("socks", Qt::CaseInsensitive);
320
321 // If proxy settings not found in config, use environment variable
322 // if it is defined. (Config file over-rides environment).
323 if (proxyHost.isEmpty() && proxyUser.isEmpty() && proxyPass.isEmpty() && proxyPort.isEmpty())
324 {
325 char *httpProxyEnv;
326 httpProxyEnv = std::getenv("http_proxy");
327 if (!httpProxyEnv)
328 {
329 httpProxyEnv = std::getenv("HTTP_PROXY");
330 }
331 if (httpProxyEnv)
332 {
333 QString proxyString = QString(httpProxyEnv);
334 if (!proxyString.isEmpty())
335 {
336 // Handle http_proxy of the form
337 // proto://username:password@fqdn:port
338 // e.g.:
339 // http://usr:pass@proxy.loc:3128/
340 // http://proxy.loc:3128/
341 // http://2001:62a:4:203:6ab5:99ff:fef2:560b:3128/
342 // http://foo:bar@2001:62a:4:203:6ab5:99ff:fef2:560b:3128/
343 QRegularExpression pre("^([^:]+://)?(?:([^:]+):([^@]*)@)?(.+):([\\d]+)");
344 QRegularExpressionMatch preMatch=pre.match(proxyString);
345 if (proxyString.indexOf(pre) >= 0)
346 {
347 proxyUser = preMatch.captured(2);
348 proxyPass = preMatch.captured(3);
349 proxyHost = preMatch.captured(4);
350 proxyPort = preMatch.captured(5);
351 }
352 else
353 {
354 qDebug() << "indecipherable environment variable http_proxy:" << proxyString;
355 return;
356 }
357 }
358 }
359 }
360
361 if (!proxyHost.isEmpty())
362 {
363 QNetworkProxy proxy;
364 if (useSocksProxy)
365 proxy.setType(QNetworkProxy::Socks5Proxy);
366 else
367 proxy.setType(QNetworkProxy::HttpProxy);
368 proxy.setHostName(proxyHost);
369 if (!proxyPort.isEmpty())
370 proxy.setPort(proxyPort.toUShort());
371
372 if (!proxyUser.isEmpty())
373 proxy.setUser(proxyUser);
374
375 if (!proxyPass.isEmpty())
376 proxy.setPassword(proxyPass);
377
378 QString ppDisp = proxyPass;
379 ppDisp.fill('*');
380 if (useSocksProxy)
381 qDebug() << "Using SOCKS proxy:" << proxyUser << ppDisp << proxyHost << proxyPort;
382 else
383 qDebug() << "Using HTTP proxy:" << proxyUser << ppDisp << proxyHost << proxyPort;
384 QNetworkProxy::setApplicationProxy(proxy);
385 }
386 }
387
388 #ifdef ENABLE_SCRIPTING
initScriptMgr()389 void StelApp::initScriptMgr()
390 {
391 scriptMgr->addModules();
392 QString startupScript;
393 if (qApp->property("onetime_startup_script").isValid())
394 startupScript = qApp->property("onetime_startup_script").toString();
395 else
396 startupScript = confSettings->value("scripts/startup_script", "startup.ssc").toString();
397 // Use a queued slot call to start the script only once the main qApp event loop is running...
398 QMetaObject::invokeMethod(scriptMgr,
399 "runScript",
400 Qt::QueuedConnection,
401 Q_ARG(QString, startupScript));
402 }
403 #else
initScriptMgr()404 void StelApp::initScriptMgr() {}
405 #endif
406
getCommandlineArguments()407 QStringList StelApp::getCommandlineArguments()
408 {
409 return qApp->property("stelCommandLine").toStringList();
410 }
411
init(QSettings * conf)412 void StelApp::init(QSettings* conf)
413 {
414 gl = QOpenGLContext::currentContext()->functions();
415 confSettings = conf;
416
417 devicePixelsPerPixel = QOpenGLContext::currentContext()->screen()->devicePixelRatio();
418 if (devicePixelsPerPixel>1)
419 qDebug() << "Detected a high resolution device! Device pixel ratio:" << devicePixelsPerPixel;
420
421 setScreenFontSize(confSettings->value("gui/screen_font_size", 13).toInt());
422 setGuiFontSize(confSettings->value("gui/gui_font_size", 13).toInt());
423
424 core = new StelCore();
425 if (!fuzzyEquals(saveProjW, -1.) && !fuzzyEquals(saveProjH, -1.))
426 core->windowHasBeenResized(0, 0, saveProjW, saveProjH);
427
428 //Initializing locale at the begining to show all strings translated
429 localeMgr = new StelLocaleMgr();
430 localeMgr->init();
431 //SplashScreen::showMessage(q_("Initializing locales..."));
432
433 SplashScreen::showMessage(q_("Initializing textures..."));
434 // Initialize AFTER creation of openGL context
435 textureMgr = new StelTextureMgr();
436
437 SplashScreen::showMessage(q_("Initializing network access..."));
438 networkAccessManager = new QNetworkAccessManager(this);
439 networkAccessManager->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
440 SplashScreen::showMessage(q_("Initializing network disk cache..."));
441 // Activate http cache if Qt version >= 4.5
442 QNetworkDiskCache* cache = new QNetworkDiskCache(networkAccessManager);
443 //make maximum cache size configurable (in MB)
444 //the default Qt value (50 MB) is quite low, especially for DSS
445 cache->setMaximumCacheSize(confSettings->value("main/network_cache_size",300).toInt() * 1024 * 1024);
446 QString cachePath = StelFileMgr::getCacheDir();
447
448 qDebug() << "Cache directory is: " << QDir::toNativeSeparators(cachePath);
449 cache->setCacheDirectory(cachePath);
450 networkAccessManager->setCache(cache);
451 connect(networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(reportFileDownloadFinished(QNetworkReply*)));
452
453 // Proxy Initialisation
454 SplashScreen::showMessage(q_("Initializing network proxy..."));
455 setupNetworkProxy();
456
457 //create non-StelModule managers
458 propMgr = new StelPropertyMgr();
459 skyCultureMgr = new StelSkyCultureMgr();
460 propMgr->registerObject(skyCultureMgr);
461 planetLocationMgr = new StelLocationMgr();
462 actionMgr = new StelActionMgr();
463
464 // register non-modules for StelProperty tracking
465 propMgr->registerObject(this);
466 propMgr->registerObject(mainWin);
467
468 // Stel Object Data Base manager
469 SplashScreen::showMessage(q_("Initializing Object Database..."));
470 stelObjectMgr = new StelObjectMgr();
471 stelObjectMgr->init();
472 getModuleMgr().registerModule(stelObjectMgr);
473
474 // Hips surveys
475 SplashScreen::showMessage(q_("Initializing HiPS survey..."));
476 HipsMgr* hipsMgr = new HipsMgr();
477 hipsMgr->init();
478 getModuleMgr().registerModule(hipsMgr);
479
480 // Init the solar system first
481 SplashScreen::showMessage(q_("Initializing Solar System objects..."));
482 SolarSystem* ssystem = new SolarSystem();
483 ssystem->init();
484 getModuleMgr().registerModule(ssystem);
485
486 // Init the nomenclature for Solar system bodies
487 SplashScreen::showMessage(q_("Initializing planetary nomenclature..."));
488 NomenclatureMgr* nomenclature = new NomenclatureMgr();
489 nomenclature->init();
490 getModuleMgr().registerModule(nomenclature);
491
492 // Load stars & their names
493 SplashScreen::showMessage(q_("Initializing stars..."));
494 StarMgr* hip_stars = new StarMgr();
495 hip_stars->init();
496 getModuleMgr().registerModule(hip_stars);
497
498 SplashScreen::showMessage(q_("Initializing core..."));
499 core->init();
500
501 // Init nebulas
502 SplashScreen::showMessage(q_("Initializing deep-sky objects..."));
503 NebulaMgr* nebulas = new NebulaMgr();
504 nebulas->init();
505 getModuleMgr().registerModule(nebulas);
506
507 // Init milky way
508 SplashScreen::showMessage(q_("Initializing Milky Way..."));
509 MilkyWay* milky_way = new MilkyWay();
510 milky_way->init();
511 getModuleMgr().registerModule(milky_way);
512
513 // Init zodiacal light
514 SplashScreen::showMessage(q_("Initializing zodiacal light..."));
515 ZodiacalLight* zodiacal_light = new ZodiacalLight();
516 zodiacal_light->init();
517 getModuleMgr().registerModule(zodiacal_light);
518
519 // Init sky image manager
520 SplashScreen::showMessage(q_("Initializing sky image layer..."));
521 skyImageMgr = new StelSkyLayerMgr();
522 skyImageMgr->init();
523 getModuleMgr().registerModule(skyImageMgr);
524
525 // Toast surveys
526 SplashScreen::showMessage(q_("Initializing TOAST surveys..."));
527 ToastMgr* toasts = new ToastMgr();
528 toasts->init();
529 getModuleMgr().registerModule(toasts);
530
531 // Init audio manager
532 SplashScreen::showMessage(q_("Initializing audio..."));
533 audioMgr = new StelAudioMgr();
534
535 // Init video manager
536 SplashScreen::showMessage(q_("Initializing video..."));
537 videoMgr = new StelVideoMgr();
538 videoMgr->init();
539 getModuleMgr().registerModule(videoMgr);
540
541 // Constellations
542 SplashScreen::showMessage(q_("Initializing constellations..."));
543 ConstellationMgr* constellations = new ConstellationMgr(hip_stars);
544 constellations->init();
545 getModuleMgr().registerModule(constellations);
546
547 // Asterisms
548 SplashScreen::showMessage(q_("Initializing asterisms..."));
549 AsterismMgr* asterisms = new AsterismMgr(hip_stars);
550 asterisms->init();
551 getModuleMgr().registerModule(asterisms);
552
553 // Landscape, atmosphere & cardinal points section
554 SplashScreen::showMessage(q_("Initializing landscape..."));
555 LandscapeMgr* landscape = new LandscapeMgr();
556 landscape->init();
557 getModuleMgr().registerModule(landscape);
558
559 SplashScreen::showMessage(q_("Initializing grid lines..."));
560 GridLinesMgr* gridLines = new GridLinesMgr();
561 gridLines->init();
562 getModuleMgr().registerModule(gridLines);
563
564 SplashScreen::showMessage(q_("Initializing special markers..."));
565 SpecialMarkersMgr* specialMarkers = new SpecialMarkersMgr();
566 specialMarkers->init();
567 getModuleMgr().registerModule(specialMarkers);
568
569 // Sporadic Meteors
570 SplashScreen::showMessage(q_("Initializing sporadic meteors..."));
571 SporadicMeteorMgr* meteors = new SporadicMeteorMgr(10, 72);
572 meteors->init();
573 getModuleMgr().registerModule(meteors);
574
575 // User labels
576 SplashScreen::showMessage(q_("Initializing user labels..."));
577 LabelMgr* skyLabels = new LabelMgr();
578 skyLabels->init();
579 getModuleMgr().registerModule(skyLabels);
580
581 SplashScreen::showMessage(q_("Initializing sky cultures..."));
582 skyCultureMgr->init();
583
584 // User markers
585 SplashScreen::showMessage(q_("Initializing user markers..."));
586 MarkerMgr* skyMarkers = new MarkerMgr();
587 skyMarkers->init();
588 getModuleMgr().registerModule(skyMarkers);
589
590 // Init custom objects
591 SplashScreen::showMessage(q_("Initializing custom objects..."));
592 CustomObjectMgr* custObj = new CustomObjectMgr();
593 custObj->init();
594 getModuleMgr().registerModule(custObj);
595
596 // Init hightlights
597 SplashScreen::showMessage(q_("Initializing highlights..."));
598 HighlightMgr* hlMgr = new HighlightMgr();
599 hlMgr->init();
600 getModuleMgr().registerModule(hlMgr);
601
602 //Create the script manager here, maybe some modules/plugins may want to connect to it
603 //It has to be initialized later after all modules have been loaded by calling initScriptMgr
604 #ifdef ENABLE_SCRIPTING
605 SplashScreen::showMessage(q_("Initializing scripting..."));
606 scriptAPIProxy = new StelMainScriptAPIProxy(this);
607 scriptMgr = new StelScriptMgr(this);
608 #endif
609
610 SplashScreen::showMessage(q_("Initializing color scheme..."));
611 // Initialisation of the color scheme
612 emit colorSchemeChanged("color");
613 setVisionModeNight(confSettings->value("viewing/flag_night", false).toBool());
614
615 // Enable viewport effect at startup if he set
616 setViewportEffect(confSettings->value("video/viewport_effect", "none").toString());
617
618 SplashScreen::clearMessage();
619 updateI18n();
620
621 // Init actions.
622 actionMgr->addAction("actionShow_Night_Mode", N_("Display Options"), N_("Night mode"), this, "nightMode", "Ctrl+N");
623
624 setFlagShowDecimalDegrees(confSettings->value("gui/flag_show_decimal_degrees", false).toBool());
625 setFlagSouthAzimuthUsage(confSettings->value("gui/flag_use_azimuth_from_south", false).toBool());
626 setFlagUseFormattingOutput(confSettings->value("gui/flag_use_formatting_output", false).toBool());
627 setFlagUseCCSDesignation(confSettings->value("gui/flag_use_ccs_designations", false).toBool());
628 setFlagOverwriteInfoColor(confSettings->value("gui/flag_overwrite_info_color", false).toBool());
629 setOverwriteInfoColor(Vec3f(confSettings->value("color/info_text_color", "1.0,1.0,1.0").toString()));
630 setDaylightInfoColor(Vec3f(confSettings->value("color/daylight_text_color", "0.0,0.0,0.0").toString()));
631
632 // Animation
633 animationScale = confSettings->value("gui/pointer_animation_speed", 1.).toDouble();
634
635 #ifdef ENABLE_SPOUT
636 //qDebug() << "Property spout is" << qApp->property("spout").toString();
637 //qDebug() << "Property spoutName is" << qApp->property("spoutName").toString();
638 if (qApp->property("spout").toString() != "none")
639 {
640 //if we are on windows and we have GLES, we are most likely on ANGLE
641 bool isANGLE=QOpenGLContext::currentContext()->isOpenGLES();
642
643 if (isANGLE)
644 {
645 qCritical() << "SPOUT: Does not run in ANGLE/OpenGL ES mode!";
646 }
647 else
648 {
649 SplashScreen::showMessage(q_("Initializing SPOUT sender..."));
650 // Create the SpoutSender object.
651 QString spoutName = qApp->property("spoutName").toString();
652 if(spoutName.isEmpty())
653 spoutName = "stellarium";
654
655 spoutSender = new SpoutSender(spoutName);
656
657 if (!spoutSender->isValid())
658 {
659 QMessageBox::warning(&StelMainView::getInstance(), "Stellarium SPOUT", q_("Cannot create Spout sender. See log for details."), QMessageBox::Ok);
660 delete spoutSender;
661 spoutSender = Q_NULLPTR;
662 qApp->setProperty("spout", "");
663 }
664 SplashScreen::clearMessage();
665 }
666 }
667 else
668 {
669 qApp->setProperty("spout", "");
670 }
671 #endif
672
673 initialized = true;
674 }
675
676 // Load and initialize external modules (plugins)
initPlugIns()677 void StelApp::initPlugIns()
678 {
679 // Load dynamically all the modules found in the modules/ directories
680 // which are configured to be loaded at startup
681 for (const auto& i : moduleMgr->getPluginsList())
682 {
683 if (i.loadAtStartup==false)
684 continue;
685 SplashScreen::showMessage(QString("%1 \"%2\"...").arg(q_("Loading plugin"), q_(i.info.displayedName)));
686 StelModule* m = moduleMgr->loadPlugin(i.info.id);
687 if (m!=Q_NULLPTR)
688 {
689 moduleMgr->registerModule(m, true);
690 //load extensions after the module is registered
691 moduleMgr->loadExtensions(i.info.id);
692 m->init();
693 }
694 }
695 SplashScreen::clearMessage();
696 }
697
deinit()698 void StelApp::deinit()
699 {
700 #ifdef ENABLE_SPOUT
701 delete spoutSender;
702 spoutSender = Q_NULLPTR;
703 #endif
704 #ifdef ENABLE_SCRIPTING
705 if (scriptMgr->scriptIsRunning())
706 scriptMgr->stopScript();
707 #endif
708 QCoreApplication::processEvents();
709 getModuleMgr().unloadAllPlugins();
710 QCoreApplication::processEvents();
711 StelPainter::deinitGLShaders();
712 }
713
714
addProgressBar()715 StelProgressController* StelApp::addProgressBar()
716 {
717 StelProgressController* p = new StelProgressController(this);
718 progressControllers.append(p);
719 emit(progressBarAdded(p));
720 return p;
721 }
722
removeProgressBar(StelProgressController * p)723 void StelApp::removeProgressBar(StelProgressController* p)
724 {
725 progressControllers.removeOne(p);
726 emit(progressBarRemoved(p));
727 delete p;
728 }
729
730
update(double deltaTime)731 void StelApp::update(double deltaTime)
732 {
733 if (!initialized)
734 return;
735
736 ++frame;
737 frameTimeAccum+=deltaTime;
738 if (frameTimeAccum > 1.)
739 {
740 // Calc the FPS rate every seconds
741 fps=static_cast<float>(frame)/static_cast<float>(frameTimeAccum);
742 frame = 0;
743 frameTimeAccum=0.;
744 }
745
746 core->update(deltaTime);
747
748 moduleMgr->update();
749
750 // Send the event to every StelModule
751 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionUpdate))
752 {
753 i->update(deltaTime);
754 }
755
756 stelObjectMgr->update(deltaTime);
757 }
758
prepareRenderBuffer()759 void StelApp::prepareRenderBuffer()
760 {
761 if (!viewportEffect) return;
762 if (!renderBuffer)
763 {
764 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
765 int w = params.viewportXywh[2];
766 int h = params.viewportXywh[3];
767 renderBuffer = new QOpenGLFramebufferObject(w, h, QOpenGLFramebufferObject::Depth); // we only need depth here
768 }
769 renderBuffer->bind();
770 }
771
applyRenderBuffer(GLuint drawFbo)772 void StelApp::applyRenderBuffer(GLuint drawFbo)
773 {
774 if (!renderBuffer) return;
775 GL(gl->glBindFramebuffer(GL_FRAMEBUFFER, drawFbo));
776 viewportEffect->paintViewportBuffer(renderBuffer);
777 }
778
779 //! Main drawing function called at each frame
draw()780 void StelApp::draw()
781 {
782 if (!initialized)
783 return;
784
785 //find out which framebuffer is the current one
786 //this is usually NOT the "zero" FBO, but one provided by QOpenGLWidget
787 GLint drawFbo;
788 GL(gl->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &drawFbo));
789
790 prepareRenderBuffer();
791 currentFbo = renderBuffer ? renderBuffer->handle() : static_cast<GLuint>(drawFbo);
792
793 core->preDraw();
794
795 const QList<StelModule*> modules = moduleMgr->getCallOrders(StelModule::ActionDraw);
796 for (auto* module : modules)
797 {
798 module->draw(core);
799 }
800 core->postDraw();
801 #ifdef ENABLE_SPOUT
802 // At this point, the sky scene has been drawn, but no GUI panels.
803 if(spoutSender)
804 spoutSender->captureAndSendFrame(static_cast<GLuint>(drawFbo));
805 #endif
806 applyRenderBuffer(static_cast<GLuint>(drawFbo));
807 }
808
809 /*************************************************************************
810 Call this when the size of the GL window has changed
811 *************************************************************************/
glWindowHasBeenResized(const QRectF & rect)812 void StelApp::glWindowHasBeenResized(const QRectF& rect)
813 {
814 // Remove the effect before resizing the core, or things get messy.
815 QString effect = getViewportEffect();
816 setViewportEffect("none");
817 if (core)
818 {
819 core->windowHasBeenResized(rect.x(), rect.y(), rect.width(), rect.height());
820 }
821 else
822 {
823 saveProjW = rect.width();
824 saveProjH = rect.height();
825 }
826 // Force to recreate the viewport effect if any.
827 setViewportEffect(effect);
828 #ifdef ENABLE_SPOUT
829 if (spoutSender)
830 spoutSender->resize(static_cast<uint>(rect.width()),static_cast<uint>(rect.height()));
831 #endif
832 }
833
834 // Handle mouse clics
handleClick(QMouseEvent * inputEvent)835 void StelApp::handleClick(QMouseEvent* inputEvent)
836 {
837 QPointF pos = inputEvent->pos();
838 qreal x, y;
839 x = pos.x();
840 y = pos.y();
841 if (viewportEffect)
842 viewportEffect->distortXY(x, y);
843
844 QMouseEvent event(inputEvent->type(), QPoint(qRound(x*devicePixelsPerPixel), qRound(y*devicePixelsPerPixel)), inputEvent->button(), inputEvent->buttons(), inputEvent->modifiers());
845 event.setAccepted(false);
846
847 // Send the event to every StelModule
848 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionHandleMouseClicks))
849 {
850 i->handleMouseClicks(&event);
851 if (event.isAccepted())
852 {
853 inputEvent->setAccepted(true);
854 return;
855 }
856 }
857 }
858
859 // Handle mouse wheel.
handleWheel(QWheelEvent * event)860 void StelApp::handleWheel(QWheelEvent* event)
861 {
862 event->setAccepted(false);
863 QWheelEvent deltaEvent(QPoint(qRound(event->pos().x()*devicePixelsPerPixel), qRound(event->pos().y()*devicePixelsPerPixel)),
864 QPoint(qRound(event->globalPos().x()*devicePixelsPerPixel), qRound(event->globalPos().y()*devicePixelsPerPixel)),
865 event->delta(), event->buttons(), event->modifiers(), event->orientation());
866 deltaEvent.setAccepted(false);
867 // Send the event to every StelModule
868 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionHandleMouseClicks)) {
869 i->handleMouseWheel(&deltaEvent);
870 if (deltaEvent.isAccepted()) {
871 event->accept();
872 break;
873 }
874 }
875 }
876
877 // Handle mouse move
handleMove(qreal x,qreal y,Qt::MouseButtons b)878 bool StelApp::handleMove(qreal x, qreal y, Qt::MouseButtons b)
879 {
880 if (viewportEffect)
881 viewportEffect->distortXY(x, y);
882 // Send the event to every StelModule
883 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionHandleMouseMoves))
884 {
885 if (i->handleMouseMoves(qRound(x*devicePixelsPerPixel), qRound(y*devicePixelsPerPixel), b))
886 return true;
887 }
888 return false;
889 }
890
891 // Handle key press and release
handleKeys(QKeyEvent * event)892 void StelApp::handleKeys(QKeyEvent* event)
893 {
894 event->setAccepted(false);
895 // First try to trigger a shortcut.
896 if (event->type() == QEvent::KeyPress)
897 {
898 if (getStelActionManager()->pushKey(event->key() + event->modifiers()))
899 {
900 event->setAccepted(true);
901 return;
902 }
903 }
904 // Send the event to every StelModule
905 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionHandleKeys))
906 {
907 i->handleKeys(event);
908 if (event->isAccepted())
909 return;
910 }
911 }
912
913 // Handle pinch on multi touch devices
handlePinch(qreal scale,bool started)914 void StelApp::handlePinch(qreal scale, bool started)
915 {
916 // Send the event to every StelModule
917 for (auto* i : moduleMgr->getCallOrders(StelModule::ActionHandleMouseMoves))
918 {
919 if (i->handlePinch(scale, started))
920 return;
921 }
922 }
923
924 //! Set flag for activating night vision mode
setVisionModeNight(bool b)925 void StelApp::setVisionModeNight(bool b)
926 {
927 if (flagNightVision!=b)
928 {
929 flagNightVision=b;
930 emit(visionNightModeChanged(b));
931 }
932 }
933
setFlagOverwriteInfoColor(bool b)934 void StelApp::setFlagOverwriteInfoColor(bool b)
935 {
936 if (flagOverwriteInfoColor!=b)
937 {
938 flagOverwriteInfoColor=b;
939 emit(flagOverwriteInfoColorChanged(b));
940 }
941 }
942
setFlagShowDecimalDegrees(bool b)943 void StelApp::setFlagShowDecimalDegrees(bool b)
944 {
945 if (flagShowDecimalDegrees!=b)
946 {
947 flagShowDecimalDegrees = b;
948 emit flagShowDecimalDegreesChanged(b);
949 }
950 }
951
setFlagUseFormattingOutput(bool b)952 void StelApp::setFlagUseFormattingOutput(bool b)
953 {
954 if (flagUseFormattingOutput!=b)
955 {
956 flagUseFormattingOutput = b;
957 emit flagUseFormattingOutputChanged(b);
958 }
959 }
960
setFlagUseCCSDesignation(bool b)961 void StelApp::setFlagUseCCSDesignation(bool b)
962 {
963 if (flagUseCCSDesignation!=b)
964 {
965 flagUseCCSDesignation = b;
966 emit flagUseCCSDesignationChanged(b);
967 }
968 }
969
setOverwriteInfoColor(const Vec3f & color)970 void StelApp::setOverwriteInfoColor(const Vec3f& color)
971 {
972 if (color != overwriteInfoColor)
973 {
974 overwriteInfoColor = color;
975 emit overwriteInfoColorChanged(color);
976 }
977 }
978
getOverwriteInfoColor() const979 Vec3f StelApp::getOverwriteInfoColor() const
980 {
981 return overwriteInfoColor;
982 }
983
setDaylightInfoColor(const Vec3f & color)984 void StelApp::setDaylightInfoColor(const Vec3f& color)
985 {
986 if (color != daylightInfoColor)
987 {
988 daylightInfoColor = color;
989 emit daylightInfoColorChanged(color);
990 }
991 }
992
getDaylightInfoColor() const993 Vec3f StelApp::getDaylightInfoColor() const
994 {
995 return daylightInfoColor;
996 }
997
998 // Update translations and font for sky everywhere in the program
updateI18n()999 void StelApp::updateI18n()
1000 {
1001 #ifdef ENABLE_NLS
1002 emit(languageChanged());
1003 #endif
1004 }
1005
ensureGLContextCurrent()1006 void StelApp::ensureGLContextCurrent()
1007 {
1008 mainWin->glContextMakeCurrent();
1009 }
1010
1011 // Return the time since when stellarium is running in second.
getTotalRunTime()1012 double StelApp::getTotalRunTime()
1013 {
1014 return static_cast<double>(QDateTime::currentMSecsSinceEpoch() - StelApp::startMSecs)/1000.;
1015 }
1016
1017 // Return the scaled time since when stellarium is running in second.
getAnimationTime()1018 double StelApp::getAnimationTime()
1019 {
1020 return static_cast<double>(QDateTime::currentMSecsSinceEpoch() - StelApp::startMSecs)*StelApp::animationScale/1000.;
1021 }
1022
reportFileDownloadFinished(QNetworkReply * reply)1023 void StelApp::reportFileDownloadFinished(QNetworkReply* reply)
1024 {
1025 bool fromCache = reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
1026 if (fromCache)
1027 {
1028 ++nbUsedCache;
1029 totalUsedCacheSize+=reply->bytesAvailable();
1030 }
1031 else
1032 {
1033 ++nbDownloadedFiles;
1034 totalDownloadedSize+=reply->bytesAvailable();
1035 }
1036 }
1037
quit()1038 void StelApp::quit()
1039 {
1040 emit aboutToQuit();
1041 // Let's allow exit from Stellarium via startup script!
1042 QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
1043 }
1044
setDevicePixelsPerPixel(qreal dppp)1045 void StelApp::setDevicePixelsPerPixel(qreal dppp)
1046 {
1047 // Check that the device-independent pixel size didn't change
1048 if (!viewportEffect && !fuzzyEquals(devicePixelsPerPixel, dppp))
1049 {
1050 devicePixelsPerPixel = dppp;
1051 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1052 params.devicePixelsPerPixel = devicePixelsPerPixel;
1053 core->setCurrentStelProjectorParams(params);
1054 }
1055 }
1056
setViewportEffect(const QString & name)1057 void StelApp::setViewportEffect(const QString& name)
1058 {
1059 if (name == getViewportEffect()) return;
1060 if (renderBuffer)
1061 {
1062 ensureGLContextCurrent();
1063 delete renderBuffer;
1064 renderBuffer = Q_NULLPTR;
1065 }
1066 if (viewportEffect)
1067 {
1068 delete viewportEffect;
1069 viewportEffect = Q_NULLPTR;
1070 }
1071 if (name == "none") return;
1072
1073 if (!core)
1074 {
1075 qDebug() << "No core to set viewport effect";
1076 return;
1077 }
1078 StelProjector::StelProjectorParams params = core->getCurrentStelProjectorParams();
1079 int w = params.viewportXywh[2];
1080 int h = params.viewportXywh[3];
1081 if (name == "sphericMirrorDistorter")
1082 {
1083 viewportEffect = new StelViewportDistorterFisheyeToSphericMirror(w, h);
1084 }
1085 else
1086 {
1087 qDebug() << "unknown viewport effect name:" << name;
1088 Q_ASSERT(false);
1089 }
1090 }
1091
getViewportEffect() const1092 QString StelApp::getViewportEffect() const
1093 {
1094 if (viewportEffect)
1095 return viewportEffect->getName();
1096 return "none";
1097 }
1098
1099 // Diagnostics
dumpModuleActionPriorities(StelModule::StelModuleActionName actionName) const1100 void StelApp::dumpModuleActionPriorities(StelModule::StelModuleActionName actionName) const
1101 {
1102 const QList<StelModule*> modules = moduleMgr->getCallOrders(actionName);
1103 QMetaEnum me = QMetaEnum::fromType<StelModule::StelModuleActionName>();
1104 qDebug() << "Module Priorities for action named" << me.valueToKey(actionName);
1105
1106 for (auto* module : modules)
1107 {
1108 module->draw(core);
1109 qDebug() << " -- " << module->getCallOrder(actionName) << "Module: " << module->objectName();
1110 }
1111 }
1112
getModule(const QString & moduleID) const1113 StelModule* StelApp::getModule(const QString& moduleID) const
1114 {
1115 return getModuleMgr().getModule(moduleID);
1116 }
setScreenFontSize(int s)1117 void StelApp::setScreenFontSize(int s)
1118 {
1119 if (screenFontSize!=s)
1120 {
1121 screenFontSize=s;
1122 emit screenFontSizeChanged(s);
1123 }
1124 }
setGuiFontSize(int s)1125 void StelApp::setGuiFontSize(int s)
1126 {
1127 if (getGuiFontSize()!=s)
1128 {
1129 QFont font=QGuiApplication::font();
1130 font.setPixelSize(s);
1131 QGuiApplication::setFont(font);
1132 emit guiFontSizeChanged(s);
1133 }
1134 }
getGuiFontSize() const1135 int StelApp::getGuiFontSize() const
1136 {
1137 return QGuiApplication::font().pixelSize();
1138 }
1139
setAppFont(QFont font)1140 void StelApp::setAppFont(QFont font)
1141 {
1142 int oldSize=QGuiApplication::font().pixelSize();
1143 font.setPixelSize(oldSize);
1144 font.setStyleHint(QFont::AnyStyle, QFont::OpenGLCompatible);
1145 QGuiApplication::setFont(font);
1146 emit fontChanged(font);
1147 }
1148
getVersion() const1149 QString StelApp::getVersion() const
1150 {
1151 QStringList ver = StelUtils::getApplicationVersion().split(".");
1152 return QString("%1.%2.%3").arg(ver[0]).arg(ver[1]).arg(ver[2]);
1153 }
1154