1 /*
2 SPDX-FileCopyrightText: 2002 Thomas Kabelmann <tk78@gmx.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 //KStars DBUS functions
8
9 #include "kstars.h"
10
11 #include "colorscheme.h"
12 #include "eyepiecefield.h"
13 #include "imageexporter.h"
14 #include "ksdssdownloader.h"
15 #include "kstarsdata.h"
16 #include "observinglist.h"
17 #include "Options.h"
18 #include "skymap.h"
19 #include "skycomponents/constellationboundarylines.h"
20 #include "skycomponents/skymapcomposite.h"
21 #include "skyobjects/catalogobject.h"
22 #include "catalogsdb.h"
23 #include "skyobjects/ksplanetbase.h"
24 #include "skyobjects/starobject.h"
25 #include "tools/whatsinteresting/wiview.h"
26 #include "dialogs/finddialog.h"
27 #include "tools/nameresolver.h"
28
29 #ifdef HAVE_CFITSIO
30 #include "fitsviewer/fitsviewer.h"
31 #ifdef HAVE_INDI
32 #include "ekos/manager.h"
33 #endif
34 #endif
35
36 #include <KActionCollection>
37
38 #include <QPrintDialog>
39 #include <QPrinter>
40 #include <QElapsedTimer>
41
42 #include "kstars_debug.h"
43
setRaDec(double ra,double dec)44 void KStars::setRaDec(double ra, double dec)
45 {
46 SkyPoint p(ra, dec);
47 map()->setClickedPoint(&p);
48 map()->slotCenter();
49 }
50
setRaDecJ2000(double ra0,double dec0)51 void KStars::setRaDecJ2000(double ra0, double dec0)
52 {
53 SkyPoint p;
54 p.setRA0(ra0);
55 p.setDec0(dec0);
56 p.updateCoordsNow(data()->updateNum());
57 map()->setClickedPoint(&p);
58 map()->slotCenter();
59 }
60
setAltAz(double alt,double az,bool altIsRefracted)61 void KStars::setAltAz(double alt, double az, bool altIsRefracted)
62 {
63 SkyPoint p;
64 if (altIsRefracted)
65 {
66 alt = SkyPoint::unrefract(alt);
67 }
68 p.setAlt(alt);
69 p.setAz(az);
70 p.HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
71 map()->setClickedPoint(&p);
72 map()->slotCenter();
73 }
74
lookTowards(const QString & direction)75 void KStars::lookTowards(const QString &direction)
76 {
77 QString dir = direction.toLower();
78 if (dir == i18n("zenith") || dir == "z")
79 {
80 actionCollection()->action("zenith")->trigger();
81 }
82 else if (dir == i18n("north") || dir == "n")
83 {
84 actionCollection()->action("north")->trigger();
85 }
86 else if (dir == i18n("east") || dir == "e")
87 {
88 actionCollection()->action("east")->trigger();
89 }
90 else if (dir == i18n("south") || dir == "s")
91 {
92 actionCollection()->action("south")->trigger();
93 }
94 else if (dir == i18n("west") || dir == "w")
95 {
96 actionCollection()->action("west")->trigger();
97 }
98 else if (dir == i18n("northeast") || dir == "ne")
99 {
100 map()->stopTracking();
101 map()->clickedPoint()->setAlt(15.0);
102 map()->clickedPoint()->setAz(45.0);
103 map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
104 map()->slotCenter();
105 }
106 else if (dir == i18n("southeast") || dir == "se")
107 {
108 map()->stopTracking();
109 map()->clickedPoint()->setAlt(15.0);
110 map()->clickedPoint()->setAz(135.0);
111 map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
112 map()->slotCenter();
113 }
114 else if (dir == i18n("southwest") || dir == "sw")
115 {
116 map()->stopTracking();
117 map()->clickedPoint()->setAlt(15.0);
118 map()->clickedPoint()->setAz(225.0);
119 map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
120 map()->slotCenter();
121 }
122 else if (dir == i18n("northwest") || dir == "nw")
123 {
124 map()->stopTracking();
125 map()->clickedPoint()->setAlt(15.0);
126 map()->clickedPoint()->setAz(315.0);
127 map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
128 map()->slotCenter();
129 }
130 else
131 {
132 SkyObject *target = data()->objectNamed(direction);
133 if (target != nullptr)
134 {
135 map()->setClickedObject(target);
136 map()->setClickedPoint(target);
137 map()->slotCenter();
138 }
139 }
140 }
141
addLabel(const QString & name)142 void KStars::addLabel(const QString &name)
143 {
144 SkyObject *target = data()->objectNamed(name);
145 if (target != nullptr)
146 {
147 data()->skyComposite()->addNameLabel(target);
148 map()->forceUpdate();
149 }
150 }
151
removeLabel(const QString & name)152 void KStars::removeLabel(const QString &name)
153 {
154 SkyObject *target = data()->objectNamed(name);
155 if (target != nullptr)
156 {
157 data()->skyComposite()->removeNameLabel(target);
158 map()->forceUpdate();
159 }
160 }
161
addTrail(const QString & name)162 void KStars::addTrail(const QString &name)
163 {
164 TrailObject *target = dynamic_cast<TrailObject *>(data()->objectNamed(name));
165 if (target)
166 {
167 target->addToTrail();
168 map()->forceUpdate();
169 }
170 }
171
removeTrail(const QString & name)172 void KStars::removeTrail(const QString &name)
173 {
174 TrailObject *target = dynamic_cast<TrailObject *>(data()->objectNamed(name));
175 if (target)
176 {
177 target->clearTrail();
178 map()->forceUpdate();
179 }
180 }
181
zoom(double z)182 void KStars::zoom(double z)
183 {
184 map()->setZoomFactor(z);
185 }
186
zoomIn()187 void KStars::zoomIn()
188 {
189 map()->slotZoomIn();
190 }
191
zoomOut()192 void KStars::zoomOut()
193 {
194 map()->slotZoomOut();
195 }
196
defaultZoom()197 void KStars::defaultZoom()
198 {
199 map()->slotZoomDefault();
200 }
201
setLocalTime(int yr,int mth,int day,int hr,int min,int sec)202 void KStars::setLocalTime(int yr, int mth, int day, int hr, int min, int sec)
203 {
204 data()->changeDateTime(data()->geo()->LTtoUT(KStarsDateTime(QDate(yr, mth, day), QTime(hr, min, sec))));
205 }
206
setTimeToNow()207 void KStars::setTimeToNow()
208 {
209 slotSetTimeToNow();
210 }
211
waitFor(double sec)212 void KStars::waitFor(double sec)
213 {
214 QElapsedTimer tm;
215 tm.start();
216 while (tm.elapsed() < int(1000. * sec))
217 {
218 qApp->processEvents();
219 }
220 }
221
waitForKey(const QString & k)222 void KStars::waitForKey(const QString &k)
223 {
224 data()->resumeKey = QKeySequence::fromString(k);
225 if (!data()->resumeKey.isEmpty())
226 {
227 //When the resumeKey is pressed, resumeKey is set to empty
228 while (!data()->resumeKey.isEmpty())
229 qApp->processEvents();
230 }
231 else
232 {
233 qDebug() << "Error [D-Bus waitForKey()]: Invalid key requested.";
234 }
235 }
236
setTracking(bool track)237 void KStars::setTracking(bool track)
238 {
239 if (track != Options::isTracking())
240 slotTrack();
241 }
242
popupMessage(int,int,const QString &)243 void KStars::popupMessage(int /*x*/, int /*y*/, const QString & /*message*/)
244 {
245 //Show a small popup window at (x,y) with a text message
246 }
247
drawLine(int,int,int,int,int)248 void KStars::drawLine(int /*x1*/, int /*y1*/, int /*x2*/, int /*y2*/, int /*speed*/)
249 {
250 //Draw a line on the skymap display
251 }
252
location()253 QString KStars::location()
254 {
255 GeoLocation *currentLocation = data()->geo();
256
257 QJsonObject locationInfo =
258 {
259 {"name", currentLocation->name()},
260 {"province", currentLocation->province()},
261 {"country", currentLocation->country()},
262 {"longitude", currentLocation->lng()->Degrees()},
263 {"latitude", currentLocation->lat()->Degrees()},
264 {"tz0", currentLocation->TZ0()},
265 {"tz", currentLocation->TZ()}
266 };
267
268 return QJsonDocument(locationInfo).toJson(QJsonDocument::Compact);
269 }
270
setGeoLocation(const QString & city,const QString & province,const QString & country)271 bool KStars::setGeoLocation(const QString &city, const QString &province, const QString &country)
272 {
273 //Set the geographic location
274 bool cityFound(false);
275
276 foreach (GeoLocation *loc, data()->geoList)
277 {
278 if (loc->translatedName() == city && (province.isEmpty() || loc->translatedProvince() == province) &&
279 loc->translatedCountry() == country)
280 {
281 cityFound = true;
282
283 data()->setLocation(*loc);
284
285 //configure time zone rule
286 KStarsDateTime ltime = loc->UTtoLT(data()->ut());
287 loc->tzrule()->reset_with_ltime(ltime, loc->TZ0(), data()->isTimeRunningForward());
288 data()->setNextDSTChange(loc->tzrule()->nextDSTChange());
289
290 //reset LST
291 data()->syncLST();
292
293 //make sure planets, etc. are updated immediately
294 data()->setFullTimeUpdate();
295
296 // If the sky is in Horizontal mode and not tracking, reset focus such that
297 // Alt/Az remain constant.
298 if (!Options::isTracking() && Options::useAltAz())
299 {
300 map()->focus()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
301 }
302
303 // recalculate new times and objects
304 data()->setSnapNextFocus();
305 updateTime();
306
307 //no need to keep looking, we're done.
308 break;
309 }
310 }
311
312 if (!cityFound)
313 {
314 if (province.isEmpty())
315 qDebug()
316 << QString("Error [D-Bus setGeoLocation]: city %1, %2 not found in database.").arg(city, country);
317 else
318 qDebug() << QString("Error [D-Bus setGeoLocation]: city %1, %2, %3 not found in database.")
319 .arg(city, province, country);
320 }
321
322 return cityFound;
323 }
324
setGPSLocation(double longitude,double latitude,double elevation,double tz0)325 bool KStars::setGPSLocation(double longitude, double latitude, double elevation, double tz0)
326 {
327 GeoLocation *geo = data()->geo();
328 std::unique_ptr<GeoLocation> tempGeo;
329
330 QString newLocationName("GPS Location");
331
332 dms lng(longitude), lat(latitude);
333
334 GeoLocation *nearest = data()->nearestLocation(longitude, latitude);
335
336 if (nearest)
337 tempGeo.reset(new GeoLocation(lng, lat, newLocationName, "", "", nearest->TZ0(), nearest->tzrule(), elevation));
338 else
339 tempGeo.reset(new GeoLocation(lng, lat, newLocationName, "", "", tz0, new TimeZoneRule(), elevation));
340
341 geo = tempGeo.get();
342
343 qCInfo(KSTARS) << "Setting location from DBus. Longitude:" << longitude << "Latitude:" << latitude;
344
345 data()->setLocation(*geo);
346
347 return true;
348 }
349
readConfig()350 void KStars::readConfig()
351 {
352 //Load config file values into Options object
353 Options::self()->load();
354
355 applyConfig();
356
357 //Reset date, if one was stored
358 if (data()->StoredDate.isValid())
359 {
360 data()->changeDateTime(data()->geo()->LTtoUT(data()->StoredDate));
361 data()->StoredDate = KStarsDateTime(QDateTime()); //invalidate StoredDate
362 }
363
364 map()->forceUpdate();
365 }
366
writeConfig()367 void KStars::writeConfig()
368 {
369 Options::self()->save();
370
371 //Store current simulation time
372 data()->StoredDate = data()->lt();
373 }
374
getOption(const QString & name)375 QString KStars::getOption(const QString &name)
376 {
377 //Some config items are not stored in the Options object while
378 //the program is running; catch these here and returntheir current value.
379 if (name == "FocusRA")
380 {
381 return QString::number(map()->focus()->ra().Hours(), 'f', 6);
382 }
383 if (name == "FocusDec")
384 {
385 return QString::number(map()->focus()->dec().Degrees(), 'f', 6);
386 }
387
388 KConfigSkeletonItem *it = Options::self()->findItem(name);
389 if (it)
390 return it->property().toString();
391 else
392 return QString();
393 }
394
changeViewOption(const QString & op,const QString & val)395 void KStars::changeViewOption(const QString &op, const QString &val)
396 {
397 bool bOk(false), dOk(false);
398
399 //parse bool value
400 bool bVal(false);
401 if (val.toLower() == "true")
402 {
403 bOk = true;
404 bVal = true;
405 }
406 if (val.toLower() == "false")
407 {
408 bOk = true;
409 bVal = false;
410 }
411 if (val == "1")
412 {
413 bOk = true;
414 bVal = true;
415 }
416 if (val == "0")
417 {
418 bOk = true;
419 bVal = false;
420 }
421
422 //parse double value
423 double dVal = val.toDouble(&dOk);
424
425 //[GUI]
426 if (op == "ShowInfoBoxes" && bOk)
427 Options::setShowInfoBoxes(bVal);
428 if (op == "ShowTimeBox" && bOk)
429 Options::setShowTimeBox(bVal);
430 if (op == "ShowGeoBox" && bOk)
431 Options::setShowGeoBox(bVal);
432 if (op == "ShowFocusBox" && bOk)
433 Options::setShowFocusBox(bVal);
434 if (op == "ShadeTimeBox" && bOk)
435 Options::setShadeTimeBox(bVal);
436 if (op == "ShadeGeoBox" && bOk)
437 Options::setShadeGeoBox(bVal);
438 if (op == "ShadeFocusBox" && bOk)
439 Options::setShadeFocusBox(bVal);
440
441 //[View]
442 // FIXME: REGRESSION
443 // if ( op == "FOVName" ) Options::setFOVName( val );
444 // if ( op == "FOVSizeX" && dOk ) Options::setFOVSizeX( (float)dVal );
445 // if ( op == "FOVSizeY" && dOk ) Options::setFOVSizeY( (float)dVal );
446 // if ( op == "FOVShape" && nOk ) Options::setFOVShape( nVal );
447 // if ( op == "FOVColor" ) Options::setFOVColor( val );
448 if (op == "ShowStars" && bOk)
449 Options::setShowStars(bVal);
450 if (op == "ShowCLines" && bOk)
451 Options::setShowCLines(bVal);
452 if (op == "ShowCBounds" && bOk)
453 Options::setShowCBounds(bVal);
454 if (op == "ShowCNames" && bOk)
455 Options::setShowCNames(bVal);
456 if (op == "ShowMilkyWay" && bOk)
457 Options::setShowMilkyWay(bVal);
458 if (op == "AutoSelectGrid" && bOk)
459 Options::setAutoSelectGrid(bVal);
460 if (op == "ShowEquatorialGrid" && bOk)
461 Options::setShowEquatorialGrid(bVal);
462 if (op == "ShowHorizontalGrid" && bOk)
463 Options::setShowHorizontalGrid(bVal);
464 if (op == "ShowEquator" && bOk)
465 Options::setShowEquator(bVal);
466 if (op == "ShowEcliptic" && bOk)
467 Options::setShowEcliptic(bVal);
468 if (op == "ShowHorizon" && bOk)
469 Options::setShowHorizon(bVal);
470 if (op == "ShowGround" && bOk)
471 Options::setShowGround(bVal);
472 if (op == "ShowSun" && bOk)
473 Options::setShowSun(bVal);
474 if (op == "ShowMoon" && bOk)
475 Options::setShowMoon(bVal);
476 if (op == "ShowMercury" && bOk)
477 Options::setShowMercury(bVal);
478 if (op == "ShowVenus" && bOk)
479 Options::setShowVenus(bVal);
480 if (op == "ShowMars" && bOk)
481 Options::setShowMars(bVal);
482 if (op == "ShowJupiter" && bOk)
483 Options::setShowJupiter(bVal);
484 if (op == "ShowSaturn" && bOk)
485 Options::setShowSaturn(bVal);
486 if (op == "ShowUranus" && bOk)
487 Options::setShowUranus(bVal);
488 if (op == "ShowNeptune" && bOk)
489 Options::setShowNeptune(bVal);
490 //if ( op == "ShowPluto" && bOk ) Options::setShowPluto( bVal );
491 if (op == "ShowAsteroids" && bOk)
492 Options::setShowAsteroids(bVal);
493 if (op == "ShowComets" && bOk)
494 Options::setShowComets(bVal);
495 if (op == "ShowSolarSystem" && bOk)
496 Options::setShowSolarSystem(bVal);
497 if (op == "ShowDeepSky" && bOk)
498 Options::setShowDeepSky(bVal);
499 if (op == "ShowSupernovae" && bOk)
500 Options::setShowSupernovae(bVal);
501 if (op == "ShowStarNames" && bOk)
502 Options::setShowStarNames(bVal);
503 if (op == "ShowStarMagnitudes" && bOk)
504 Options::setShowStarMagnitudes(bVal);
505 if (op == "ShowAsteroidNames" && bOk)
506 Options::setShowAsteroidNames(bVal);
507 if (op == "ShowCometNames" && bOk)
508 Options::setShowCometNames(bVal);
509 if (op == "ShowPlanetNames" && bOk)
510 Options::setShowPlanetNames(bVal);
511 if (op == "ShowPlanetImages" && bOk)
512 Options::setShowPlanetImages(bVal);
513 if (op == "HideOnSlew" && bOk)
514 Options::setHideOnSlew(bVal);
515 if (op == "HideStars" && bOk)
516 Options::setHideStars(bVal);
517 if (op == "HidePlanets" && bOk)
518 Options::setHidePlanets(bVal);
519 if (op == "HideMilkyWay" && bOk)
520 Options::setHideMilkyWay(bVal);
521 if (op == "HideCNames" && bOk)
522 Options::setHideCNames(bVal);
523 if (op == "HideCLines" && bOk)
524 Options::setHideCLines(bVal);
525 if (op == "HideCBounds" && bOk)
526 Options::setHideCBounds(bVal);
527 if (op == "HideGrids" && bOk)
528 Options::setHideGrids(bVal);
529 if (op == "HideLabels" && bOk)
530 Options::setHideLabels(bVal);
531
532 if (op == "UseAltAz" && bOk)
533 Options::setUseAltAz(bVal);
534 if (op == "UseRefraction" && bOk)
535 Options::setUseRefraction(bVal);
536 if (op == "UseAutoLabel" && bOk)
537 Options::setUseAutoLabel(bVal);
538 if (op == "UseHoverLabel" && bOk)
539 Options::setUseHoverLabel(bVal);
540 if (op == "UseAutoTrail" && bOk)
541 Options::setUseAutoTrail(bVal);
542 if (op == "UseAnimatedSlewing" && bOk)
543 Options::setUseAnimatedSlewing(bVal);
544 if (op == "FadePlanetTrails" && bOk)
545 Options::setFadePlanetTrails(bVal);
546 if (op == "SlewTimeScale" && dOk)
547 Options::setSlewTimeScale(dVal);
548 if (op == "ZoomFactor" && dOk)
549 Options::setZoomFactor(dVal);
550 // if ( op == "MagLimitDrawStar" && dOk ) Options::setMagLimitDrawStar( dVal );
551 if (op == "MagLimitDrawDeepSky" && dOk)
552 Options::setMagLimitDrawDeepSky(dVal);
553 if (op == "StarDensity" && dOk)
554 Options::setStarDensity(dVal);
555 // if ( op == "MagLimitDrawStarZoomOut" && dOk ) Options::setMagLimitDrawStarZoomOut( dVal );
556 if (op == "MagLimitDrawDeepSkyZoomOut" && dOk)
557 Options::setMagLimitDrawDeepSkyZoomOut(dVal);
558 if (op == "StarLabelDensity" && dOk)
559 Options::setStarLabelDensity(dVal);
560 if (op == "MagLimitHideStar" && dOk)
561 Options::setMagLimitHideStar(dVal);
562 if (op == "MagLimitAsteroid" && dOk)
563 Options::setMagLimitAsteroid(dVal);
564 if (op == "AsteroidLabelDensity" && dOk)
565 Options::setAsteroidLabelDensity(dVal);
566 if (op == "MaxRadCometName" && dOk)
567 Options::setMaxRadCometName(dVal);
568
569 //these three are a "radio group"
570 if (op == "UseLatinConstellationNames" && bOk)
571 {
572 Options::setUseLatinConstellNames(true);
573 Options::setUseLocalConstellNames(false);
574 Options::setUseAbbrevConstellNames(false);
575 }
576 if (op == "UseLocalConstellationNames" && bOk)
577 {
578 Options::setUseLatinConstellNames(false);
579 Options::setUseLocalConstellNames(true);
580 Options::setUseAbbrevConstellNames(false);
581 }
582 if (op == "UseAbbrevConstellationNames" && bOk)
583 {
584 Options::setUseLatinConstellNames(false);
585 Options::setUseLocalConstellNames(false);
586 Options::setUseAbbrevConstellNames(true);
587 }
588
589 map()->forceUpdate();
590 }
591
setColor(const QString & name,const QString & value)592 void KStars::setColor(const QString &name, const QString &value)
593 {
594 ColorScheme *cs = data()->colorScheme();
595 if (cs->hasColorNamed(name))
596 {
597 cs->setColor(name, value);
598 map()->forceUpdate();
599 }
600 }
601
colorScheme() const602 QString KStars::colorScheme() const
603 {
604 return data()->colorScheme()->fileName();
605 }
606
loadColorScheme(const QString & name)607 void KStars::loadColorScheme(const QString &name)
608 {
609 data()->colorScheme()->load(name);
610
611 #if 0
612 if (ok)
613 {
614 //set the application colors for the Night Vision scheme
615 if (Options::darkAppColors())
616 {
617 //OriginalPalette = QApplication::palette();
618 QApplication::setPalette(DarkPalette);
619 if (KStars::Instance()->wiView())
620 KStars::Instance()->wiView()->setNightVisionOn(true);
621 //Note: This uses style sheets to set the dark colors, this is cross platform. Palettes have a different behavior on OS X and Windows as opposed to Linux.
622 //It might be a good idea to use stylesheets in the future instead of palettes but this will work for now for OS X.
623 //This is also in KStars.cpp. If you change it, change it in BOTH places.
624 #ifdef Q_OS_OSX
625 qDebug() << "setting dark stylesheet";
626 qApp->setStyleSheet(
627 "QWidget { background-color: black; color:red; "
628 "selection-background-color:rgb(30,30,30);selection-color:white}"
629 "QToolBar { border:none }"
630 "QTabBar::tab:selected { background-color:rgb(50,50,50) }"
631 "QTabBar::tab:!selected { background-color:rgb(30,30,30) }"
632 "QPushButton { background-color:rgb(50,50,50);border-width:1px; border-style:solid;border-color:black}"
633 "QPushButton::disabled { background-color:rgb(10,10,10);border-width:1px; "
634 "border-style:solid;border-color:black }"
635 "QToolButton:Checked { background-color:rgb(30,30,30); border:none }"
636 "QComboBox { background-color:rgb(30,30,30); }"
637 "QComboBox::disabled { background-color:rgb(10,10,10) }"
638 "QScrollBar::handle { background: rgb(30,30,30) }"
639 "QSpinBox { border-width: 1px; border-style:solid; border-color:rgb(30,30,30) }"
640 "QDoubleSpinBox { border-width:1px; border-style:solid; border-color:rgb(30,30,30) }"
641 "QLineEdit { border-width: 1px; border-style: solid; border-color:rgb(30,30,30) }"
642 "QCheckBox::indicator:unchecked { background-color:rgb(30,30,30);border-width:1px; "
643 "border-style:solid;border-color:black }"
644 "QCheckBox::indicator:checked { background-color:red;border-width:1px; "
645 "border-style:solid;border-color:black }"
646 "QRadioButton::indicator:unchecked { background-color:rgb(30,30,30) }"
647 "QRadioButton::indicator:checked { background-color:red }"
648 "QRoundProgressBar { alternate-background-color:black }"
649 "QDateTimeEdit {background-color:rgb(30,30,30); border-width: 1px; border-style:solid; "
650 "border-color:rgb(30,30,30) }"
651 "QHeaderView { color:red;background-color:black }"
652 "QHeaderView::Section { background-color:rgb(30,30,30) }"
653 "QTableCornerButton::section{ background-color:rgb(30,30,30) }"
654 "");
655 qDebug() << "stylesheet set";
656 #endif
657 }
658 else
659 {
660 if (KStars::Instance()->wiView())
661 KStars::Instance()->wiView()->setNightVisionOn(false);
662 QApplication::setPalette(OriginalPalette);
663 #ifdef Q_OS_OSX
664 qDebug() << "setting light stylesheet";
665 qApp->setStyleSheet("");
666 qDebug() << "stylesheet set";
667 #endif
668 }
669 }
670 #endif
671
672 Options::setColorSchemeFile(name);
673
674 emit colorSchemeChanged();
675
676 map()->forceUpdate();
677 }
678
exportImage(const QString & url,int w,int h,bool includeLegend)679 void KStars::exportImage(const QString &url, int w, int h, bool includeLegend)
680 {
681 ImageExporter *m_ImageExporter = m_KStarsData->imageExporter();
682
683 if (w <= 0)
684 w = map()->width();
685 if (h <= 0)
686 h = map()->height();
687
688 QSize size(w, h);
689
690 m_ImageExporter->includeLegend(includeLegend);
691 m_ImageExporter->setRasterOutputSize(&size);
692 m_ImageExporter->exportImage(url);
693 }
694
getDSSURL(const QString & objectName)695 QString KStars::getDSSURL(const QString &objectName)
696 {
697 SkyObject *target = data()->objectNamed(objectName);
698 if (!target)
699 {
700 return QString("ERROR");
701 }
702 else
703 {
704 return KSDssDownloader::getDSSURL(target);
705 }
706 }
707
getDSSURL(double RA_J2000,double Dec_J2000,float width,float height)708 QString KStars::getDSSURL(double RA_J2000, double Dec_J2000, float width, float height)
709 {
710 dms ra(RA_J2000), dec(Dec_J2000);
711 return KSDssDownloader::getDSSURL(ra, dec, width, height);
712 }
713
getObjectDataXML(const QString & objectName,bool fallbackToInternet,bool storeInternetResolved)714 QString KStars::getObjectDataXML(const QString &objectName, bool fallbackToInternet, bool storeInternetResolved)
715 {
716 bool deleteTargetAfterUse = false;
717 const SkyObject *target = data()->objectNamed(objectName);
718 if (!target && fallbackToInternet)
719 {
720 if (!storeInternetResolved)
721 {
722 const auto &cedata = NameResolver::resolveName(objectName);
723 if (cedata.first)
724 {
725 target = cedata.second.clone(); // We have to free this since we own the pointer
726 deleteTargetAfterUse = true; // so note that down
727 }
728 }
729 else
730 {
731 CatalogsDB::DBManager db_manager { CatalogsDB::dso_db_path() };
732 target = FindDialog::resolveAndAdd(db_manager, objectName);
733 }
734
735 }
736 if (!target)
737 {
738 return QString("<xml></xml>");
739 }
740 QString output;
741 QXmlStreamWriter stream(&output);
742 stream.setAutoFormatting(true);
743 stream.writeStartDocument();
744 stream.writeStartElement("object");
745 stream.writeTextElement("Name", target->name());
746 stream.writeTextElement("Alt_Name", target->name2());
747 stream.writeTextElement("Long_Name", target->longname());
748 stream.writeTextElement("Constellation",
749 KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(target));
750 stream.writeTextElement("RA_Dec_Epoch_JD", QString::number(target->getLastPrecessJD(), 'f', 3));
751 stream.writeTextElement("RA_HMS", target->ra().toHMSString());
752 stream.writeTextElement("Dec_DMS", target->dec().toDMSString());
753 stream.writeTextElement("RA_J2000_HMS", target->ra0().toHMSString());
754 stream.writeTextElement("Dec_J2000_DMS", target->dec0().toDMSString());
755 stream.writeTextElement("RA_Degrees", QString::number(target->ra().Degrees()));
756 stream.writeTextElement("Dec_Degrees", QString::number(target->dec().Degrees()));
757 stream.writeTextElement("RA_J2000_Degrees", QString::number(target->ra0().Degrees()));
758 stream.writeTextElement("Dec_J2000_Degrees", QString::number(target->dec0().Degrees()));
759 stream.writeTextElement("Type", target->typeName());
760 stream.writeTextElement("Magnitude", QString::number(target->mag(), 'g', 2));
761 stream.writeTextElement("Position_Angle", QString::number(target->pa(), 'g', 3));
762 auto *star = dynamic_cast<const StarObject *>(target);
763 auto *dso = dynamic_cast<const CatalogObject *>(target);
764 if (star)
765 {
766 stream.writeTextElement("Spectral_Type", star->sptype());
767 stream.writeTextElement("Genetive_Name", star->gname());
768 stream.writeTextElement("Greek_Letter", star->greekLetter());
769 stream.writeTextElement("Proper_Motion", QString::number(star->pmMagnitude()));
770 stream.writeTextElement("Proper_Motion_RA", QString::number(star->pmRA()));
771 stream.writeTextElement("Proper_Motion_Dec", QString::number(star->pmDec()));
772 stream.writeTextElement("Parallax_mas", QString::number(star->parallax()));
773 stream.writeTextElement("Distance_pc", QString::number(star->distance()));
774 stream.writeTextElement("Henry_Draper", QString::number(star->getHDIndex()));
775 stream.writeTextElement("BV_Index", QString::number(star->getBVIndex()));
776 }
777 else if (dso)
778 {
779 stream.writeTextElement("Catalog", dso->getCatalog().name);
780 stream.writeTextElement("Major_Axis", QString::number(dso->a()));
781 stream.writeTextElement("Minor_Axis", QString::number(dso->a() * dso->e()));
782 }
783 stream.writeEndElement(); // object
784 stream.writeEndDocument();
785
786 if (deleteTargetAfterUse)
787 {
788 Q_ASSERT(!!target);
789 delete target;
790 }
791
792 return output;
793 }
794
getObjectPositionInfo(const QString & objectName)795 QString KStars::getObjectPositionInfo(const QString &objectName)
796 {
797 Q_ASSERT(data());
798 const SkyObject *obj = data()->objectNamed(objectName); // make sure we work with a clone
799 if (!obj)
800 {
801 return QString("<xml></xml>");
802 }
803 SkyObject *target = obj->clone();
804 if (!target) // should not happen
805 {
806 qWarning() << "ERROR: Could not clone SkyObject " << objectName << "!";
807 return QString("<xml></xml>");
808 }
809
810 const KSNumbers *updateNum = data()->updateNum();
811 const KStarsDateTime ut = data()->ut();
812 const GeoLocation *geo = data()->geo();
813 QString riseTimeString, setTimeString, transitTimeString;
814 QString riseAzString, setAzString, transitAltString;
815
816 // Make sure the coordinates of the SkyObject are updated
817 target->updateCoords(updateNum, true, geo->lat(), data()->lst(), true);
818 target->EquatorialToHorizontal(data()->lst(), geo->lat());
819
820 // Compute rise, set and transit times and parameters -- Code pulled from DetailDialog
821 QTime riseTime = target->riseSetTime(ut, geo, true); //true = use rise time
822 dms riseAz = target->riseSetTimeAz(ut, geo, true); //true = use rise time
823 QTime transitTime = target->transitTime(ut, geo);
824 dms transitAlt = target->transitAltitude(ut, geo);
825 if (transitTime < riseTime)
826 {
827 transitTime = target->transitTime(ut.addDays(1), geo);
828 transitAlt = target->transitAltitude(ut.addDays(1), geo);
829 }
830 //If set time is before rise time, use set time for tomorrow
831 QTime setTime = target->riseSetTime(ut, geo, false); //false = use set time
832 dms setAz = target->riseSetTimeAz(ut, geo, false); //false = use set time
833 if (setTime < riseTime)
834 {
835 setTime = target->riseSetTime(ut.addDays(1), geo, false); //false = use set time
836 setAz = target->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time
837 }
838 if (riseTime.isValid())
839 {
840 riseTimeString = QString::asprintf("%02d:%02d", riseTime.hour(), riseTime.minute());
841 setTimeString = QString::asprintf("%02d:%02d", setTime.hour(), setTime.minute());
842 riseAzString = riseAz.toDMSString(true, true);
843 setAzString = setAz.toDMSString(true, true);
844 }
845 else
846 {
847 if (target->alt().Degrees() > 0.0)
848 {
849 riseTimeString = setTimeString = QString("Circumpolar");
850 }
851 else
852 {
853 riseTimeString = setTimeString = QString("Never Rises");
854 }
855 riseAzString = setAzString = QString("N/A");
856 }
857
858 transitTimeString = QString::asprintf("%02d:%02d", transitTime.hour(), transitTime.minute());
859 transitAltString = transitAlt.toDMSString(true, true);
860
861 QString output;
862 QXmlStreamWriter stream(&output);
863 stream.setAutoFormatting(true);
864 stream.writeStartDocument();
865 stream.writeStartElement("object");
866 stream.writeTextElement("Name", target->name());
867 stream.writeTextElement("RA_Dec_Epoch_JD", QString::number(target->getLastPrecessJD(), 'f', 3));
868 stream.writeTextElement("AltAz_JD", QString::number(data()->ut().djd(), 'f', 3));
869 stream.writeTextElement("RA_HMS", target->ra().toHMSString(true));
870 stream.writeTextElement("Dec_DMS", target->dec().toDMSString(true, true));
871 stream.writeTextElement("RA_J2000_HMS", target->ra0().toHMSString(true));
872 stream.writeTextElement("Dec_J2000_DMS", target->dec0().toDMSString(true, true));
873 stream.writeTextElement("RA_Degrees", QString::number(target->ra().Degrees()));
874 stream.writeTextElement("Dec_Degrees", QString::number(target->dec().Degrees()));
875 stream.writeTextElement("RA_J2000_Degrees", QString::number(target->ra0().Degrees()));
876 stream.writeTextElement("Dec_J2000_Degrees", QString::number(target->dec0().Degrees()));
877 stream.writeTextElement("Altitude_DMS", target->alt().toDMSString(true, true));
878 stream.writeTextElement("Azimuth_DMS", target->az().toDMSString(true, true));
879 stream.writeTextElement("Altitude_Degrees", QString::number(target->alt().Degrees()));
880 stream.writeTextElement("Azimuth_Degrees", QString::number(target->az().Degrees()));
881 stream.writeTextElement("Rise", riseTimeString);
882 stream.writeTextElement("Rise_Az_DMS", riseAzString);
883 stream.writeTextElement("Set", setTimeString);
884 stream.writeTextElement("Set_Az_DMS", setAzString);
885 stream.writeTextElement("Transit", transitTimeString);
886 stream.writeTextElement("Transit_Alt_DMS", transitAltString);
887 stream.writeTextElement("Time_Zone_Offset", QString::asprintf("%02.2f", geo->TZ()));
888
889 stream.writeEndElement(); // object
890 stream.writeEndDocument();
891 return output;
892 }
893
renderEyepieceView(const QString & objectName,const QString & destPathChart,const double fovWidth,const double fovHeight,const double rotation,const double scale,const bool flip,const bool invert,QString imagePath,const QString & destPathImage,const bool overlay,const bool invertColors)894 void KStars::renderEyepieceView(const QString &objectName, const QString &destPathChart, const double fovWidth,
895 const double fovHeight, const double rotation, const double scale, const bool flip,
896 const bool invert, QString imagePath, const QString &destPathImage, const bool overlay,
897 const bool invertColors)
898 {
899 const SkyObject *obj = data()->objectNamed(objectName);
900 if (!obj)
901 {
902 qCWarning(KSTARS) << "Object named " << objectName << " was not found!";
903 return;
904 }
905 SkyObject *target = obj->clone();
906 const KSNumbers *updateNum = data()->updateNum();
907 const KStarsDateTime ut = data()->ut();
908 const GeoLocation *geo = data()->geo();
909 QPixmap *renderChart = new QPixmap();
910 QPixmap *renderImage = nullptr;
911 QTemporaryFile tempFile;
912 if (overlay || (!destPathImage.isEmpty()))
913 {
914 if (!QFile::exists(imagePath))
915 {
916 // We must download a DSS image
917 tempFile.open();
918 QEventLoop loop;
919 std::function<void(bool)> slot = [&loop](bool unused)
920 {
921 Q_UNUSED(unused);
922 loop.quit();
923 };
924 new KSDssDownloader(target, tempFile.fileName(), slot, this);
925 qDebug() << "DSS download requested. Waiting for download to complete...";
926 loop.exec(); // wait for download to complete
927 imagePath = tempFile.fileName();
928 }
929 if (QFile::exists(imagePath)) // required because DSS Download may fail
930 renderImage = new QPixmap();
931 }
932
933 // Make sure the coordinates of the SkyObject are updated
934 target->updateCoords(updateNum, true, geo->lat(), data()->lst(), true);
935 target->EquatorialToHorizontal(data()->lst(), geo->lat());
936
937 EyepieceField::renderEyepieceView(target, renderChart, fovWidth, fovHeight, rotation, scale, flip, invert,
938 imagePath, renderImage, overlay, invertColors);
939 renderChart->save(destPathChart);
940 delete renderChart;
941 if (renderImage)
942 {
943 renderImage->save(destPathImage);
944 delete renderImage;
945 }
946 }
getObservingWishListObjectNames()947 QString KStars::getObservingWishListObjectNames()
948 {
949 QString output;
950
951 for (auto &object : KStarsData::Instance()->observingList()->obsList())
952 {
953 output.append(object->name() + '\n');
954 }
955 return output;
956 }
957
getObservingSessionPlanObjectNames()958 QString KStars::getObservingSessionPlanObjectNames()
959 {
960 QString output;
961
962 for (auto &object : KStarsData::Instance()->observingList()->sessionList())
963 {
964 output.append(object->name() + '\n');
965 }
966 return output;
967 }
968
setApproxFOV(double FOV_Degrees)969 void KStars::setApproxFOV(double FOV_Degrees)
970 {
971 zoom(map()->width() / (FOV_Degrees * dms::DegToRad));
972 }
973
getSkyMapDimensions()974 QString KStars::getSkyMapDimensions()
975 {
976 return (QString::number(map()->width()) + 'x' + QString::number(map()->height()));
977 }
printImage(bool usePrintDialog,bool useChartColors)978 void KStars::printImage(bool usePrintDialog, bool useChartColors)
979 {
980 //QPRINTER_FOR_NOW
981 // KPrinter printer( true, QPrinter::HighResolution );
982 QPrinter printer(QPrinter::HighResolution);
983 printer.setFullPage(false);
984
985 //Set up the printer (either with the Print Dialog,
986 //or using the default settings)
987 bool ok(false);
988 if (usePrintDialog)
989 {
990 //QPRINTER_FOR_NOW
991 // ok = printer.setup( this, i18n("Print Sky") );
992 //QPrintDialog *dialog = KdePrint::createPrintDialog(&printer, this);
993 QPrintDialog *dialog = new QPrintDialog(&printer, this);
994 dialog->setWindowTitle(i18nc("@title:window", "Print Sky"));
995 if (dialog->exec() == QDialog::Accepted)
996 ok = true;
997 delete dialog;
998 }
999 else
1000 {
1001 //QPRINTER_FOR_NOW
1002 // ok = printer.autoConfigure();
1003 ok = true;
1004 }
1005
1006 if (ok)
1007 {
1008 QApplication::setOverrideCursor(Qt::WaitCursor);
1009
1010 //Save current ColorScheme file name and switch to Star Chart
1011 //scheme (if requested)
1012 QString schemeName = data()->colorScheme()->fileName();
1013 if (useChartColors)
1014 {
1015 loadColorScheme("chart.colors");
1016 }
1017
1018 map()->setupProjector();
1019 map()->exportSkyImage(&printer, true);
1020
1021 //Restore old color scheme if necessary
1022 //(if printing was aborted, the ColorScheme is still restored)
1023 if (useChartColors)
1024 {
1025 loadColorScheme(schemeName);
1026 map()->forceUpdate();
1027 }
1028
1029 QApplication::restoreOverrideCursor();
1030 }
1031 }
1032
openFITS(const QUrl & imageURL)1033 void KStars::openFITS(const QUrl &imageURL)
1034 {
1035 #ifndef HAVE_CFITSIO
1036 qWarning() << "KStars does not support loading FITS. Please recompile KStars with FITS support.";
1037 #else
1038 QPointer<FITSViewer> fv = createFITSViewer();
1039 // auto m_Loaded = std::make_shared<QMetaObject::Connection>();
1040 // *m_Loaded = connect(fv.get(), &FITSViewer::loaded, [fv, m_Loaded]()
1041 // {
1042 // fv->show();
1043
1044 // QObject::disconnect(*m_Loaded);
1045 // });
1046
1047 // auto m_Failed = std::make_shared<QMetaObject::Connection>();
1048 // *m_Failed = connect(fv.get(), &FITSViewer::failed, [fv, m_Failed]()
1049 // {
1050 // QObject::disconnect(*m_Failed);
1051 // });
1052
1053 fv->loadFile(imageURL);
1054 #endif
1055 }
1056