File indexing completed on 2022-12-06 18:58:48

0001 /*
0002     SPDX-FileCopyrightText: 2002 Thomas Kabelmann <tk78@gmx.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 //KStars DBUS functions
0008 
0009 #include "kstars.h"
0010 
0011 #include "colorscheme.h"
0012 #include "eyepiecefield.h"
0013 #include "imageexporter.h"
0014 #include "ksdssdownloader.h"
0015 #include "kstarsdata.h"
0016 #include "observinglist.h"
0017 #include "Options.h"
0018 #include "skymap.h"
0019 #include "skycomponents/constellationboundarylines.h"
0020 #include "skycomponents/skymapcomposite.h"
0021 #include "skyobjects/catalogobject.h"
0022 #include "catalogsdb.h"
0023 #include "skyobjects/ksplanetbase.h"
0024 #include "skyobjects/starobject.h"
0025 #include "tools/whatsinteresting/wiview.h"
0026 #include "dialogs/finddialog.h"
0027 #include "tools/nameresolver.h"
0028 
0029 #ifdef HAVE_CFITSIO
0030 #include "fitsviewer/fitsviewer.h"
0031 #ifdef HAVE_INDI
0032 #include "ekos/manager.h"
0033 #endif
0034 #endif
0035 
0036 #include <KActionCollection>
0037 
0038 #include <QPrintDialog>
0039 #include <QPrinter>
0040 #include <QElapsedTimer>
0041 
0042 #include "kstars_debug.h"
0043 
0044 void KStars::setRaDec(double ra, double dec)
0045 {
0046     SkyPoint p(ra, dec);
0047     map()->setClickedPoint(&p);
0048     map()->slotCenter();
0049 }
0050 
0051 void KStars::setRaDecJ2000(double ra0, double dec0)
0052 {
0053     SkyPoint p;
0054     p.setRA0(ra0);
0055     p.setDec0(dec0);
0056     p.updateCoordsNow(data()->updateNum());
0057     map()->setClickedPoint(&p);
0058     map()->slotCenter();
0059 }
0060 
0061 void KStars::setAltAz(double alt, double az, bool altIsRefracted)
0062 {
0063     SkyPoint p;
0064     if (altIsRefracted)
0065     {
0066         alt = SkyPoint::unrefract(alt);
0067     }
0068     p.setAlt(alt);
0069     p.setAz(az);
0070     p.HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0071     map()->setClickedPoint(&p);
0072     map()->slotCenter();
0073 }
0074 
0075 void KStars::lookTowards(const QString &direction)
0076 {
0077     QString dir = direction.toLower();
0078     if (dir == i18n("zenith") || dir == "z")
0079     {
0080         actionCollection()->action("zenith")->trigger();
0081     }
0082     else if (dir == i18n("north") || dir == "n")
0083     {
0084         actionCollection()->action("north")->trigger();
0085     }
0086     else if (dir == i18n("east") || dir == "e")
0087     {
0088         actionCollection()->action("east")->trigger();
0089     }
0090     else if (dir == i18n("south") || dir == "s")
0091     {
0092         actionCollection()->action("south")->trigger();
0093     }
0094     else if (dir == i18n("west") || dir == "w")
0095     {
0096         actionCollection()->action("west")->trigger();
0097     }
0098     else if (dir == i18n("northeast") || dir == "ne")
0099     {
0100         map()->stopTracking();
0101         map()->clickedPoint()->setAlt(15.0);
0102         map()->clickedPoint()->setAz(45.0);
0103         map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0104         map()->slotCenter();
0105     }
0106     else if (dir == i18n("southeast") || dir == "se")
0107     {
0108         map()->stopTracking();
0109         map()->clickedPoint()->setAlt(15.0);
0110         map()->clickedPoint()->setAz(135.0);
0111         map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0112         map()->slotCenter();
0113     }
0114     else if (dir == i18n("southwest") || dir == "sw")
0115     {
0116         map()->stopTracking();
0117         map()->clickedPoint()->setAlt(15.0);
0118         map()->clickedPoint()->setAz(225.0);
0119         map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0120         map()->slotCenter();
0121     }
0122     else if (dir == i18n("northwest") || dir == "nw")
0123     {
0124         map()->stopTracking();
0125         map()->clickedPoint()->setAlt(15.0);
0126         map()->clickedPoint()->setAz(315.0);
0127         map()->clickedPoint()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0128         map()->slotCenter();
0129     }
0130     else
0131     {
0132         SkyObject *target = data()->objectNamed(direction);
0133         if (target != nullptr)
0134         {
0135             map()->setClickedObject(target);
0136             map()->setClickedPoint(target);
0137             map()->slotCenter();
0138         }
0139     }
0140 }
0141 
0142 void KStars::addLabel(const QString &name)
0143 {
0144     SkyObject *target = data()->objectNamed(name);
0145     if (target != nullptr)
0146     {
0147         data()->skyComposite()->addNameLabel(target);
0148         map()->forceUpdate();
0149     }
0150 }
0151 
0152 void KStars::removeLabel(const QString &name)
0153 {
0154     SkyObject *target = data()->objectNamed(name);
0155     if (target != nullptr)
0156     {
0157         data()->skyComposite()->removeNameLabel(target);
0158         map()->forceUpdate();
0159     }
0160 }
0161 
0162 void KStars::addTrail(const QString &name)
0163 {
0164     TrailObject *target = dynamic_cast<TrailObject *>(data()->objectNamed(name));
0165     if (target)
0166     {
0167         target->addToTrail();
0168         map()->forceUpdate();
0169     }
0170 }
0171 
0172 void KStars::removeTrail(const QString &name)
0173 {
0174     TrailObject *target = dynamic_cast<TrailObject *>(data()->objectNamed(name));
0175     if (target)
0176     {
0177         target->clearTrail();
0178         map()->forceUpdate();
0179     }
0180 }
0181 
0182 void KStars::zoom(double z)
0183 {
0184     map()->setZoomFactor(z);
0185 }
0186 
0187 void KStars::zoomIn()
0188 {
0189     map()->slotZoomIn();
0190 }
0191 
0192 void KStars::zoomOut()
0193 {
0194     map()->slotZoomOut();
0195 }
0196 
0197 void KStars::defaultZoom()
0198 {
0199     map()->slotZoomDefault();
0200 }
0201 
0202 void KStars::setLocalTime(int yr, int mth, int day, int hr, int min, int sec)
0203 {
0204     data()->changeDateTime(data()->geo()->LTtoUT(KStarsDateTime(QDate(yr, mth, day), QTime(hr, min, sec))));
0205 }
0206 
0207 void KStars::setTimeToNow()
0208 {
0209     slotSetTimeToNow();
0210 }
0211 
0212 void KStars::waitFor(double sec)
0213 {
0214     QElapsedTimer tm;
0215     tm.start();
0216     while (tm.elapsed() < int(1000. * sec))
0217     {
0218         qApp->processEvents();
0219     }
0220 }
0221 
0222 void KStars::waitForKey(const QString &k)
0223 {
0224     data()->resumeKey = QKeySequence::fromString(k);
0225     if (!data()->resumeKey.isEmpty())
0226     {
0227         //When the resumeKey is pressed, resumeKey is set to empty
0228         while (!data()->resumeKey.isEmpty())
0229             qApp->processEvents();
0230     }
0231     else
0232     {
0233         qDebug() << Q_FUNC_INFO << "Error [D-Bus waitForKey()]: Invalid key requested.";
0234     }
0235 }
0236 
0237 void KStars::setTracking(bool track)
0238 {
0239     if (track != Options::isTracking())
0240         slotTrack();
0241 }
0242 
0243 void KStars::popupMessage(int /*x*/, int /*y*/, const QString & /*message*/)
0244 {
0245     //Show a small popup window at (x,y) with a text message
0246 }
0247 
0248 void KStars::drawLine(int /*x1*/, int /*y1*/, int /*x2*/, int /*y2*/, int /*speed*/)
0249 {
0250     //Draw a line on the skymap display
0251 }
0252 
0253 QString KStars::location()
0254 {
0255     GeoLocation *currentLocation = data()->geo();
0256 
0257     QJsonObject locationInfo =
0258     {
0259         {"name", currentLocation->name()},
0260         {"province", currentLocation->province()},
0261         {"country", currentLocation->country()},
0262         {"longitude", currentLocation->lng()->Degrees()},
0263         {"latitude", currentLocation->lat()->Degrees()},
0264         {"tz0", currentLocation->TZ0()},
0265         {"tz", currentLocation->TZ()}
0266     };
0267 
0268     return QJsonDocument(locationInfo).toJson(QJsonDocument::Compact);
0269 }
0270 
0271 bool KStars::setGeoLocation(const QString &city, const QString &province, const QString &country)
0272 {
0273     //Set the geographic location
0274     bool cityFound(false);
0275 
0276     foreach (GeoLocation *loc, data()->geoList)
0277     {
0278         if (loc->translatedName() == city && (province.isEmpty() || loc->translatedProvince() == province) &&
0279                 loc->translatedCountry() == country)
0280         {
0281             cityFound = true;
0282 
0283             data()->setLocation(*loc);
0284 
0285             //configure time zone rule
0286             KStarsDateTime ltime = loc->UTtoLT(data()->ut());
0287             loc->tzrule()->reset_with_ltime(ltime, loc->TZ0(), data()->isTimeRunningForward());
0288             data()->setNextDSTChange(loc->tzrule()->nextDSTChange());
0289 
0290             //reset LST
0291             data()->syncLST();
0292 
0293             //make sure planets, etc. are updated immediately
0294             data()->setFullTimeUpdate();
0295 
0296             // If the sky is in Horizontal mode and not tracking, reset focus such that
0297             // Alt/Az remain constant.
0298             if (!Options::isTracking() && Options::useAltAz())
0299             {
0300                 map()->focus()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0301             }
0302 
0303             // recalculate new times and objects
0304             data()->setSnapNextFocus();
0305             updateTime();
0306 
0307             //no need to keep looking, we're done.
0308             break;
0309         }
0310     }
0311 
0312     if (!cityFound)
0313     {
0314         if (province.isEmpty())
0315             qDebug()
0316                     << QString("Error [D-Bus setGeoLocation]: city %1, %2 not found in database.").arg(city, country);
0317         else
0318             qDebug() << Q_FUNC_INFO << QString("Error [D-Bus setGeoLocation]: city %1, %2, %3 not found in database.")
0319                      .arg(city, province, country);
0320     }
0321 
0322     return cityFound;
0323 }
0324 
0325 bool KStars::setGPSLocation(double longitude, double latitude, double elevation, double tz0)
0326 {
0327     GeoLocation *geo = data()->geo();
0328     std::unique_ptr<GeoLocation> tempGeo;
0329 
0330     QString newLocationName("GPS Location");
0331 
0332     dms lng(longitude), lat(latitude);
0333 
0334     GeoLocation *nearest = data()->nearestLocation(longitude, latitude);
0335 
0336     if (nearest)
0337         tempGeo.reset(new GeoLocation(lng, lat, newLocationName, "", "", nearest->TZ0(), nearest->tzrule(), elevation));
0338     else
0339         tempGeo.reset(new GeoLocation(lng, lat, newLocationName, "", "", tz0, new TimeZoneRule(), elevation));
0340 
0341     geo = tempGeo.get();
0342 
0343     qCInfo(KSTARS) << "Setting location from DBus. Longitude:" << longitude << "Latitude:" << latitude;
0344 
0345     data()->setLocation(*geo);
0346 
0347     return true;
0348 }
0349 
0350 void KStars::readConfig()
0351 {
0352     //Load config file values into Options object
0353     Options::self()->load();
0354 
0355     applyConfig();
0356 
0357     //Reset date, if one was stored
0358     if (data()->StoredDate.isValid())
0359     {
0360         data()->changeDateTime(data()->geo()->LTtoUT(data()->StoredDate));
0361         data()->StoredDate = KStarsDateTime(QDateTime()); //invalidate StoredDate
0362     }
0363 
0364     map()->forceUpdate();
0365 }
0366 
0367 void KStars::writeConfig()
0368 {
0369     Options::self()->save();
0370 
0371     //Store current simulation time
0372     data()->StoredDate = data()->lt();
0373 }
0374 
0375 QString KStars::getOption(const QString &name)
0376 {
0377     //Some config items are not stored in the Options object while
0378     //the program is running; catch these here and returntheir current value.
0379     if (name == "FocusRA")
0380     {
0381         return QString::number(map()->focus()->ra().Hours(), 'f', 6);
0382     }
0383     if (name == "FocusDec")
0384     {
0385         return QString::number(map()->focus()->dec().Degrees(), 'f', 6);
0386     }
0387 
0388     KConfigSkeletonItem *it = Options::self()->findItem(name);
0389     if (it)
0390         return it->property().toString();
0391     else
0392         return QString();
0393 }
0394 
0395 void KStars::changeViewOption(const QString &op, const QString &val)
0396 {
0397     bool bOk(false), dOk(false);
0398 
0399     //parse bool value
0400     bool bVal(false);
0401     if (val.toLower() == "true")
0402     {
0403         bOk  = true;
0404         bVal = true;
0405     }
0406     if (val.toLower() == "false")
0407     {
0408         bOk  = true;
0409         bVal = false;
0410     }
0411     if (val == "1")
0412     {
0413         bOk  = true;
0414         bVal = true;
0415     }
0416     if (val == "0")
0417     {
0418         bOk  = true;
0419         bVal = false;
0420     }
0421 
0422     //parse double value
0423     double dVal = val.toDouble(&dOk);
0424 
0425     //[GUI]
0426     if (op == "ShowInfoBoxes" && bOk)
0427         Options::setShowInfoBoxes(bVal);
0428     if (op == "ShowTimeBox" && bOk)
0429         Options::setShowTimeBox(bVal);
0430     if (op == "ShowGeoBox" && bOk)
0431         Options::setShowGeoBox(bVal);
0432     if (op == "ShowFocusBox" && bOk)
0433         Options::setShowFocusBox(bVal);
0434     if (op == "ShadeTimeBox" && bOk)
0435         Options::setShadeTimeBox(bVal);
0436     if (op == "ShadeGeoBox" && bOk)
0437         Options::setShadeGeoBox(bVal);
0438     if (op == "ShadeFocusBox" && bOk)
0439         Options::setShadeFocusBox(bVal);
0440 
0441     //[View]
0442     // FIXME: REGRESSION
0443     //     if ( op == "FOVName"                ) Options::setFOVName(         val );
0444     //     if ( op == "FOVSizeX"         && dOk ) Options::setFOVSizeX( (float)dVal );
0445     //     if ( op == "FOVSizeY"         && dOk ) Options::setFOVSizeY( (float)dVal );
0446     //     if ( op == "FOVShape"        && nOk ) Options::setFOVShape(       nVal );
0447     //     if ( op == "FOVColor"               ) Options::setFOVColor(        val );
0448     if (op == "ShowStars" && bOk)
0449         Options::setShowStars(bVal);
0450     if (op == "ShowCLines" && bOk)
0451         Options::setShowCLines(bVal);
0452     if (op == "ShowCBounds" && bOk)
0453         Options::setShowCBounds(bVal);
0454     if (op == "ShowCNames" && bOk)
0455         Options::setShowCNames(bVal);
0456     if (op == "ShowMilkyWay" && bOk)
0457         Options::setShowMilkyWay(bVal);
0458     if (op == "AutoSelectGrid" && bOk)
0459         Options::setAutoSelectGrid(bVal);
0460     if (op == "ShowEquatorialGrid" && bOk)
0461         Options::setShowEquatorialGrid(bVal);
0462     if (op == "ShowHorizontalGrid" && bOk)
0463         Options::setShowHorizontalGrid(bVal);
0464     if (op == "ShowEquator" && bOk)
0465         Options::setShowEquator(bVal);
0466     if (op == "ShowEcliptic" && bOk)
0467         Options::setShowEcliptic(bVal);
0468     if (op == "ShowHorizon" && bOk)
0469         Options::setShowHorizon(bVal);
0470     if (op == "ShowGround" && bOk)
0471         Options::setShowGround(bVal);
0472     if (op == "ShowSun" && bOk)
0473         Options::setShowSun(bVal);
0474     if (op == "ShowMoon" && bOk)
0475         Options::setShowMoon(bVal);
0476     if (op == "ShowMercury" && bOk)
0477         Options::setShowMercury(bVal);
0478     if (op == "ShowVenus" && bOk)
0479         Options::setShowVenus(bVal);
0480     if (op == "ShowMars" && bOk)
0481         Options::setShowMars(bVal);
0482     if (op == "ShowJupiter" && bOk)
0483         Options::setShowJupiter(bVal);
0484     if (op == "ShowSaturn" && bOk)
0485         Options::setShowSaturn(bVal);
0486     if (op == "ShowUranus" && bOk)
0487         Options::setShowUranus(bVal);
0488     if (op == "ShowNeptune" && bOk)
0489         Options::setShowNeptune(bVal);
0490     //if ( op == "ShowPluto"       && bOk ) Options::setShowPluto(    bVal );
0491     if (op == "ShowAsteroids" && bOk)
0492         Options::setShowAsteroids(bVal);
0493     if (op == "ShowComets" && bOk)
0494         Options::setShowComets(bVal);
0495     if (op == "ShowSolarSystem" && bOk)
0496         Options::setShowSolarSystem(bVal);
0497     if (op == "ShowDeepSky" && bOk)
0498         Options::setShowDeepSky(bVal);
0499     if (op == "ShowSupernovae" && bOk)
0500         Options::setShowSupernovae(bVal);
0501     if (op == "ShowStarNames" && bOk)
0502         Options::setShowStarNames(bVal);
0503     if (op == "ShowStarMagnitudes" && bOk)
0504         Options::setShowStarMagnitudes(bVal);
0505     if (op == "ShowAsteroidNames" && bOk)
0506         Options::setShowAsteroidNames(bVal);
0507     if (op == "ShowCometNames" && bOk)
0508         Options::setShowCometNames(bVal);
0509     if (op == "ShowPlanetNames" && bOk)
0510         Options::setShowPlanetNames(bVal);
0511     if (op == "ShowPlanetImages" && bOk)
0512         Options::setShowPlanetImages(bVal);
0513     if (op == "HideOnSlew" && bOk)
0514         Options::setHideOnSlew(bVal);
0515     if (op == "HideStars" && bOk)
0516         Options::setHideStars(bVal);
0517     if (op == "HidePlanets" && bOk)
0518         Options::setHidePlanets(bVal);
0519     if (op == "HideMilkyWay" && bOk)
0520         Options::setHideMilkyWay(bVal);
0521     if (op == "HideCNames" && bOk)
0522         Options::setHideCNames(bVal);
0523     if (op == "HideCLines" && bOk)
0524         Options::setHideCLines(bVal);
0525     if (op == "HideCBounds" && bOk)
0526         Options::setHideCBounds(bVal);
0527     if (op == "HideGrids" && bOk)
0528         Options::setHideGrids(bVal);
0529     if (op == "HideLabels" && bOk)
0530         Options::setHideLabels(bVal);
0531 
0532     if (op == "UseAltAz" && bOk)
0533         Options::setUseAltAz(bVal);
0534     if (op == "UseRefraction" && bOk)
0535         Options::setUseRefraction(bVal);
0536     if (op == "UseAutoLabel" && bOk)
0537         Options::setUseAutoLabel(bVal);
0538     if (op == "UseHoverLabel" && bOk)
0539         Options::setUseHoverLabel(bVal);
0540     if (op == "UseAutoTrail" && bOk)
0541         Options::setUseAutoTrail(bVal);
0542     if (op == "UseAnimatedSlewing" && bOk)
0543         Options::setUseAnimatedSlewing(bVal);
0544     if (op == "FadePlanetTrails" && bOk)
0545         Options::setFadePlanetTrails(bVal);
0546     if (op == "SlewTimeScale" && dOk)
0547         Options::setSlewTimeScale(dVal);
0548     if (op == "ZoomFactor" && dOk)
0549         Options::setZoomFactor(dVal);
0550     //    if ( op == "MagLimitDrawStar"     && dOk )    Options::setMagLimitDrawStar(    dVal );
0551     if (op == "MagLimitDrawDeepSky" && dOk)
0552         Options::setMagLimitDrawDeepSky(dVal);
0553     if (op == "StarDensity" && dOk)
0554         Options::setStarDensity(dVal);
0555     //    if ( op == "MagLimitDrawStarZoomOut" && dOk ) Options::setMagLimitDrawStarZoomOut(        dVal );
0556     if (op == "MagLimitDrawDeepSkyZoomOut" && dOk)
0557         Options::setMagLimitDrawDeepSkyZoomOut(dVal);
0558     if (op == "StarLabelDensity" && dOk)
0559         Options::setStarLabelDensity(dVal);
0560     if (op == "MagLimitHideStar" && dOk)
0561         Options::setMagLimitHideStar(dVal);
0562     if (op == "MagLimitAsteroid" && dOk)
0563         Options::setMagLimitAsteroid(dVal);
0564     if (op == "AsteroidLabelDensity" && dOk)
0565         Options::setAsteroidLabelDensity(dVal);
0566     if (op == "MaxRadCometName" && dOk)
0567         Options::setMaxRadCometName(dVal);
0568 
0569     //these three are a "radio group"
0570     if (op == "UseLatinConstellationNames" && bOk)
0571     {
0572         Options::setUseLatinConstellNames(true);
0573         Options::setUseLocalConstellNames(false);
0574         Options::setUseAbbrevConstellNames(false);
0575     }
0576     if (op == "UseLocalConstellationNames" && bOk)
0577     {
0578         Options::setUseLatinConstellNames(false);
0579         Options::setUseLocalConstellNames(true);
0580         Options::setUseAbbrevConstellNames(false);
0581     }
0582     if (op == "UseAbbrevConstellationNames" && bOk)
0583     {
0584         Options::setUseLatinConstellNames(false);
0585         Options::setUseLocalConstellNames(false);
0586         Options::setUseAbbrevConstellNames(true);
0587     }
0588 
0589     map()->forceUpdate();
0590 }
0591 
0592 void KStars::setColor(const QString &name, const QString &value)
0593 {
0594     ColorScheme *cs = data()->colorScheme();
0595     if (cs->hasColorNamed(name))
0596     {
0597         cs->setColor(name, value);
0598         map()->forceUpdate();
0599     }
0600 }
0601 
0602 QString KStars::colorScheme() const
0603 {
0604     return data()->colorScheme()->fileName();
0605 }
0606 
0607 void KStars::loadColorScheme(const QString &name)
0608 {
0609     data()->colorScheme()->load(name);
0610 
0611 #if 0
0612     if (ok)
0613     {
0614         //set the application colors for the Night Vision scheme
0615         if (Options::darkAppColors())
0616         {
0617             //OriginalPalette = QApplication::palette();
0618             QApplication::setPalette(DarkPalette);
0619             if (KStars::Instance()->wiView())
0620                 KStars::Instance()->wiView()->setNightVisionOn(true);
0621             //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.
0622             //It might be a good idea to use stylesheets in the future instead of palettes but this will work for now for OS X.
0623             //This is also in KStars.cpp.  If you change it, change it in BOTH places.
0624 #ifdef Q_OS_OSX
0625             qDebug() << Q_FUNC_INFO << "setting dark stylesheet";
0626             qApp->setStyleSheet(
0627                 "QWidget { background-color: black; color:red; "
0628                 "selection-background-color:rgb(30,30,30);selection-color:white}"
0629                 "QToolBar { border:none }"
0630                 "QTabBar::tab:selected { background-color:rgb(50,50,50) }"
0631                 "QTabBar::tab:!selected { background-color:rgb(30,30,30) }"
0632                 "QPushButton { background-color:rgb(50,50,50);border-width:1px; border-style:solid;border-color:black}"
0633                 "QPushButton::disabled { background-color:rgb(10,10,10);border-width:1px; "
0634                 "border-style:solid;border-color:black }"
0635                 "QToolButton:Checked { background-color:rgb(30,30,30); border:none }"
0636                 "QComboBox { background-color:rgb(30,30,30); }"
0637                 "QComboBox::disabled { background-color:rgb(10,10,10) }"
0638                 "QScrollBar::handle { background: rgb(30,30,30) }"
0639                 "QSpinBox { border-width: 1px; border-style:solid; border-color:rgb(30,30,30) }"
0640                 "QDoubleSpinBox { border-width:1px; border-style:solid; border-color:rgb(30,30,30) }"
0641                 "QLineEdit { border-width: 1px; border-style: solid; border-color:rgb(30,30,30) }"
0642                 "QCheckBox::indicator:unchecked { background-color:rgb(30,30,30);border-width:1px; "
0643                 "border-style:solid;border-color:black }"
0644                 "QCheckBox::indicator:checked { background-color:red;border-width:1px; "
0645                 "border-style:solid;border-color:black }"
0646                 "QRadioButton::indicator:unchecked { background-color:rgb(30,30,30) }"
0647                 "QRadioButton::indicator:checked { background-color:red }"
0648                 "QRoundProgressBar { alternate-background-color:black }"
0649                 "QDateTimeEdit {background-color:rgb(30,30,30); border-width: 1px; border-style:solid; "
0650                 "border-color:rgb(30,30,30) }"
0651                 "QHeaderView { color:red;background-color:black }"
0652                 "QHeaderView::Section { background-color:rgb(30,30,30) }"
0653                 "QTableCornerButton::section{ background-color:rgb(30,30,30) }"
0654                 "");
0655             qDebug() << Q_FUNC_INFO << "stylesheet set";
0656 #endif
0657         }
0658         else
0659         {
0660             if (KStars::Instance()->wiView())
0661                 KStars::Instance()->wiView()->setNightVisionOn(false);
0662             QApplication::setPalette(OriginalPalette);
0663 #ifdef Q_OS_OSX
0664             qDebug() << Q_FUNC_INFO << "setting light stylesheet";
0665             qApp->setStyleSheet("");
0666             qDebug() << Q_FUNC_INFO << "stylesheet set";
0667 #endif
0668         }
0669     }
0670 #endif
0671 
0672     Options::setColorSchemeFile(name);
0673 
0674     emit colorSchemeChanged();
0675 
0676     map()->forceUpdate();
0677 }
0678 
0679 void KStars::exportImage(const QString &url, int w, int h, bool includeLegend)
0680 {
0681     ImageExporter *m_ImageExporter = m_KStarsData->imageExporter();
0682 
0683     if (w <= 0)
0684         w = map()->width();
0685     if (h <= 0)
0686         h = map()->height();
0687 
0688     QSize size(w, h);
0689 
0690     m_ImageExporter->includeLegend(includeLegend);
0691     m_ImageExporter->setRasterOutputSize(&size);
0692     m_ImageExporter->exportImage(url);
0693 }
0694 
0695 QString KStars::getDSSURL(const QString &objectName)
0696 {
0697     SkyObject *target = data()->objectNamed(objectName);
0698     if (!target)
0699     {
0700         return QString("ERROR");
0701     }
0702     else
0703     {
0704         return KSDssDownloader::getDSSURL(target);
0705     }
0706 }
0707 
0708 QString KStars::getDSSURL(double RA_J2000, double Dec_J2000, float width, float height)
0709 {
0710     dms ra(RA_J2000), dec(Dec_J2000);
0711     return KSDssDownloader::getDSSURL(ra, dec, width, height);
0712 }
0713 
0714 QString KStars::getObjectDataXML(const QString &objectName, bool fallbackToInternet, bool storeInternetResolved)
0715 {
0716     bool deleteTargetAfterUse = false;
0717     const SkyObject *target = data()->objectNamed(objectName);
0718     if (!target && fallbackToInternet)
0719     {
0720         if (!storeInternetResolved)
0721         {
0722             const auto &cedata = NameResolver::resolveName(objectName);
0723             if (cedata.first)
0724             {
0725                 target = cedata.second.clone(); // We have to free this since we own the pointer
0726                 deleteTargetAfterUse = true; // so note that down
0727             }
0728         }
0729         else
0730         {
0731             CatalogsDB::DBManager db_manager { CatalogsDB::dso_db_path() };
0732             target = FindDialog::resolveAndAdd(db_manager, objectName);
0733         }
0734 
0735     }
0736     if (!target)
0737     {
0738         return QString("<xml></xml>");
0739     }
0740     QString output;
0741     QXmlStreamWriter stream(&output);
0742     stream.setAutoFormatting(true);
0743     stream.writeStartDocument();
0744     stream.writeStartElement("object");
0745     stream.writeTextElement("Name", target->name());
0746     stream.writeTextElement("Alt_Name", target->name2());
0747     stream.writeTextElement("Long_Name", target->longname());
0748     stream.writeTextElement("Constellation",
0749                             KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(target));
0750     stream.writeTextElement("RA_Dec_Epoch_JD", QString::number(target->getLastPrecessJD(), 'f', 3));
0751     stream.writeTextElement("RA_HMS", target->ra().toHMSString());
0752     stream.writeTextElement("Dec_DMS", target->dec().toDMSString());
0753     stream.writeTextElement("RA_J2000_HMS", target->ra0().toHMSString());
0754     stream.writeTextElement("Dec_J2000_DMS", target->dec0().toDMSString());
0755     stream.writeTextElement("RA_Degrees", QString::number(target->ra().Degrees()));
0756     stream.writeTextElement("Dec_Degrees", QString::number(target->dec().Degrees()));
0757     stream.writeTextElement("RA_J2000_Degrees", QString::number(target->ra0().Degrees()));
0758     stream.writeTextElement("Dec_J2000_Degrees", QString::number(target->dec0().Degrees()));
0759     stream.writeTextElement("Type", target->typeName());
0760     stream.writeTextElement("Magnitude", QString::number(target->mag(), 'g', 2));
0761     stream.writeTextElement("Position_Angle", QString::number(target->pa(), 'g', 3));
0762     auto *star = dynamic_cast<const StarObject *>(target);
0763     auto *dso = dynamic_cast<const CatalogObject *>(target);
0764     if (star)
0765     {
0766         stream.writeTextElement("Spectral_Type", star->sptype());
0767         stream.writeTextElement("Genetive_Name", star->gname());
0768         stream.writeTextElement("Greek_Letter", star->greekLetter());
0769         stream.writeTextElement("Proper_Motion", QString::number(star->pmMagnitude()));
0770         stream.writeTextElement("Proper_Motion_RA", QString::number(star->pmRA()));
0771         stream.writeTextElement("Proper_Motion_Dec", QString::number(star->pmDec()));
0772         stream.writeTextElement("Parallax_mas", QString::number(star->parallax()));
0773         stream.writeTextElement("Distance_pc", QString::number(star->distance()));
0774         stream.writeTextElement("Henry_Draper", QString::number(star->getHDIndex()));
0775         stream.writeTextElement("BV_Index", QString::number(star->getBVIndex()));
0776     }
0777     else if (dso)
0778     {
0779         stream.writeTextElement("Catalog", dso->getCatalog().name);
0780         stream.writeTextElement("Major_Axis", QString::number(dso->a()));
0781         stream.writeTextElement("Minor_Axis", QString::number(dso->a() * dso->e()));
0782     }
0783     stream.writeEndElement(); // object
0784     stream.writeEndDocument();
0785 
0786     if (deleteTargetAfterUse)
0787     {
0788         Q_ASSERT(!!target);
0789         delete target;
0790     }
0791 
0792     return output;
0793 }
0794 
0795 QString KStars::getObjectPositionInfo(const QString &objectName)
0796 {
0797     Q_ASSERT(data());
0798     const SkyObject *obj = data()->objectNamed(objectName); // make sure we work with a clone
0799     if (!obj)
0800     {
0801         return QString("<xml></xml>");
0802     }
0803     SkyObject *target = obj->clone();
0804     if (!target) // should not happen
0805     {
0806         qWarning() << "ERROR: Could not clone SkyObject " << objectName << "!";
0807         return QString("<xml></xml>");
0808     }
0809 
0810     const KSNumbers *updateNum = data()->updateNum();
0811     const KStarsDateTime ut    = data()->ut();
0812     const GeoLocation *geo     = data()->geo();
0813     QString riseTimeString, setTimeString, transitTimeString;
0814     QString riseAzString, setAzString, transitAltString;
0815 
0816     // Make sure the coordinates of the SkyObject are updated
0817     target->updateCoords(updateNum, true, geo->lat(), data()->lst(), true);
0818     target->EquatorialToHorizontal(data()->lst(), geo->lat());
0819 
0820     // Compute rise, set and transit times and parameters -- Code pulled from DetailDialog
0821     QTime riseTime    = target->riseSetTime(ut, geo, true);   //true = use rise time
0822     dms riseAz        = target->riseSetTimeAz(ut, geo, true); //true = use rise time
0823     QTime transitTime = target->transitTime(ut, geo);
0824     dms transitAlt    = target->transitAltitude(ut, geo);
0825     if (transitTime < riseTime)
0826     {
0827         transitTime = target->transitTime(ut.addDays(1), geo);
0828         transitAlt  = target->transitAltitude(ut.addDays(1), geo);
0829     }
0830     //If set time is before rise time, use set time for tomorrow
0831     QTime setTime = target->riseSetTime(ut, geo, false);   //false = use set time
0832     dms setAz     = target->riseSetTimeAz(ut, geo, false); //false = use set time
0833     if (setTime < riseTime)
0834     {
0835         setTime = target->riseSetTime(ut.addDays(1), geo, false);   //false = use set time
0836         setAz   = target->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time
0837     }
0838     if (riseTime.isValid())
0839     {
0840         riseTimeString = QString::asprintf("%02d:%02d", riseTime.hour(), riseTime.minute());
0841         setTimeString  = QString::asprintf("%02d:%02d", setTime.hour(), setTime.minute());
0842         riseAzString   = riseAz.toDMSString(true, true);
0843         setAzString    = setAz.toDMSString(true, true);
0844     }
0845     else
0846     {
0847         if (target->alt().Degrees() > 0.0)
0848         {
0849             riseTimeString = setTimeString = QString("Circumpolar");
0850         }
0851         else
0852         {
0853             riseTimeString = setTimeString = QString("Never Rises");
0854         }
0855         riseAzString = setAzString = QString("N/A");
0856     }
0857 
0858     transitTimeString = QString::asprintf("%02d:%02d", transitTime.hour(), transitTime.minute());
0859     transitAltString  = transitAlt.toDMSString(true, true);
0860 
0861     QString output;
0862     QXmlStreamWriter stream(&output);
0863     stream.setAutoFormatting(true);
0864     stream.writeStartDocument();
0865     stream.writeStartElement("object");
0866     stream.writeTextElement("Name", target->name());
0867     stream.writeTextElement("RA_Dec_Epoch_JD", QString::number(target->getLastPrecessJD(), 'f', 3));
0868     stream.writeTextElement("AltAz_JD", QString::number(data()->ut().djd(), 'f', 3));
0869     stream.writeTextElement("RA_HMS", target->ra().toHMSString(true));
0870     stream.writeTextElement("Dec_DMS", target->dec().toDMSString(true, true));
0871     stream.writeTextElement("RA_J2000_HMS", target->ra0().toHMSString(true));
0872     stream.writeTextElement("Dec_J2000_DMS", target->dec0().toDMSString(true, true));
0873     stream.writeTextElement("RA_Degrees", QString::number(target->ra().Degrees()));
0874     stream.writeTextElement("Dec_Degrees", QString::number(target->dec().Degrees()));
0875     stream.writeTextElement("RA_J2000_Degrees", QString::number(target->ra0().Degrees()));
0876     stream.writeTextElement("Dec_J2000_Degrees", QString::number(target->dec0().Degrees()));
0877     stream.writeTextElement("Altitude_DMS", target->alt().toDMSString(true, true));
0878     stream.writeTextElement("Azimuth_DMS", target->az().toDMSString(true, true));
0879     stream.writeTextElement("Altitude_Degrees", QString::number(target->alt().Degrees()));
0880     stream.writeTextElement("Azimuth_Degrees", QString::number(target->az().Degrees()));
0881     stream.writeTextElement("Rise", riseTimeString);
0882     stream.writeTextElement("Rise_Az_DMS", riseAzString);
0883     stream.writeTextElement("Set", setTimeString);
0884     stream.writeTextElement("Set_Az_DMS", setAzString);
0885     stream.writeTextElement("Transit", transitTimeString);
0886     stream.writeTextElement("Transit_Alt_DMS", transitAltString);
0887     stream.writeTextElement("Time_Zone_Offset", QString::asprintf("%02.2f", geo->TZ()));
0888 
0889     stream.writeEndElement(); // object
0890     stream.writeEndDocument();
0891     return output;
0892 }
0893 
0894 void KStars::renderEyepieceView(const QString &objectName, const QString &destPathChart, const double fovWidth,
0895                                 const double fovHeight, const double rotation, const double scale, const bool flip,
0896                                 const bool invert, QString imagePath, const QString &destPathImage, const bool overlay,
0897                                 const bool invertColors)
0898 {
0899     const SkyObject *obj = data()->objectNamed(objectName);
0900     if (!obj)
0901     {
0902         qCWarning(KSTARS) << "Object named " << objectName << " was not found!";
0903         return;
0904     }
0905     SkyObject *target          = obj->clone();
0906     const KSNumbers *updateNum = data()->updateNum();
0907     const KStarsDateTime ut    = data()->ut();
0908     const GeoLocation *geo     = data()->geo();
0909     QPixmap *renderChart       = new QPixmap();
0910     QPixmap *renderImage       = nullptr;
0911     QTemporaryFile tempFile;
0912     if (overlay || (!destPathImage.isEmpty()))
0913     {
0914         if (!QFile::exists(imagePath))
0915         {
0916             // We must download a DSS image
0917             tempFile.open();
0918             QEventLoop loop;
0919             std::function<void(bool)> slot = [&loop](bool unused)
0920             {
0921                 Q_UNUSED(unused);
0922                 loop.quit();
0923             };
0924             new KSDssDownloader(target, tempFile.fileName(), slot, this);
0925             qDebug() << Q_FUNC_INFO << "DSS download requested. Waiting for download to complete...";
0926             loop.exec(); // wait for download to complete
0927             imagePath = tempFile.fileName();
0928         }
0929         if (QFile::exists(imagePath)) // required because DSS Download may fail
0930             renderImage = new QPixmap();
0931     }
0932 
0933     // Make sure the coordinates of the SkyObject are updated
0934     target->updateCoords(updateNum, true, geo->lat(), data()->lst(), true);
0935     target->EquatorialToHorizontal(data()->lst(), geo->lat());
0936 
0937     EyepieceField::renderEyepieceView(target, renderChart, fovWidth, fovHeight, rotation, scale, flip, invert,
0938                                       imagePath, renderImage, overlay, invertColors);
0939     renderChart->save(destPathChart);
0940     delete renderChart;
0941     if (renderImage)
0942     {
0943         renderImage->save(destPathImage);
0944         delete renderImage;
0945     }
0946 }
0947 QString KStars::getObservingWishListObjectNames()
0948 {
0949     QString output;
0950 
0951     for (auto &object : KStarsData::Instance()->observingList()->obsList())
0952     {
0953         output.append(object->name() + '\n');
0954     }
0955     return output;
0956 }
0957 
0958 QString KStars::getObservingSessionPlanObjectNames()
0959 {
0960     QString output;
0961 
0962     for (auto &object : KStarsData::Instance()->observingList()->sessionList())
0963     {
0964         output.append(object->name() + '\n');
0965     }
0966     return output;
0967 }
0968 
0969 void KStars::setApproxFOV(double FOV_Degrees)
0970 {
0971     zoom(map()->width() / (FOV_Degrees * dms::DegToRad));
0972 }
0973 
0974 QString KStars::getSkyMapDimensions()
0975 {
0976     return (QString::number(map()->width()) + 'x' + QString::number(map()->height()));
0977 }
0978 void KStars::printImage(bool usePrintDialog, bool useChartColors)
0979 {
0980     //QPRINTER_FOR_NOW
0981     //    KPrinter printer( true, QPrinter::HighResolution );
0982     QPrinter printer(QPrinter::HighResolution);
0983     printer.setFullPage(false);
0984 
0985     //Set up the printer (either with the Print Dialog,
0986     //or using the default settings)
0987     bool ok(false);
0988     if (usePrintDialog)
0989     {
0990         //QPRINTER_FOR_NOW
0991         //        ok = printer.setup( this, i18n("Print Sky") );
0992         //QPrintDialog *dialog = KdePrint::createPrintDialog(&printer, this);
0993         QPrintDialog *dialog = new QPrintDialog(&printer, this);
0994         dialog->setWindowTitle(i18nc("@title:window", "Print Sky"));
0995         if (dialog->exec() == QDialog::Accepted)
0996             ok = true;
0997         delete dialog;
0998     }
0999     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 
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 }