Warning, file /education/kstars/kstars/dialogs/detaildialog.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2002 Jason Harris and Jasem Mutlaq <kstars@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "detaildialog.h"
0008 
0009 #include "config-kstars.h"
0010 
0011 #include "addlinkdialog.h"
0012 #include "kspaths.h"
0013 #include "ksnotification.h"
0014 #include "kstarsdata.h"
0015 #include "observinglist.h"
0016 #include "skymap.h"
0017 #include "skyobjectuserdata.h"
0018 #include "thumbnailpicker.h"
0019 #include "skycomponents/constellationboundarylines.h"
0020 #include "skycomponents/skymapcomposite.h"
0021 #include "catalogobject.h"
0022 #include "skyobjects/ksasteroid.h"
0023 #include "skyobjects/kscomet.h"
0024 #include "skyobjects/ksmoon.h"
0025 #include "skyobjects/starobject.h"
0026 #include "skyobjects/supernova.h"
0027 #include "catalogsdb.h"
0028 #include "Options.h"
0029 
0030 #ifdef HAVE_INDI
0031 #include "indi/indilistener.h"
0032 #include "indi/indimount.h"
0033 #endif
0034 
0035 #include <QDesktopServices>
0036 #include <QDir>
0037 
0038 DetailDialog::DetailDialog(SkyObject *o, const KStarsDateTime &ut, GeoLocation *geo,
0039                            QWidget *parent)
0040     : KPageDialog(parent), selectedObject(o), Data(nullptr), DataComet(nullptr),
0041       Pos(nullptr), Links(nullptr), Adv(nullptr),
0042       Log(nullptr), m_user_data{ KStarsData::Instance()->getUserData(o->name()) }
0043 {
0044 #ifdef Q_OS_OSX
0045     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0046 #endif
0047     setFaceType(Tabbed);
0048     setBackgroundRole(QPalette::Base);
0049 
0050     titlePalette = palette();
0051     titlePalette.setColor(backgroundRole(), palette().color(QPalette::Active, QPalette::Highlight));
0052     titlePalette.setColor(foregroundRole(), palette().color(QPalette::Active, QPalette::HighlightedText));
0053 
0054     //Create thumbnail image
0055     Thumbnail.reset(new QPixmap(200, 200));
0056 
0057     setWindowTitle(i18nc("@title:window", "Object Details"));
0058 
0059     // JM 2016-11-22: Do we really need a close button?
0060     //setStandardButtons(QDialogButtonBox::Close);
0061     setStandardButtons(QDialogButtonBox::NoButton);
0062 
0063     createGeneralTab();
0064     createPositionTab(ut, geo);
0065     createLinksTab();
0066     createAdvancedTab();
0067     createLogTab();
0068 }
0069 
0070 void DetailDialog::createGeneralTab()
0071 {
0072     Data = new DataWidget(this);
0073     addPage(Data, i18n("General"));
0074 
0075     Data->Names->setPalette(titlePalette);
0076 
0077     //Connections
0078     connect(Data->ObsListButton, SIGNAL(clicked()), this, SLOT(addToObservingList()));
0079     connect(Data->CenterButton, SIGNAL(clicked()), this, SLOT(centerMap()));
0080 #ifdef HAVE_INDI
0081     connect(Data->ScopeButton, SIGNAL(clicked()), this, SLOT(centerTelescope()));
0082 #else
0083     Data->ScopeButton->setEnabled(false);
0084 #endif
0085     connect(Data->Image, SIGNAL(clicked()), this, SLOT(updateThumbnail()));
0086 
0087     // Stuff that should be visible only for specific types of objects
0088     Data->IllumLabel->setVisible(false); // Only shown for the moon
0089     Data->Illumination->setVisible(false);
0090 
0091     Data->BVIndex->setVisible(false); // Only shown for stars
0092     Data->BVLabel->setVisible(false);
0093 
0094     Data->CatalogLabel->setVisible(false);
0095 
0096     //Show object thumbnail image
0097     showThumbnail();
0098 
0099     //Fill in the data fields
0100     //Contents depend on type of object
0101     QString objecttyp;
0102 
0103     switch (selectedObject->type())
0104     {
0105         case SkyObject::STAR:
0106         {
0107             StarObject *s = (StarObject *)selectedObject;
0108 
0109             if (s->getHDIndex())
0110             {
0111                 Data->Names->setText(
0112                     QString("%1, HD %2").arg(s->longname()).arg(s->getHDIndex()));
0113             }
0114             else
0115             {
0116                 Data->Names->setText(s->longname());
0117             }
0118 
0119             objecttyp = i18n("%1 star", s->sptype());
0120             Data->Magnitude->setText(
0121                 i18nc("number in magnitudes", "%1 mag",
0122                       QLocale().toString(s->mag(), 'f', 2))); //show to hundredth place
0123 
0124             Data->BVLabel->setVisible(true);
0125             Data->BVIndex->setVisible(true);
0126             if (s->getBVIndex() < 30.)
0127             {
0128                 Data->BVIndex->setText(QString::number(s->getBVIndex(), 'f', 2));
0129             }
0130 
0131             //The thumbnail image is empty, and isn't clickable for stars
0132             //Also, don't show the border around the Image QFrame.
0133             Data->Image->setFrameStyle(QFrame::NoFrame);
0134             disconnect(Data->Image, SIGNAL(clicked()), this, SLOT(updateThumbnail()));
0135 
0136             //distance
0137             if (s->distance() > 2000. || s->distance() < 0.) // parallax < 0.5 mas
0138             {
0139                 Data->Distance->setText(
0140                     QString(i18nc("larger than 2000 parsecs", "> 2000 pc")));
0141             }
0142             else if (s->distance() > 50.) //show to nearest integer
0143             {
0144                 Data->Distance->setText(i18nc("number in parsecs", "%1 pc",
0145                                               QLocale().toString(s->distance(), 'f', 0)));
0146             }
0147             else if (s->distance() > 10.0) //show to tenths place
0148             {
0149                 Data->Distance->setText(i18nc("number in parsecs", "%1 pc",
0150                                               QLocale().toString(s->distance(), 'f', 1)));
0151             }
0152             else //show to hundredths place
0153             {
0154                 Data->Distance->setText(i18nc("number in parsecs", "%1 pc",
0155                                               QLocale().toString(s->distance(), 'f', 2)));
0156             }
0157 
0158             //Note multiplicity/variability in angular size label
0159             Data->AngSizeLabel->setText(QString());
0160             Data->AngSize->setText(QString());
0161             Data->AngSizeLabel->setFont(Data->AngSize->font());
0162             if (s->isMultiple() && s->isVariable())
0163             {
0164                 Data->AngSizeLabel->setText(
0165                     i18nc("the star is a multiple star", "multiple") + ',');
0166                 Data->AngSize->setText(i18nc("the star is a variable star", "variable"));
0167             }
0168             else if (s->isMultiple())
0169             {
0170                 Data->AngSizeLabel->setText(
0171                     i18nc("the star is a multiple star", "multiple"));
0172             }
0173             else if (s->isVariable())
0174             {
0175                 Data->AngSizeLabel->setText(
0176                     i18nc("the star is a variable star", "variable"));
0177             }
0178 
0179             // Add a label to indicate proper motion
0180             double pmRA = s->pmRA(), pmDec = s->pmDec();
0181             if (std::isfinite(pmRA) && std::isfinite(pmDec) && (pmRA != 0.0 || pmDec != 0.0))
0182             {
0183                 // we have data : abuse the illumination label to show it!
0184                 Data->IllumLabel->setText(i18nc("Proper motion of a star", "Proper Motion:"));
0185                 Data->Illumination->setText(
0186                     i18nc(
0187                         "The first arg is proper motion in right ascension and the second in the declination. The unit stands for milliarcsecond per year",
0188                         "%1 %2 mas/yr",
0189                         QLocale().toString(pmRA, 'f', (pmRA >= 100.0 ? 1 :  2)),
0190                         QLocale().toString(pmDec, 'f', (pmDec >= 100.0 ? 1 : 2))
0191                     ));
0192                 Data->IllumLabel->setVisible(true);
0193                 Data->Illumination->setVisible(true);
0194             }
0195 
0196             break; //end of stars case
0197         }
0198         case SkyObject::ASTEROID: //[fall through to planets]
0199         case SkyObject::COMET:    //[fall through to planets]
0200         case SkyObject::MOON:     //[fall through to planets]
0201         case SkyObject::PLANET:
0202         {
0203             KSPlanetBase *ps = dynamic_cast<KSPlanetBase *>(selectedObject);
0204 
0205             if (!ps)
0206                 break;
0207 
0208             Data->Names->setText(ps->longname());
0209 
0210             //Type is "G5 star" for Sun
0211             if (ps->name() == i18n("Sun"))
0212             {
0213                 objecttyp = i18n("G5 star");
0214             }
0215             else if (ps->name() == i18n("Moon"))
0216             {
0217                 objecttyp = ps->translatedName();
0218             }
0219             else if (ps->name() == i18nc("Asteroid name (optional)", "Pluto") ||
0220                      ps->name() == i18nc("Asteroid name (optional)", "Ceres") ||
0221                      ps->name() == i18nc("Asteroid name (optional)", "Eris"))
0222             {
0223                 objecttyp = i18n("Dwarf planet");
0224             }
0225             else
0226             {
0227                 objecttyp = ps->typeName();
0228             }
0229 
0230             //The moon displays illumination fraction and updateMag is called to calculate moon's current magnitude
0231             if (selectedObject->name() == i18n("Moon"))
0232             {
0233                 Data->IllumLabel->setVisible(true);
0234                 Data->Illumination->setVisible(true);
0235                 Data->Illumination->setText(QString("%1 %").arg(QLocale().toString(
0236                                                 ((KSMoon *)selectedObject)->illum() * 100., 'f', 0)));
0237                 ((KSMoon *)selectedObject)->updateMag();
0238             }
0239 
0240             // JM: Shouldn't we use the calculated magnitude? Disabling the following
0241             /*
0242             if(selectedObject->type() == SkyObject::COMET){
0243                 Data->Magnitude->setText(i18nc("number in magnitudes", "%1 mag",
0244                                          QLocale().toString( ((KSComet *)selectedObject)->getTotalMagnitudeParameter(), 'f', 2)));  //show to hundredth place
0245 
0246             }
0247             else{*/
0248             Data->Magnitude->setText(
0249                 i18nc("number in magnitudes", "%1 mag",
0250                       QLocale().toString(ps->mag(), 'f', 2))); //show to hundredth place
0251             //}
0252 
0253             //Distance from Earth.  The moon requires a unit conversion
0254             if (ps->name() == i18n("Moon"))
0255             {
0256                 Data->Distance->setText(
0257                     i18nc("distance in kilometers", "%1 km",
0258                           QLocale().toString(ps->rearth() * AU_KM, 'f', 2)));
0259             }
0260             else
0261             {
0262                 Data->Distance->setText(i18nc("distance in Astronomical Units", "%1 AU",
0263                                               QLocale().toString(ps->rearth(), 'f', 3)));
0264             }
0265 
0266             //Angular size; moon and sun in arcmin, others in arcsec
0267             if (ps->angSize())
0268             {
0269                 if (ps->name() == i18n("Sun") || ps->name() == i18n("Moon"))
0270                 {
0271                     Data->AngSize->setText(i18nc(
0272                                                "angular size in arcminutes", "%1 arcmin",
0273                                                QLocale().toString(
0274                                                    ps->angSize(), 'f',
0275                                                    1))); // Needn't be a plural form because sun / moon will never contract to 1 arcminute
0276                 }
0277                 else
0278                 {
0279                     Data->AngSize->setText(
0280                         i18nc("angular size in arcseconds", "%1 arcsec",
0281                               QLocale().toString(ps->angSize() * 60.0, 'f', 1)));
0282                 }
0283             }
0284             else
0285             {
0286                 Data->AngSize->setText("--");
0287             }
0288 
0289             break; //end of planets/comets/asteroids case
0290         }
0291         case SkyObject::SUPERNOVA:
0292         {
0293             Supernova *sup = dynamic_cast<Supernova *>(selectedObject);
0294 
0295             objecttyp = i18n("Supernova");
0296             Data->Names->setText(sup->name());
0297             if (sup->mag() < 99)
0298                 Data->Magnitude->setText(i18nc("number in magnitudes", "%1 mag",
0299                                                QLocale().toString(sup->mag(), 'f', 2)));
0300             else
0301                 Data->Magnitude->setText("--");
0302 
0303             Data->DistanceLabel->setVisible(false);
0304             Data->Distance->setVisible(false);
0305 
0306             Data->AngSizeLabel->setVisible(false);
0307             Data->AngSize->setVisible(false);
0308 
0309             QLabel *discoveryDateLabel = new QLabel(i18n("Discovery Date:"), this);
0310             QLabel *discoveryDate      = new QLabel(sup->getDate(), this);
0311             Data->dataGridLayout->addWidget(discoveryDateLabel, 1, 0);
0312             Data->dataGridLayout->addWidget(discoveryDate, 1, 1);
0313 
0314             QLabel *typeLabel = new QLabel(i18n("Type:"), this);
0315             QLabel *type      = new QLabel(sup->getType(), this);
0316             Data->dataGridLayout->addWidget(typeLabel, 2, 0);
0317             Data->dataGridLayout->addWidget(type, 2, 1);
0318 
0319             QLabel *hostGalaxyLabel = new QLabel(i18n("Host Galaxy:"), this);
0320             QLabel *hostGalaxy      = new QLabel(
0321                 sup->getHostGalaxy().isEmpty() ? "--" : sup->getHostGalaxy(), this);
0322             Data->dataGridLayout->addWidget(hostGalaxyLabel, 3, 0);
0323             Data->dataGridLayout->addWidget(hostGalaxy, 3, 1);
0324 
0325             QLabel *redShiftLabel = new QLabel(i18n("Red Shift:"), this);
0326             QLabel *redShift      = new QLabel(
0327                 (sup->getRedShift() < 99) ? QString::number(sup->getRedShift(), 'f', 2) :
0328                 QString("--"),
0329                 this);
0330             Data->dataGridLayout->addWidget(redShiftLabel, 4, 0);
0331             Data->dataGridLayout->addWidget(redShift, 4, 1);
0332 
0333             break;
0334         }
0335         default: //deep-sky objects
0336         {
0337             CatalogObject *dso = dynamic_cast<CatalogObject *>(selectedObject);
0338 
0339             if (!dso)
0340                 break;
0341 
0342             //Show all names recorded for the object
0343             QStringList nameList;
0344             if (!dso->longname().isEmpty() && dso->longname() != dso->name())
0345             {
0346                 nameList.append(dso->translatedLongName());
0347             }
0348 
0349             nameList.append(dso->translatedName());
0350 
0351             if (!dso->translatedName2().isEmpty())
0352             {
0353                 nameList.append(dso->translatedName2());
0354             }
0355 
0356             Data->Names->setText(nameList.join(","));
0357 
0358             objecttyp = dso->typeName();
0359 
0360             if (dso->type() == SkyObject::RADIO_SOURCE)
0361             {
0362                 Data->MagLabel->setText(
0363                     i18nc("integrated flux at a frequency", "Flux(%1):", 1));
0364                 Data->Magnitude->setText(i18nc("integrated flux value", "%1 %2",
0365                                                QLocale().toString(dso->flux(), 'f', 1),
0366                                                "obs")); //show to tenths place
0367             }
0368             else if (std::isnan(dso->mag()))
0369             {
0370                 Data->Magnitude->setText("--");
0371             }
0372             else
0373             {
0374                 Data->Magnitude->setText(
0375                     i18nc("number in magnitudes", "%1 mag",
0376                           QLocale().toString(dso->mag(), 'f', 1))); //show to tenths place
0377             }
0378 
0379             //No distances at this point...
0380             Data->Distance->setText("--");
0381 
0382             Data->CatalogLabel->setVisible(true);
0383             Data->Catalog->setText(dso->getCatalog().name);
0384 
0385             //Only show decimal place for small angular sizes
0386             if (dso->a() > 10.0)
0387             {
0388                 Data->AngSize->setText(i18nc("angular size in arcminutes", "%1 arcmin",
0389                                              QLocale().toString(dso->a(), 'f', 0)));
0390             }
0391             else if (dso->a())
0392             {
0393                 Data->AngSize->setText(i18nc("angular size in arcminutes", "%1 arcmin",
0394                                              QLocale().toString(dso->a(), 'f', 1)));
0395             }
0396             else
0397             {
0398                 Data->AngSize->setText("--");
0399             }
0400 
0401             break;
0402         }
0403     }
0404 
0405     // Add specifics data
0406     switch (selectedObject->type())
0407     {
0408         case SkyObject::ASTEROID:
0409         {
0410             KSAsteroid *ast = dynamic_cast<KSAsteroid *>(selectedObject);
0411             // Show same specifics data as comets
0412             DataComet = new DataCometWidget(this);
0413             Data->IncludeData->layout()->addWidget(DataComet);
0414 
0415             // Perihelion
0416             DataComet->Perihelion->setText(i18nc("Distance in astronomical units",
0417                                                  "%1 AU",
0418                                                  QString::number(ast->getPerihelion())));
0419             // Earth MOID
0420             if (ast->getEarthMOID() == 0)
0421                 DataComet->EarthMOID->setText("--");
0422             else
0423                 DataComet->EarthMOID->setText(
0424                     i18nc("Distance in astronomical units", "%1 AU",
0425                           QString::number(ast->getEarthMOID())));
0426             // Orbit ID
0427             DataComet->OrbitID->setText(ast->getOrbitID());
0428             // Orbit Class
0429             DataComet->OrbitClass->setText(ast->getOrbitClass());
0430             // NEO
0431             if (ast->isNEO())
0432                 DataComet->NEO->setText(i18n("Yes"));
0433             else
0434                 DataComet->NEO->setText(i18n("No"));
0435             // Albedo
0436             if (ast->getAlbedo() == 0.0)
0437                 DataComet->Albedo->setText("--");
0438             else
0439                 DataComet->Albedo->setText(QString::number(ast->getAlbedo()));
0440             // Diameter
0441             if (ast->getDiameter() == 0.0)
0442                 DataComet->Diameter->setText("--");
0443             else
0444                 DataComet->Diameter->setText(i18nc("Diameter in kilometers", "%1 km",
0445                                                    QString::number(ast->getDiameter())));
0446             // Dimensions
0447             if (ast->getDimensions().isEmpty())
0448                 DataComet->Dimensions->setText("--");
0449             else
0450                 DataComet->Dimensions->setText(
0451                     i18nc("Dimension in kilometers", "%1 km", ast->getDimensions()));
0452             // Rotation period
0453             if (ast->getRotationPeriod() == 0.0)
0454                 DataComet->Rotation->setText("--");
0455             else
0456                 DataComet->Rotation->setText(
0457                     i18nc("Rotation period in hours", "%1 h",
0458                           QString::number(ast->getRotationPeriod())));
0459             // Period
0460             if (ast->getPeriod() == 0.0)
0461                 DataComet->Period->setText("--");
0462             else
0463                 DataComet->Period->setText(i18nc("Orbit period in years", "%1 y",
0464                                                  QString::number(ast->getPeriod())));
0465             break;
0466         }
0467         case SkyObject::COMET:
0468         {
0469             KSComet *com = dynamic_cast<KSComet *>(selectedObject);
0470             DataComet    = new DataCometWidget(this);
0471             Data->IncludeData->layout()->addWidget(DataComet);
0472 
0473             // Perihelion
0474             DataComet->Perihelion->setText(i18nc("Distance in astronomical units",
0475                                                  "%1 AU",
0476                                                  QString::number(com->getPerihelion())));
0477             // Earth MOID
0478             if (com->getEarthMOID() == 0)
0479                 DataComet->EarthMOID->setText("--");
0480             else
0481                 DataComet->EarthMOID->setText(
0482                     i18nc("Distance in astronomical units", "%1 AU",
0483                           QString::number(com->getEarthMOID())));
0484             // Orbit ID
0485             DataComet->OrbitID->setText(com->getOrbitID());
0486             // Orbit Class
0487             DataComet->OrbitClass->setText(com->getOrbitClass());
0488             // NEO
0489             if (com->isNEO())
0490                 DataComet->NEO->setText(i18n("Yes"));
0491             else
0492                 DataComet->NEO->setText(i18n("No"));
0493             // Albedo
0494             if (com->getAlbedo() == 0.0)
0495                 DataComet->Albedo->setText("--");
0496             else
0497                 DataComet->Albedo->setText(QString::number(com->getAlbedo()));
0498             // Diameter
0499             if (com->getDiameter() == 0.0)
0500                 DataComet->Diameter->setText("--");
0501             else
0502                 DataComet->Diameter->setText(i18nc("Diameter in kilometers", "%1 km",
0503                                                    QString::number(com->getDiameter())));
0504             // Dimensions
0505             if (com->getDimensions().isEmpty())
0506                 DataComet->Dimensions->setText("--");
0507             else
0508                 DataComet->Dimensions->setText(
0509                     i18nc("Dimension in kilometers", "%1 km", com->getDimensions()));
0510             // Rotation period
0511             if (com->getRotationPeriod() == 0.0)
0512                 DataComet->Rotation->setText("--");
0513             else
0514                 DataComet->Rotation->setText(
0515                     i18nc("Rotation period in hours", "%1 h",
0516                           QString::number(com->getRotationPeriod())));
0517             // Period
0518             if (com->getPeriod() == 0.0)
0519                 DataComet->Period->setText("--");
0520             else
0521                 DataComet->Period->setText(i18nc("Orbit period in years", "%1 y",
0522                                                  QString::number(com->getPeriod())));
0523             break;
0524         }
0525     }
0526 
0527     //Common to all types:
0528     QString cname = KStarsData::Instance()
0529                     ->skyComposite()
0530                     ->constellationBoundary()
0531                     ->constellationName(selectedObject);
0532     if (selectedObject->type() != SkyObject::CONSTELLATION)
0533     {
0534         cname = i18nc(
0535                     "%1 type of sky object (planet, asteroid etc), %2 name of a constellation",
0536                     "%1 in %2", objecttyp, cname);
0537     }
0538     Data->ObjectTypeInConstellation->setText(cname);
0539 }
0540 
0541 void DetailDialog::createPositionTab(const KStarsDateTime &ut, GeoLocation *geo)
0542 {
0543     Pos = new PositionWidget(this);
0544     addPage(Pos, i18n("Position"));
0545 
0546     Pos->CoordTitle->setPalette(titlePalette);
0547     Pos->RSTTitle->setPalette(titlePalette);
0548     KStarsData *data = KStarsData::Instance();
0549 
0550     //Coordinates Section:
0551     //Don't use KLocale::formatNumber() for the epoch string,
0552     //because we don't want a thousands-place separator!
0553     selectedObject->updateCoords(data->updateNum(), true, data->geo()->lat(), data->lst(), false);
0554     QString sEpoch = QString::number(KStarsDateTime::jdToEpoch(selectedObject->getLastPrecessJD()), 'f', 1);
0555     //Replace the decimal point with localized decimal symbol
0556     sEpoch.replace('.', QLocale().decimalPoint()); // Is this necessary? -- asimha Oct 2016
0557 
0558     /*qDebug() << Q_FUNC_INFO << (selectedObject->deprecess(data->updateNum())).ra0().toHMSString()
0559              << (selectedObject->deprecess(data->updateNum())).dec0().toDMSString();*/
0560     //qDebug() << Q_FUNC_INFO << selectedObject->ra().toHMSString() << selectedObject->dec().toDMSString();
0561     Pos->RALabel->setText(i18n("RA (%1):", sEpoch));
0562     Pos->DecLabel->setText(i18n("DE (%1):", sEpoch));
0563     Pos->RA->setText(selectedObject->ra().toHMSString(false, true));
0564     Pos->Dec->setText(selectedObject->dec().toDMSString(false, false, true));
0565 
0566     selectedObject->EquatorialToHorizontal(data->lst(), data->geo()->lat());
0567 
0568     Pos->Az->setText(selectedObject->az().toDMSString());
0569     dms a;
0570 
0571     if (Options::useAltAz())
0572         a = selectedObject->alt();
0573     else
0574         a = selectedObject->altRefracted();
0575     Pos->Alt->setText(a.toDMSString());
0576 
0577     // Display the RA0 and Dec0 for objects that are outside the solar system
0578     // 2017-09-10 JM: Exception added for asteroids and comets since we have J2000 for them.
0579     // Maybe others?
0580     Pos->RA0->setText(selectedObject->ra0().toHMSString(false, true));
0581     Pos->Dec0->setText(selectedObject->dec0().toDMSString(false, false, true));
0582 #if 0
0583     if (!selectedObject->isSolarSystem() || selectedObject->type() == SkyObject::COMET
0584             || selectedObject->type() == SkyObject::ASTEROID)
0585     {
0586         Pos->RA0->setText(selectedObject->ra0().toHMSString());
0587         Pos->Dec0->setText(selectedObject->dec0().toDMSString());
0588     }
0589     else
0590     {
0591         Pos->RA0->setText("--");
0592         Pos->Dec0->setText("--");
0593     }
0594 #endif
0595 
0596     //Hour Angle can be negative, but dms HMS expressions cannot.
0597     //Here's a kludgy workaround:
0598     dms lst = geo->GSTtoLST(ut.gst());
0599     dms ha(lst.Degrees() - selectedObject->ra().Degrees());
0600     QChar sgn('+');
0601     if (ha.Hours() > 12.0)
0602     {
0603         ha.setH(24.0 - ha.Hours());
0604         sgn = '-';
0605     }
0606     Pos->HA->setText(QString("%1%2").arg(sgn).arg(ha.toHMSString()));
0607 
0608     //Airmass is approximated as the secant of the zenith distance,
0609     //equivalent to 1./sin(Alt).  Beware of Inf at Alt=0!
0610     if (selectedObject->alt().Degrees() > 0.0)
0611         Pos->Airmass->setText(QLocale().toString(selectedObject->airmass(), 'f', 2));
0612     else
0613         Pos->Airmass->setText("--");
0614 
0615     //Rise/Set/Transit Section:
0616 
0617     //Prepare time/position variables
0618     QTime rt = selectedObject->riseSetTime(ut, geo, true);   //true = use rise time
0619     dms raz  = selectedObject->riseSetTimeAz(ut, geo, true); //true = use rise time
0620 
0621     //If transit time is before rise time, use transit time for tomorrow
0622     QTime tt = selectedObject->transitTime(ut, geo);
0623     dms talt = selectedObject->transitAltitude(ut, geo);
0624     if (tt < rt)
0625     {
0626         tt   = selectedObject->transitTime(ut.addDays(1), geo);
0627         talt = selectedObject->transitAltitude(ut.addDays(1), geo);
0628     }
0629 
0630     // JM 2021.09.14: Set time is already taken care of
0631     QTime st = selectedObject->riseSetTime(ut, geo, false);   //false = use set time
0632     dms saz  = selectedObject->riseSetTimeAz(ut, geo, false); //false = use set time
0633     //    if (st < rt)
0634     //    {
0635     //        st  = selectedObject->riseSetTime(ut.addDays(1), geo, false);   //false = use set time
0636     //        saz = selectedObject->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time
0637     //    }
0638 
0639     if (rt.isValid())
0640     {
0641         Pos->TimeRise->setText(QString::asprintf("%02d:%02d", rt.hour(), rt.minute()));
0642         Pos->TimeSet->setText(QString::asprintf("%02d:%02d", st.hour(), st.minute()));
0643         Pos->AzRise->setText(raz.toDMSString());
0644         Pos->AzSet->setText(saz.toDMSString());
0645     }
0646     else
0647     {
0648         if (selectedObject->alt().Degrees() > 0.0)
0649         {
0650             Pos->TimeRise->setText(i18n("Circumpolar"));
0651             Pos->TimeSet->setText(i18n("Circumpolar"));
0652         }
0653         else
0654         {
0655             Pos->TimeRise->setText(i18n("Never rises"));
0656             Pos->TimeSet->setText(i18n("Never rises"));
0657         }
0658 
0659         Pos->AzRise->setText(i18nc("Not Applicable", "N/A"));
0660         Pos->AzSet->setText(i18nc("Not Applicable", "N/A"));
0661     }
0662 
0663     Pos->TimeTransit->setText(QString::asprintf("%02d:%02d", tt.hour(), tt.minute()));
0664     Pos->AltTransit->setText(talt.toDMSString());
0665 
0666     // Restore the position and other time-dependent parameters
0667     selectedObject->recomputeCoords(ut, geo);
0668 }
0669 
0670 void DetailDialog::createLinksTab()
0671 {
0672     // don't create a link tab for an unnamed star
0673     if (selectedObject->name() == QString("star"))
0674         return;
0675 
0676     Links = new LinksWidget(this);
0677     addPage(Links, i18n("Links"));
0678 
0679     Links->InfoTitle->setPalette(titlePalette);
0680     Links->ImagesTitle->setPalette(titlePalette);
0681 
0682     for (const auto &link : m_user_data.websites())
0683         Links->InfoTitleList->addItem(i18nc("Image/info menu item (should be translated)",
0684                                             link.title.toLocal8Bit()));
0685 
0686     //Links->InfoTitleList->setCurrentRow(0);
0687 
0688     for (const auto &link : m_user_data.images())
0689         Links->ImageTitleList->addItem(i18nc(
0690                                            "Image/info menu item (should be translated)", link.title.toLocal8Bit()));
0691 
0692     // Signals/Slots
0693     connect(Links->ViewButton, SIGNAL(clicked()), this, SLOT(viewLink()));
0694     connect(Links->AddLinkButton, SIGNAL(clicked()), this, SLOT(addLink()));
0695     connect(Links->EditLinkButton, SIGNAL(clicked()), this, SLOT(editLinkDialog()));
0696     connect(Links->RemoveLinkButton, SIGNAL(clicked()), this, SLOT(removeLinkDialog()));
0697 
0698     // When an item is selected in info list, selected items are cleared image list.
0699     connect(Links->InfoTitleList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this,
0700             SLOT(setCurrentLink(QListWidgetItem*)));
0701     connect(Links->InfoTitleList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
0702             Links->ImageTitleList, SLOT(clearSelection()));
0703 
0704     // vice versa
0705     connect(Links->ImageTitleList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this,
0706             SLOT(setCurrentLink(QListWidgetItem*)));
0707     connect(Links->ImageTitleList, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
0708             Links->InfoTitleList, SLOT(clearSelection()));
0709 
0710     connect(Links->InfoTitleList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(viewLink()));
0711     connect(Links->ImageTitleList, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(viewLink()));
0712 
0713     connect(Links->InfoTitleList, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
0714     connect(Links->ImageTitleList, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
0715 
0716     updateLists();
0717 }
0718 
0719 void DetailDialog::addLink()
0720 {
0721     if (!selectedObject)
0722         return;
0723     QPointer<AddLinkDialog> adialog = new AddLinkDialog(this, selectedObject->name());
0724     QString entry;
0725     QFile file;
0726 
0727     if (adialog->exec() == QDialog::Accepted)
0728     {
0729         const auto &success = KStarsData::Instance()->addToUserData(
0730                                   selectedObject->name(),
0731                                   SkyObjectUserdata::LinkData
0732         {
0733             adialog->desc(), QUrl(adialog->url()),
0734             (adialog->isImageLink()) ? SkyObjectUserdata::LinkData::Type::image :
0735             SkyObjectUserdata::LinkData::Type::website });
0736 
0737         if (!success.first)
0738         {
0739             KSNotification::sorry(success.second, i18n("Could not add the link."));
0740         }
0741     }
0742 
0743     updateLists();
0744     delete adialog;
0745 }
0746 
0747 void DetailDialog::createAdvancedTab()
0748 {
0749     // Don't create an adv tab for an unnamed star or if advinterface file failed loading
0750     // We also don't need adv dialog for solar system objects.
0751     if (selectedObject->name() == QString("star") || KStarsData::Instance()->avdTree().isEmpty() ||
0752             selectedObject->type() == SkyObject::PLANET || selectedObject->type() == SkyObject::COMET ||
0753             selectedObject->type() == SkyObject::ASTEROID)
0754         return;
0755 
0756     Adv = new DatabaseWidget(this);
0757     addPage(Adv, i18n("Advanced"));
0758 
0759     connect(Adv->ADVTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(viewADVData()));
0760 
0761     populateADVTree();
0762 }
0763 
0764 void DetailDialog::createLogTab()
0765 {
0766     //Don't create a log tab for an unnamed star
0767     if (selectedObject->name() == QString("star"))
0768         return;
0769 
0770     // Log Tab
0771     Log = new LogWidget(this);
0772     addPage(Log, i18n("Log"));
0773 
0774     Log->LogTitle->setPalette(titlePalette);
0775 
0776     const auto &log = m_user_data.userLog;
0777 
0778     if (log.isEmpty())
0779         Log->UserLog->setText(i18n("Record here observation logs and/or data on %1.",
0780                                    selectedObject->translatedName()));
0781     else
0782         Log->UserLog->setText(log);
0783 
0784     //Automatically save the log contents when the widget loses focus
0785     connect(Log->UserLog, SIGNAL(focusOut()), this, SLOT(saveLogData()));
0786 }
0787 
0788 void DetailDialog::setCurrentLink(QListWidgetItem *it)
0789 {
0790     m_CurrentLink = it;
0791 }
0792 
0793 void DetailDialog::viewLink()
0794 {
0795     QString URL;
0796 
0797     if (m_CurrentLink == nullptr)
0798         return;
0799 
0800     if (m_CurrentLink->listWidget() == Links->InfoTitleList)
0801     {
0802         URL = m_user_data.websites()
0803               .at(Links->InfoTitleList->row(m_CurrentLink))
0804               .url.toString();
0805     }
0806     else if (m_CurrentLink->listWidget() == Links->ImageTitleList)
0807     {
0808         URL = m_user_data.images()
0809               .at(Links->ImageTitleList->row(m_CurrentLink))
0810               .url.toString();
0811     }
0812 
0813     if (!URL.isEmpty())
0814         QDesktopServices::openUrl(QUrl(URL));
0815 }
0816 
0817 void DetailDialog::updateLists()
0818 {
0819     Links->InfoTitleList->clear();
0820     Links->ImageTitleList->clear();
0821 
0822     for (const auto &element : m_user_data.websites())
0823         Links->InfoTitleList->addItem(element.title);
0824 
0825     for (const auto &element : m_user_data.images())
0826         Links->ImageTitleList->addItem(element.title);
0827 
0828     updateButtons();
0829 }
0830 
0831 void DetailDialog::updateButtons()
0832 {
0833     bool anyLink = false;
0834     if (!Links->InfoTitleList->selectedItems().isEmpty() || !Links->ImageTitleList->selectedItems().isEmpty())
0835         anyLink = true;
0836 
0837     // Buttons could be disabled if lists are initially empty, we enable and disable them here
0838     // depending on the current status of the list.
0839     Links->ViewButton->setEnabled(anyLink);
0840     Links->EditLinkButton->setEnabled(anyLink);
0841     Links->RemoveLinkButton->setEnabled(anyLink);
0842 }
0843 
0844 void DetailDialog::editLinkDialog()
0845 {
0846     SkyObjectUserdata::Type type = SkyObjectUserdata::Type::image;
0847     int row                      = 0;
0848 
0849     if (m_CurrentLink == nullptr)
0850         return;
0851 
0852     QDialog editDialog(this);
0853     editDialog.setWindowTitle(i18nc("@title:window", "Edit Link"));
0854 
0855     QVBoxLayout *mainLayout = new QVBoxLayout;
0856 
0857     QFrame editFrame(&editDialog);
0858 
0859     mainLayout->addWidget(&editFrame);
0860 
0861     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0862     mainLayout->addWidget(buttonBox);
0863     connect(buttonBox, SIGNAL(accepted()), &editDialog, SLOT(accept()));
0864     connect(buttonBox, SIGNAL(rejected()), &editDialog, SLOT(reject()));
0865 
0866     editDialog.setLayout(mainLayout);
0867 
0868     if (m_CurrentLink->listWidget() == Links->InfoTitleList)
0869     {
0870         row  = Links->InfoTitleList->row(m_CurrentLink);
0871         type = SkyObjectUserdata::Type::website;
0872     }
0873     else if (m_CurrentLink->listWidget() == Links->ImageTitleList)
0874     {
0875         row  = Links->ImageTitleList->row(m_CurrentLink);
0876         type = SkyObjectUserdata::Type::image;
0877     }
0878     else
0879         return;
0880 
0881     const auto &currentItem = m_user_data.links.at(type).at(row);
0882 
0883     QLineEdit editNameField(&editFrame);
0884     editNameField.setObjectName("nameedit");
0885     editNameField.home(false);
0886     editNameField.setText(currentItem.title);
0887     QLabel editLinkURL(i18n("URL:"), &editFrame);
0888     QLineEdit editLinkField(&editFrame);
0889     editLinkField.setObjectName("urledit");
0890     editLinkField.home(false);
0891     editLinkField.setText(currentItem.url.toString());
0892     QVBoxLayout vlay(&editFrame);
0893     vlay.setObjectName("vlay");
0894     QHBoxLayout editLinkLayout(&editFrame);
0895     editLinkLayout.setObjectName("editlinklayout");
0896     editLinkLayout.addWidget(&editLinkURL);
0897     editLinkLayout.addWidget(&editLinkField);
0898     vlay.addWidget(&editNameField);
0899     vlay.addLayout(&editLinkLayout);
0900 
0901     bool go(true);
0902     // If user presses cancel then skip the action
0903     if (editDialog.exec() != QDialog::Accepted)
0904         go = false;
0905 
0906     // If nothing changed, skip th action
0907     if (editLinkField.text() == currentItem.url.toString() &&
0908             editNameField.text() == currentItem.title)
0909         go = false;
0910 
0911     if (go)
0912     {
0913         const auto &success = KStarsData::Instance()->editUserData(
0914                                   selectedObject->name(), row,
0915         { editNameField.text(), QUrl{ editLinkField.text() }, type });
0916 
0917         if (!success.first)
0918             KSNotification::sorry(success.second, i18n("Could not edit the entry."));
0919 
0920         // Set focus to the same item again
0921         if (type == SkyObjectUserdata::Type::website)
0922             Links->InfoTitleList->setCurrentRow(row);
0923         else
0924             Links->ImageTitleList->setCurrentRow(row);
0925     }
0926 
0927     updateLists();
0928 }
0929 
0930 void DetailDialog::removeLinkDialog()
0931 {
0932     int row = 0;
0933     if (m_CurrentLink == nullptr)
0934         return;
0935 
0936     SkyObjectUserdata::Type type;
0937 
0938     if (m_CurrentLink->listWidget() == Links->InfoTitleList)
0939     {
0940         row  = Links->InfoTitleList->row(m_CurrentLink);
0941         type = SkyObjectUserdata::Type::website;
0942     }
0943     else if (m_CurrentLink->listWidget() == Links->ImageTitleList)
0944     {
0945         row  = Links->ImageTitleList->row(m_CurrentLink);
0946         type = SkyObjectUserdata::Type::image;
0947     }
0948     else
0949         return;
0950 
0951     if (KMessageBox::warningContinueCancel(
0952                 nullptr,
0953                 i18n("Are you sure you want to remove the %1 link?", m_CurrentLink->text()),
0954                 i18n("Delete Confirmation"),
0955                 KStandardGuiItem::del()) != KMessageBox::Continue)
0956         return;
0957 
0958     const auto &success =
0959         KStarsData::Instance()->deleteUserData(selectedObject->name(), row, type);
0960 
0961     if (!success.first)
0962         KSNotification::sorry(success.second, i18n("Could not delete the entry."));
0963 
0964     // Set focus to the 1st item in the list
0965     if (type == SkyObjectUserdata::LinkData::Type::website)
0966         Links->InfoTitleList->clearSelection();
0967     else
0968         Links->ImageTitleList->clearSelection();
0969 }
0970 
0971 void DetailDialog::populateADVTree()
0972 {
0973     QTreeWidgetItem *parent = nullptr;
0974     QTreeWidgetItem *temp   = nullptr;
0975 
0976     // We populate the tree iteratively, keeping track of parents as we go
0977     // This solution is more efficient than the previous recursion algorithm.
0978     foreach (ADVTreeData *item, KStarsData::Instance()->avdTree())
0979     {
0980         switch (item->Type)
0981         {
0982             // Top Level
0983             case 0:
0984                 temp = new QTreeWidgetItem(parent, QStringList(i18nc("Advanced URLs: description or category",
0985                                            item->Name.toLocal8Bit().data())));
0986                 if (parent == nullptr)
0987                     Adv->ADVTree->addTopLevelItem(temp);
0988                 parent = temp;
0989 
0990                 break;
0991 
0992             // End of top level
0993             case 1:
0994                 if (parent != nullptr)
0995                     parent = parent->parent();
0996                 break;
0997 
0998             // Leaf
0999             case 2:
1000                 new QTreeWidgetItem(parent, QStringList(i18nc("Advanced URLs: description or category", item->Name.toLocal8Bit().data())));
1001                 break;
1002         }
1003     }
1004 }
1005 
1006 void DetailDialog::viewADVData()
1007 {
1008     QString link;
1009     QTreeWidgetItem *current = Adv->ADVTree->currentItem();
1010 
1011     //If the item has children or is invalid, do nothing
1012     if (!current || current->childCount() > 0)
1013         return;
1014 
1015     foreach (ADVTreeData *item, KStarsData::Instance()->avdTree())
1016     {
1017         if (item->Name == current->text(0))
1018         {
1019             link = item->Link;
1020             link = parseADVData(link);
1021             QDesktopServices::openUrl(QUrl(link));
1022             return;
1023         }
1024     }
1025 }
1026 
1027 QString DetailDialog::parseADVData(const QString &inlink)
1028 {
1029     QString link = inlink;
1030     QString subLink;
1031     int index;
1032 
1033     if ((index = link.indexOf("KSOBJ")) != -1)
1034     {
1035         link.remove(index, 5);
1036         link = link.insert(index, selectedObject->name());
1037     }
1038 
1039     if ((index = link.indexOf("KSRA")) != -1)
1040     {
1041         link.remove(index, 4);
1042         subLink = QString::asprintf("%02d%02d%02d", selectedObject->ra0().hour(), selectedObject->ra0().minute(),
1043                                     selectedObject->ra0().second());
1044         subLink = subLink.insert(2, "%20");
1045         subLink = subLink.insert(7, "%20");
1046 
1047         link = link.insert(index, subLink);
1048     }
1049     if ((index = link.indexOf("KSDEC")) != -1)
1050     {
1051         link.remove(index, 5);
1052         if (selectedObject->dec().degree() < 0)
1053         {
1054             subLink = QString::asprintf("%03d%02d%02d", selectedObject->dec0().degree(), selectedObject->dec0().arcmin(),
1055                                         selectedObject->dec0().arcsec());
1056             subLink = subLink.insert(3, "%20");
1057             subLink = subLink.insert(8, "%20");
1058         }
1059         else
1060         {
1061             subLink = QString::asprintf("%02d%02d%02d", selectedObject->dec0().degree(), selectedObject->dec0().arcmin(),
1062                                         selectedObject->dec0().arcsec());
1063             subLink = subLink.insert(0, "%2B");
1064             subLink = subLink.insert(5, "%20");
1065             subLink = subLink.insert(10, "%20");
1066         }
1067         link = link.insert(index, subLink);
1068     }
1069 
1070     return link;
1071 }
1072 
1073 void DetailDialog::saveLogData()
1074 {
1075     const auto &success = KStarsData::Instance()->updateUserLog(
1076                               selectedObject->name(), Log->UserLog->toPlainText());
1077 
1078     if (!success.first)
1079         KSNotification::sorry(success.second, i18n("Could not update the user log."));
1080 }
1081 
1082 void DetailDialog::addToObservingList()
1083 {
1084     KStarsData::Instance()->observingList()->slotAddObject(selectedObject);
1085 }
1086 
1087 void DetailDialog::centerMap()
1088 {
1089     SkyMap::Instance()->setClickedObject(selectedObject);
1090     SkyMap::Instance()->slotCenter();
1091 }
1092 
1093 void DetailDialog::centerTelescope()
1094 {
1095 #ifdef HAVE_INDI
1096 
1097     if (INDIListener::Instance()->size() == 0)
1098     {
1099         KSNotification::sorry(i18n("No connected mounts found."));
1100         return;
1101     }
1102 
1103     for (auto &oneDevice : INDIListener::devices())
1104     {
1105         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
1106             continue;
1107 
1108         if (oneDevice->isConnected() == false)
1109         {
1110             KSNotification::error(i18n("Mount %1 is offline. Please connect and retry again.", oneDevice->getDeviceName()));
1111             return;
1112         }
1113 
1114         auto mount = oneDevice->getMount();
1115         if (!mount)
1116             continue;
1117 
1118         // Display Sun warning on slew
1119         if (selectedObject && selectedObject->name() == i18n("Sun"))
1120         {
1121             if (KMessageBox::warningContinueCancel(nullptr,
1122                                                    i18n("Danger! Viewing the Sun without adequate solar filters is dangerous and will result in permanent eye damage!"))
1123                     == KMessageBox::Cancel)
1124                 return;
1125         }
1126 
1127         mount->Slew(selectedObject);
1128         return;
1129     }
1130 
1131     KSNotification::sorry(i18n("No connected mounts found."));
1132 
1133 #endif
1134 }
1135 
1136 void DetailDialog::showThumbnail()
1137 {
1138     //No image if object is a star
1139     if (selectedObject->type() == SkyObject::STAR ||
1140             selectedObject->type() == SkyObject::CATALOG_STAR)
1141     {
1142         Thumbnail->scaled(Data->Image->width(), Data->Image->height());
1143         Thumbnail->fill(Data->DataFrame->palette().color(QPalette::Window));
1144         Data->Image->setPixmap(*Thumbnail);
1145         return;
1146     }
1147 
1148     //Try to load the object's image from disk
1149     //If no image found, load "no image" image
1150 
1151     const auto &base = KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
1152     QDirIterator search(base, QStringList() << "thumb*", QDir::Dirs);
1153 
1154     bool found = false;
1155     while (search.hasNext())
1156     {
1157         const auto &path =
1158             QDir(search.next())
1159             .absoluteFilePath(
1160                 "thumb-" + selectedObject->name().toLower().remove(' ').remove('/') +
1161                 ".png");
1162 
1163         const QFile file{ path };
1164         if (file.exists())
1165         {
1166             Thumbnail->load(path, "PNG");
1167             found = true;
1168         }
1169     }
1170 
1171     if (!found)
1172         Thumbnail->load(":/images/noimage.png");
1173 
1174     *Thumbnail = Thumbnail->scaled(Data->Image->width(), Data->Image->height(),
1175                                    Qt::KeepAspectRatio, Qt::FastTransformation);
1176 
1177     Data->Image->setPixmap(*Thumbnail);
1178 }
1179 
1180 void DetailDialog::updateThumbnail()
1181 {
1182     QPointer<ThumbnailPicker> tp = new ThumbnailPicker(selectedObject, *Thumbnail, this);
1183 
1184     if (tp->exec() == QDialog::Accepted)
1185     {
1186         QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).mkpath("thumbnails");
1187 
1188         QString const fname =
1189             QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
1190             .filePath("thumb-" + selectedObject->name().toLower().remove(' ').remove('/') + ".png");
1191 
1192         Data->Image->setPixmap(*(tp->image()));
1193 
1194         //If a real image was set, save it.
1195         //If the image was unset, delete the old image on disk.
1196         if (tp->imageFound())
1197         {
1198 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
1199             bool rc = Data->Image->pixmap()->save(fname, "PNG");
1200             if (rc == false)
1201             {
1202                 KSNotification::error(i18n("Unable to save image to %1", fname),
1203                                       i18n("Save Thumbnail"));
1204             }
1205             else
1206                 *Thumbnail = *(Data->Image->pixmap());
1207 #else
1208             bool rc = Data->Image->pixmap(Qt::ReturnByValue).save(fname, "PNG");
1209             if (rc == false)
1210             {
1211                 KSNotification::error(i18n("Unable to save image to %1", fname),
1212                                       i18n("Save Thumbnail"));
1213             }
1214             else
1215                 *Thumbnail = (Data->Image->pixmap(Qt::ReturnByValue));
1216 #endif
1217         }
1218         else
1219         {
1220             QFile f;
1221             f.setFileName(fname);
1222             f.remove();
1223         }
1224     }
1225     delete tp;
1226 }
1227 
1228 DataWidget::DataWidget(QWidget *p) : QFrame(p)
1229 {
1230     setupUi(this);
1231     DataFrame->setBackgroundRole(QPalette::Base);
1232 }
1233 
1234 DataCometWidget::DataCometWidget(QWidget *p) : QFrame(p)
1235 {
1236     setupUi(this);
1237 }
1238 
1239 PositionWidget::PositionWidget(QWidget *p) : QFrame(p)
1240 {
1241     setupUi(this);
1242     CoordFrame->setBackgroundRole(QPalette::Base);
1243     RSTFrame->setBackgroundRole(QPalette::Base);
1244 }
1245 
1246 LinksWidget::LinksWidget(QWidget *p) : QFrame(p)
1247 {
1248     setupUi(this);
1249 }
1250 
1251 DatabaseWidget::DatabaseWidget(QWidget *p) : QFrame(p)
1252 {
1253     setupUi(this);
1254 }
1255 
1256 LogWidget::LogWidget(QWidget *p) : QFrame(p)
1257 {
1258     setupUi(this);
1259 }