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 ¤tItem = 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 }