File indexing completed on 2024-04-21 14:46:30

0001 /*
0002     SPDX-FileCopyrightText: 2011 Rafał Kułaga <rl.kulaga@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "detailstable.h"
0008 
0009 #include <QTextDocument>
0010 #include <QTextTable>
0011 
0012 #include "kstars.h"
0013 #include "kstarsdata.h"
0014 #include "ksplanetbase.h"
0015 #include "starobject.h"
0016 #include "skymapcomposite.h"
0017 #include "constellationboundarylines.h"
0018 #include "catalogobject.h"
0019 #include "ksmoon.h"
0020 #include "ksasteroid.h"
0021 #include "kscomet.h"
0022 #include "Options.h"
0023 #include "catalogsdb.h"
0024 
0025 DetailsTable::DetailsTable()
0026 {
0027     m_Document = new QTextDocument(KStars::Instance());
0028 
0029     setDefaultFormatting();
0030 }
0031 
0032 DetailsTable::~DetailsTable()
0033 {
0034     if (m_Document)
0035     {
0036         delete m_Document;
0037     }
0038 }
0039 
0040 void DetailsTable::createGeneralTable(SkyObject *obj)
0041 {
0042     clearContents();
0043 
0044     QTextCursor cursor = m_Document->rootFrame()->firstCursorPosition();
0045 
0046     //Fill in the data fields
0047     //Contents depend on type of object
0048     StarObject *s      = nullptr;
0049     CatalogObject *dso = nullptr;
0050     KSPlanetBase *ps   = nullptr;
0051     QString pname, oname;
0052 
0053     QString objNamesVal, objTypeVal, objDistVal, objSizeVal, objMagVal, objBvVal, objIllumVal;
0054     QString objSizeLabel, objMagLabel;
0055 
0056     switch (obj->type())
0057     {
0058         case SkyObject::STAR:
0059         {
0060             s = (StarObject *)obj;
0061 
0062             objNamesVal = s->longname();
0063 
0064             if (s->getHDIndex() != 0)
0065             {
0066                 if (!s->longname().isEmpty())
0067                 {
0068                     objNamesVal = s->longname() + QString(", HD%1").arg(QString::number(s->getHDIndex()));
0069                 }
0070 
0071                 else
0072                 {
0073                     objNamesVal = QString(", HD%1").arg(QString::number(s->getHDIndex()));
0074                 }
0075             }
0076 
0077             objTypeVal = s->sptype() + ' ' + i18n("star");
0078             objMagVal = i18nc("number in magnitudes", "%1 mag", QLocale().toString(s->mag(), 1)); //show to tenths place
0079 
0080             if (s->getBVIndex() < 30.0)
0081             {
0082                 objBvVal = QString::number(s->getBVIndex(), 'g', 2);
0083             }
0084 
0085             //distance
0086             if (s->distance() > 2000. || s->distance() < 0.) // parallax < 0.5 mas
0087             {
0088                 objDistVal = i18nc("larger than 2000 parsecs", "> 2000 pc");
0089             }
0090 
0091             else if (s->distance() > 50.0) //show to nearest integer
0092             {
0093                 objDistVal = i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 0));
0094             }
0095 
0096             else if (s->distance() > 10.0) //show to tenths place
0097             {
0098                 objDistVal = i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 1));
0099             }
0100 
0101             else //show to hundredths place
0102             {
0103                 objDistVal = i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 2));
0104             }
0105 
0106             //Note multiplicity/variability in angular size label
0107             if (s->isMultiple() && s->isVariable())
0108             {
0109                 objSizeLabel = i18nc("the star is a multiple star", "multiple") + ',';
0110                 objSizeVal   = i18nc("the star is a variable star", "variable");
0111             }
0112 
0113             else if (s->isMultiple())
0114             {
0115                 objSizeLabel = i18nc("the star is a multiple star", "multiple");
0116             }
0117 
0118             else if (s->isVariable())
0119             {
0120                 objSizeLabel = i18nc("the star is a variable star", "variable");
0121             }
0122 
0123             objIllumVal = "--";
0124 
0125             break; //End of stars case
0126         }
0127 
0128         case SkyObject::ASTEROID: //[fall through to planets]
0129 
0130         case SkyObject::COMET: //[fall through to planets]
0131 
0132         case SkyObject::MOON: //[fall through to planets]
0133 
0134         case SkyObject::PLANET:
0135         {
0136             ps = dynamic_cast<KSPlanetBase *>(obj);
0137 
0138             objNamesVal = ps->longname();
0139             //Type is "G5 star" for Sun
0140             if (ps->name() == i18n("Sun"))
0141             {
0142                 objTypeVal = i18n("G5 star");
0143             }
0144 
0145             else if (ps->name() == i18n("Moon"))
0146             {
0147                 objTypeVal = ps->translatedName();
0148             }
0149 
0150             else if (ps->name() == i18nc("Asteroid name (optional)", "Pluto") || ps->name() == i18nc("Asteroid name (optional)", "Ceres") ||
0151                      ps->name() == i18nc("Asteroid name (optional)", "Eris")) // TODO: Check if Ceres / Eris have translations and i18n() them
0152             {
0153                 objTypeVal = i18n("Dwarf planet");
0154             }
0155 
0156             else
0157             {
0158                 objTypeVal = ps->typeName();
0159             }
0160 
0161             //Magnitude: The moon displays illumination fraction instead
0162             if (obj->name() == i18n("Moon"))
0163             {
0164                 KSMoon * const m = dynamic_cast<KSMoon *>(obj);
0165                 if (m)
0166                     objIllumVal = QString("%1 %").arg(QLocale().toString(m->illum() * 100., 0));
0167             }
0168 
0169             objMagVal =
0170                 i18nc("number in magnitudes", "%1 mag", QLocale().toString(ps->mag(), 1)); //show to tenths place
0171 
0172             //Distance from Earth.  The moon requires a unit conversion
0173             if (ps->name() == i18n("Moon"))
0174             {
0175                 objDistVal = i18nc("distance in kilometers", "%1 km", QLocale().toString(ps->rearth() * AU_KM));
0176             }
0177 
0178             else
0179             {
0180                 objDistVal = i18nc("distance in Astronomical Units", "%1 AU", QLocale().toString(ps->rearth()));
0181             }
0182 
0183             //Angular size; moon and sun in arcmin, others in arcsec
0184             if (ps->angSize())
0185             {
0186                 if (ps->name() == i18n("Sun") || ps->name() == i18n("Moon"))
0187                 {
0188                     // Needn't be a plural form because sun / moon will never contract to 1 arcminute
0189                     objSizeVal = i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(ps->angSize()));
0190                 }
0191 
0192                 else
0193                 {
0194                     objSizeVal =
0195                         i18nc("angular size in arcseconds", "%1 arcsec", QLocale().toString(ps->angSize() * 60.0));
0196                 }
0197             }
0198 
0199             else
0200             {
0201                 objSizeVal = "--";
0202             }
0203 
0204             break; //End of planets/comets/asteroids case
0205         }
0206 
0207         default: //Deep-sky objects
0208         {
0209             dso = (CatalogObject *)obj;
0210 
0211             //Show all names recorded for the object
0212             if (!dso->longname().isEmpty() && dso->longname() != dso->name())
0213             {
0214                 pname = dso->translatedLongName();
0215                 oname = dso->translatedName();
0216             }
0217 
0218             else
0219             {
0220                 pname = dso->translatedName();
0221             }
0222 
0223             if (!dso->translatedName2().isEmpty())
0224             {
0225                 if (oname.isEmpty())
0226                 {
0227                     oname = dso->translatedName2();
0228                 }
0229 
0230                 else
0231                 {
0232                     oname += ", " + dso->translatedName2();
0233                 }
0234             }
0235 
0236 
0237             if (!oname.isEmpty())
0238             {
0239                 pname += ", " + oname;
0240             }
0241 
0242             objNamesVal = pname;
0243 
0244             objTypeVal = dso->typeName();
0245 
0246             if (dso->type() == SkyObject::RADIO_SOURCE)
0247             {
0248                 objMagLabel =
0249                     i18nc("integrated flux at a frequency", "Flux(%1):", CatalogsDB::flux_frequency);
0250                 objMagVal = i18nc("integrated flux value", "%1 %2", QLocale().toString(dso->flux(), 1),
0251                                   CatalogsDB::flux_unit); //show to tenths place
0252             }
0253 
0254             if (dso->mag() > 90.0)
0255             {
0256                 objMagVal = "--";
0257             }
0258 
0259             else
0260             {
0261                 objMagVal =
0262                     i18nc("number in magnitudes", "%1 mag", QLocale().toString(dso->mag(), 1)); //show to tenths place
0263             }
0264 
0265             //No distances at this point...
0266             objDistVal = "--";
0267 
0268             //Only show decimal place for small angular sizes
0269             if (dso->a() > 10.0)
0270             {
0271                 objSizeVal = i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 0));
0272             }
0273 
0274             else if (dso->a())
0275             {
0276                 objSizeVal = i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 1));
0277             }
0278 
0279             else
0280             {
0281                 objSizeVal = "--";
0282             }
0283 
0284             break; //End of deep-space objects case
0285         }
0286     }
0287 
0288     //Common to all types:
0289     if (obj->type() == SkyObject::CONSTELLATION)
0290     {
0291         objTypeVal = KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(obj);
0292     }
0293 
0294     else
0295     {
0296         objTypeVal =
0297             i18nc("%1 type of sky object (planet, asteroid etc), %2 name of a constellation", "%1 in %2", objTypeVal,
0298                   KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(obj));
0299     }
0300 
0301     QVector<QTextLength> constraints;
0302     constraints << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25)
0303                 << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25);
0304     m_TableFormat.setColumnWidthConstraints(constraints);
0305 
0306     QTextTable *table = cursor.insertTable(5, 4, m_TableFormat);
0307     table->mergeCells(0, 0, 1, 4);
0308     QTextBlockFormat centered;
0309     centered.setAlignment(Qt::AlignCenter);
0310     table->cellAt(0, 0).firstCursorPosition().setBlockFormat(centered);
0311     table->cellAt(0, 0).firstCursorPosition().insertText(i18n("General"), m_TableTitleCharFormat);
0312 
0313     table->mergeCells(1, 1, 1, 3);
0314     table->cellAt(1, 0).firstCursorPosition().insertText(i18n("Names:"), m_ItemNameCharFormat);
0315     table->cellAt(1, 0).firstCursorPosition().setBlockFormat(centered);
0316     table->cellAt(1, 1).firstCursorPosition().insertText(objNamesVal, m_ItemValueCharFormat);
0317 
0318     table->cellAt(2, 0).firstCursorPosition().insertText(i18n("Type:"), m_ItemNameCharFormat);
0319     table->cellAt(2, 0).firstCursorPosition().setBlockFormat(centered);
0320     table->cellAt(2, 1).firstCursorPosition().insertText(objTypeVal, m_ItemValueCharFormat);
0321 
0322     table->cellAt(3, 0).firstCursorPosition().insertText(i18n("Distance:"), m_ItemNameCharFormat);
0323     table->cellAt(3, 0).firstCursorPosition().setBlockFormat(centered);
0324     table->cellAt(3, 1).firstCursorPosition().insertText(objDistVal, m_ItemValueCharFormat);
0325 
0326     table->cellAt(4, 0).firstCursorPosition().insertText(i18n("Size:"), m_ItemNameCharFormat);
0327     table->cellAt(4, 0).firstCursorPosition().setBlockFormat(centered);
0328     table->cellAt(4, 1).firstCursorPosition().insertText(objSizeVal, m_ItemValueCharFormat);
0329 
0330     table->cellAt(2, 2).firstCursorPosition().insertText(i18n("Magnitude:"), m_ItemNameCharFormat);
0331     table->cellAt(2, 2).firstCursorPosition().setBlockFormat(centered);
0332     table->cellAt(2, 3).firstCursorPosition().insertText(objMagVal, m_ItemValueCharFormat);
0333 
0334     table->cellAt(3, 2).firstCursorPosition().insertText(i18n("B-V index:"), m_ItemNameCharFormat);
0335     table->cellAt(3, 2).firstCursorPosition().setBlockFormat(centered);
0336     table->cellAt(3, 3).firstCursorPosition().insertText(objBvVal, m_ItemValueCharFormat);
0337 
0338     table->cellAt(4, 2).firstCursorPosition().insertText(i18n("Illumination:"), m_ItemNameCharFormat);
0339     table->cellAt(4, 2).firstCursorPosition().setBlockFormat(centered);
0340     table->cellAt(4, 3).firstCursorPosition().insertText(objIllumVal, m_ItemValueCharFormat);
0341 }
0342 
0343 void DetailsTable::createAsteroidCometTable(SkyObject *obj)
0344 {
0345     clearContents();
0346 
0347     QTextCursor cursor = m_Document->rootFrame()->firstCursorPosition();
0348 
0349     QString perihelionVal, orbitIdVal, neoVal, diamVal, rotPeriodVal, moidVal;
0350     QString orbitClassVal, albedoVal, dimVal, periodVal;
0351 
0352     // Add specifics data
0353     switch (obj->type())
0354     {
0355         case SkyObject::ASTEROID:
0356         {
0357             KSAsteroid *ast = (KSAsteroid *)obj;
0358 
0359             // Perihelion
0360             perihelionVal = QString::number(ast->getPerihelion()) + " AU";
0361 
0362             // Earth MOID
0363             moidVal = ast->getEarthMOID() == 0 ? QString("--") : QString::number(ast->getEarthMOID()) + QString(" AU");
0364 
0365             // Orbit ID
0366             orbitIdVal = ast->getOrbitID();
0367 
0368             // Orbit Class
0369             orbitClassVal = ast->getOrbitClass();
0370 
0371             // NEO
0372             neoVal = ast->isNEO() ? i18n("Yes") : i18n("No");
0373 
0374             // Albedo
0375             albedoVal = ast->getAlbedo() == 0 ? QString("--") : QString::number(ast->getAlbedo());
0376 
0377             // Diameter
0378             diamVal = ast->getDiameter() == 0 ? QString("--") : QString::number(ast->getDiameter()) + QString(" km");
0379 
0380             // Dimensions
0381             dimVal = ast->getDimensions().isEmpty() ? QString("--") : ast->getDimensions() + QString(" km");
0382 
0383             // Rotation period
0384             rotPeriodVal = ast->getRotationPeriod() == 0 ? QString("--") :
0385                            QString::number(ast->getRotationPeriod()) + QString(" h");
0386 
0387             // Period
0388             periodVal = ast->getPeriod() == 0 ? QString("--") : QString::number(ast->getPeriod()) + QString(" y");
0389 
0390             break;
0391         }
0392 
0393         case SkyObject::COMET:
0394         {
0395             KSComet *com = (KSComet *)obj;
0396 
0397             // Perihelion
0398             perihelionVal = QString::number(com->getPerihelion()) + " AU";
0399 
0400             // Earth MOID
0401             moidVal = com->getEarthMOID() == 0 ? QString("--") : QString::number(com->getEarthMOID()) + QString(" AU");
0402 
0403             // Orbit ID
0404             orbitIdVal = com->getOrbitID();
0405 
0406             // Orbit Class
0407             orbitClassVal = com->getOrbitClass();
0408 
0409             // NEO
0410             neoVal = com->isNEO() ? i18n("Yes") : i18n("No");
0411 
0412             // Albedo
0413             albedoVal = com->getAlbedo() == 0 ? QString("--") : QString::number(com->getAlbedo());
0414 
0415             // Diameter
0416             diamVal = com->getDiameter() == 0 ? QString("--") : QString::number(com->getDiameter()) + QString(" km");
0417 
0418             // Dimensions
0419             dimVal = com->getDimensions().isEmpty() ? QString("--") : com->getDimensions() + QString(" km");
0420 
0421             // Rotation period
0422             rotPeriodVal = com->getRotationPeriod() == 0 ? QString("--") :
0423                            QString::number(com->getRotationPeriod()) + QString(" h");
0424 
0425             // Period
0426             periodVal = com->getPeriod() == 0 ? QString("--") : QString::number(com->getPeriod()) + QString(" y");
0427 
0428             break;
0429         }
0430 
0431         default:
0432         {
0433             return;
0434         }
0435     }
0436 
0437     // Set column width constraints
0438     QVector<QTextLength> constraints;
0439     constraints << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25)
0440                 << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25);
0441     m_TableFormat.setColumnWidthConstraints(constraints);
0442 
0443     QTextTable *table = cursor.insertTable(6, 4, m_TableFormat);
0444     table->mergeCells(0, 0, 1, 4);
0445     QTextBlockFormat centered;
0446     centered.setAlignment(Qt::AlignCenter);
0447     table->cellAt(0, 0).firstCursorPosition().setBlockFormat(centered);
0448     table->cellAt(0, 0).firstCursorPosition().insertText(i18n("Asteroid/Comet details"), m_TableTitleCharFormat);
0449 
0450     table->cellAt(1, 0).firstCursorPosition().insertText(i18n("Perihelion:"), m_ItemNameCharFormat);
0451     table->cellAt(1, 0).firstCursorPosition().setBlockFormat(centered);
0452     table->cellAt(1, 1).firstCursorPosition().insertText(perihelionVal, m_ItemValueCharFormat);
0453 
0454     table->cellAt(2, 0).firstCursorPosition().insertText(i18n("Orbit ID:"), m_ItemNameCharFormat);
0455     table->cellAt(2, 0).firstCursorPosition().setBlockFormat(centered);
0456     table->cellAt(2, 1).firstCursorPosition().insertText(orbitIdVal, m_ItemValueCharFormat);
0457 
0458     table->cellAt(3, 0).firstCursorPosition().insertText(i18n("NEO:"), m_ItemNameCharFormat);
0459     table->cellAt(3, 0).firstCursorPosition().setBlockFormat(centered);
0460     table->cellAt(3, 1).firstCursorPosition().insertText(neoVal, m_ItemValueCharFormat);
0461 
0462     table->cellAt(4, 0).firstCursorPosition().insertText(i18n("Diameter:"), m_ItemNameCharFormat);
0463     table->cellAt(4, 0).firstCursorPosition().setBlockFormat(centered);
0464     table->cellAt(4, 1).firstCursorPosition().insertText(diamVal, m_ItemValueCharFormat);
0465 
0466     table->cellAt(5, 0).firstCursorPosition().insertText(i18n("Rotation period:"), m_ItemNameCharFormat);
0467     table->cellAt(5, 0).firstCursorPosition().setBlockFormat(centered);
0468     table->cellAt(5, 1).firstCursorPosition().insertText(rotPeriodVal, m_ItemValueCharFormat);
0469 
0470     table->cellAt(1, 2).firstCursorPosition().insertText(i18n("Earth MOID:"), m_ItemNameCharFormat);
0471     table->cellAt(1, 2).firstCursorPosition().setBlockFormat(centered);
0472     table->cellAt(1, 3).firstCursorPosition().insertText(moidVal, m_ItemValueCharFormat);
0473 
0474     table->cellAt(2, 2).firstCursorPosition().insertText(i18n("Orbit class:"), m_ItemNameCharFormat);
0475     table->cellAt(2, 2).firstCursorPosition().setBlockFormat(centered);
0476     table->cellAt(2, 3).firstCursorPosition().insertText(orbitClassVal, m_ItemValueCharFormat);
0477 
0478     table->cellAt(3, 2).firstCursorPosition().insertText(i18n("Albedo:"), m_ItemNameCharFormat);
0479     table->cellAt(3, 2).firstCursorPosition().setBlockFormat(centered);
0480     table->cellAt(3, 3).firstCursorPosition().insertText(albedoVal, m_ItemValueCharFormat);
0481 
0482     table->cellAt(4, 2).firstCursorPosition().insertText(i18n("Dimensions:"), m_ItemNameCharFormat);
0483     table->cellAt(4, 2).firstCursorPosition().setBlockFormat(centered);
0484     table->cellAt(4, 3).firstCursorPosition().insertText(dimVal, m_ItemValueCharFormat);
0485 
0486     table->cellAt(5, 2).firstCursorPosition().insertText(i18n("Period:"), m_ItemNameCharFormat);
0487     table->cellAt(5, 2).firstCursorPosition().setBlockFormat(centered);
0488     table->cellAt(5, 3).firstCursorPosition().insertText(periodVal, m_ItemValueCharFormat);
0489 }
0490 
0491 void DetailsTable::createCoordinatesTable(SkyObject *obj, const KStarsDateTime &ut, GeoLocation *geo)
0492 {
0493     clearContents();
0494 
0495     QTextCursor cursor = m_Document->rootFrame()->firstCursorPosition();
0496 
0497     // Set column width constraints
0498     QVector<QTextLength> constraints;
0499     constraints << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25)
0500                 << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25);
0501     m_TableFormat.setColumnWidthConstraints(constraints);
0502 
0503     // Insert table & row containing table name
0504     QTextTable *table = cursor.insertTable(4, 4, m_TableFormat);
0505     table->mergeCells(0, 0, 1, 4);
0506     QTextBlockFormat centered;
0507     centered.setAlignment(Qt::AlignCenter);
0508     table->cellAt(0, 0).firstCursorPosition().setBlockFormat(centered);
0509     table->cellAt(0, 0).firstCursorPosition().insertText(i18n("Coordinates"), m_TableTitleCharFormat);
0510 
0511     //Coordinates Section:
0512     //Don't use KLocale::formatNumber() for the epoch string,
0513     //because we don't want a thousands-place separator!
0514     QString sEpoch = QString::number(ut.epoch(), 'f', 1);
0515     //Replace the decimal point with localized decimal symbol
0516     sEpoch.replace('.', QLocale().decimalPoint());
0517 
0518     table->cellAt(1, 0).firstCursorPosition().insertText(i18n("RA (%1):", sEpoch), m_ItemNameCharFormat);
0519     table->cellAt(1, 0).firstCursorPosition().setBlockFormat(centered);
0520     table->cellAt(1, 1).firstCursorPosition().insertText(obj->ra().toHMSString(), m_ItemValueCharFormat);
0521 
0522     table->cellAt(2, 0).firstCursorPosition().insertText(i18n("Dec (%1):", sEpoch), m_ItemNameCharFormat);
0523     table->cellAt(2, 0).firstCursorPosition().setBlockFormat(centered);
0524     table->cellAt(2, 1).firstCursorPosition().insertText(obj->dec().toDMSString(), m_ItemValueCharFormat);
0525 
0526     table->cellAt(3, 0).firstCursorPosition().insertText(i18n("Hour angle:"), m_ItemNameCharFormat);
0527     table->cellAt(3, 0).firstCursorPosition().setBlockFormat(centered);
0528     //Hour Angle can be negative, but dms HMS expressions cannot.
0529     //Here's a kludgy workaround:
0530     dms lst = geo->GSTtoLST(ut.gst());
0531     dms ha(lst.Degrees() - obj->ra().Degrees());
0532     QChar sgn('+');
0533     if (ha.Hours() > 12.0)
0534     {
0535         ha.setH(24.0 - ha.Hours());
0536         sgn = '-';
0537     }
0538     table->cellAt(3, 1).firstCursorPosition().insertText(QString("%1%2").arg(sgn).arg(ha.toHMSString()),
0539             m_ItemValueCharFormat);
0540 
0541     table->cellAt(1, 2).firstCursorPosition().insertText(i18n("Azimuth:"), m_ItemNameCharFormat);
0542     table->cellAt(1, 2).firstCursorPosition().setBlockFormat(centered);
0543     table->cellAt(1, 3).firstCursorPosition().insertText(obj->az().toDMSString(), m_ItemValueCharFormat);
0544 
0545     table->cellAt(2, 2).firstCursorPosition().insertText(i18n("Altitude:"), m_ItemNameCharFormat);
0546     table->cellAt(2, 2).firstCursorPosition().setBlockFormat(centered);
0547     dms a;
0548     if (Options::useAltAz())
0549     {
0550         a = obj->alt();
0551     }
0552 
0553     else
0554     {
0555         a = obj->altRefracted();
0556     }
0557     table->cellAt(2, 3).firstCursorPosition().insertText(a.toDMSString(), m_ItemValueCharFormat);
0558 
0559     table->cellAt(3, 2).firstCursorPosition().insertText(i18n("Airmass:"), m_ItemNameCharFormat);
0560     table->cellAt(3, 2).firstCursorPosition().setBlockFormat(centered);
0561     //Airmass is approximated as the secant of the zenith distance,
0562     //equivalent to 1./sin(Alt).  Beware of Inf at Alt=0!
0563     QString aMassStr;
0564     if (obj->alt().Degrees() > 0.0)
0565     {
0566         aMassStr = QLocale().toString(1. / sin(obj->alt().radians()), 2);
0567     }
0568 
0569     else
0570     {
0571         aMassStr = "--";
0572     }
0573     table->cellAt(3, 3).firstCursorPosition().insertText(aMassStr, m_ItemValueCharFormat);
0574 
0575     // Restore the position and other time-dependent parameters
0576     obj->recomputeCoords(ut, geo);
0577 }
0578 
0579 void DetailsTable::createRSTTAble(SkyObject *obj, const KStarsDateTime &ut, GeoLocation *geo)
0580 {
0581     clearContents();
0582 
0583     QTextCursor cursor = m_Document->rootFrame()->firstCursorPosition();
0584 
0585     QString rtValue, stValue;   // Rise/Set time values
0586     QString azRValue, azSValue; // Rise/Set azimuth values
0587 
0588     //Prepare time/position variables
0589     QTime rt = obj->riseSetTime(ut, geo, true);   //true = use rise time
0590     dms raz  = obj->riseSetTimeAz(ut, geo, true); //true = use rise time
0591 
0592     //If transit time is before rise time, use transit time for tomorrow
0593     QTime tt = obj->transitTime(ut, geo);
0594     dms talt = obj->transitAltitude(ut, geo);
0595     if (tt < rt)
0596     {
0597         tt   = obj->transitTime(ut.addDays(1), geo);
0598         talt = obj->transitAltitude(ut.addDays(1), geo);
0599     }
0600 
0601     //If set time is before rise time, use set time for tomorrow
0602     QTime st = obj->riseSetTime(ut, geo, false);   //false = use set time
0603     dms saz  = obj->riseSetTimeAz(ut, geo, false); //false = use set time
0604     if (st < rt)
0605     {
0606         st  = obj->riseSetTime(ut.addDays(1), geo, false);   //false = use set time
0607         saz = obj->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time
0608     }
0609 
0610     if (rt.isValid())
0611     {
0612         rtValue  = QString::asprintf("%02d:%02d", rt.hour(), rt.minute());
0613         stValue  = QString::asprintf("%02d:%02d", st.hour(), st.minute());
0614         azRValue = raz.toDMSString();
0615         azSValue = saz.toDMSString();
0616     }
0617 
0618     else
0619     {
0620         if (obj->alt().Degrees() > 0.0)
0621         {
0622             rtValue = i18n("Circumpolar");
0623             stValue = i18n("Circumpolar");
0624         }
0625 
0626         else
0627         {
0628             rtValue = i18n("Never rises");
0629             stValue = i18n("Never rises");
0630         }
0631 
0632         azRValue = i18nc("Not Applicable", "N/A");
0633         azSValue = i18nc("Not Applicable", "N/A");
0634     }
0635 
0636     // Set column width constraints
0637     QVector<QTextLength> constraints;
0638     constraints << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25)
0639                 << QTextLength(QTextLength::PercentageLength, 25) << QTextLength(QTextLength::PercentageLength, 25);
0640     m_TableFormat.setColumnWidthConstraints(constraints);
0641 
0642     // Insert table & row containing table name
0643     QTextTable *table = cursor.insertTable(4, 4, m_TableFormat);
0644     table->mergeCells(0, 0, 1, 4);
0645     QTextBlockFormat centered;
0646     centered.setAlignment(Qt::AlignCenter);
0647     table->cellAt(0, 0).firstCursorPosition().setBlockFormat(centered);
0648     table->cellAt(0, 0).firstCursorPosition().insertText(i18n("Rise/Set/Transit"), m_TableTitleCharFormat);
0649 
0650     // Insert cell names & values
0651     table->cellAt(1, 0).firstCursorPosition().insertText(i18n("Rise time:"), m_ItemNameCharFormat);
0652     table->cellAt(1, 0).firstCursorPosition().setBlockFormat(centered);
0653     table->cellAt(1, 1).firstCursorPosition().insertText(rtValue, m_ItemValueCharFormat);
0654 
0655     table->cellAt(2, 0).firstCursorPosition().insertText(i18n("Transit time:"), m_ItemNameCharFormat);
0656     table->cellAt(2, 0).firstCursorPosition().setBlockFormat(centered);
0657     table->cellAt(2, 1).firstCursorPosition().insertText(QString::asprintf("%02d:%02d", tt.hour(), tt.minute()),
0658             m_ItemValueCharFormat);
0659 
0660     table->cellAt(3, 0).firstCursorPosition().insertText(i18n("Set time:"), m_ItemNameCharFormat);
0661     table->cellAt(3, 0).firstCursorPosition().setBlockFormat(centered);
0662     table->cellAt(3, 1).firstCursorPosition().insertText(stValue, m_ItemValueCharFormat);
0663 
0664     table->cellAt(1, 2).firstCursorPosition().insertText(i18n("Azimuth at rise:"), m_ItemNameCharFormat);
0665     table->cellAt(1, 2).firstCursorPosition().setBlockFormat(centered);
0666     table->cellAt(1, 3).firstCursorPosition().insertText(azRValue, m_ItemValueCharFormat);
0667 
0668     table->cellAt(2, 2).firstCursorPosition().insertText(i18n("Altitude at transit:"), m_ItemNameCharFormat);
0669     table->cellAt(2, 2).firstCursorPosition().setBlockFormat(centered);
0670     table->cellAt(2, 3).firstCursorPosition().insertText(talt.toDMSString(), m_ItemValueCharFormat);
0671 
0672     table->cellAt(3, 2).firstCursorPosition().insertText(i18n("Azimuth at set:"), m_ItemNameCharFormat);
0673     table->cellAt(3, 2).firstCursorPosition().setBlockFormat(centered);
0674     table->cellAt(3, 3).firstCursorPosition().insertText(azSValue, m_ItemValueCharFormat);
0675 
0676     // Restore the position and other time-dependent parameters
0677     obj->recomputeCoords(ut, geo);
0678 }
0679 
0680 void DetailsTable::clearContents()
0681 {
0682     m_Document->clear();
0683 }
0684 
0685 void DetailsTable::setDefaultFormatting()
0686 {
0687     // Set default table format
0688     m_TableFormat.setAlignment(Qt::AlignCenter);
0689     m_TableFormat.setBorder(4);
0690     m_TableFormat.setCellPadding(2);
0691     m_TableFormat.setCellSpacing(2);
0692 
0693     // Set default table title character format
0694     m_TableTitleCharFormat.setFont(QFont("Times", 12, QFont::Bold));
0695     m_TableTitleCharFormat.setFontCapitalization(QFont::Capitalize);
0696 
0697     // Set default table item name character format
0698     m_ItemNameCharFormat.setFont(QFont("Times", 10, QFont::Bold));
0699 
0700     // Set default table item value character format
0701     m_ItemValueCharFormat.setFont(QFont("Times", 10));
0702 }