File indexing completed on 2025-03-23 03:31:25
0001 /* 0002 SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "detaildialoglite.h" 0008 0009 #include "constellationboundarylines.h" 0010 #include "deepskyobject.h" 0011 #include "kspaths.h" 0012 #include "ksutils.h" 0013 #include "Options.h" 0014 #include "skymapcomposite.h" 0015 #include "skymaplite.h" 0016 #include "starobject.h" 0017 #include "kstarslite/skyobjectlite.h" 0018 #include "skyobjects/ksasteroid.h" 0019 #include "skyobjects/kscomet.h" 0020 #include "skyobjects/ksmoon.h" 0021 #include "skyobjects/ksplanetbase.h" 0022 #include "skyobjects/supernova.h" 0023 0024 #include <QDesktopServices> 0025 #include <QTemporaryFile> 0026 0027 DetailDialogLite::DetailDialogLite() 0028 { 0029 setProperty("isLinksOn", true); 0030 setProperty("isLogOn", true); 0031 } 0032 0033 void DetailDialogLite::initialize() 0034 { 0035 connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createGeneralTab())); 0036 connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createPositionTab())); 0037 connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createLogTab())); 0038 connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createLinksTab())); 0039 } 0040 0041 void DetailDialogLite::createGeneralTab() 0042 { 0043 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0044 0045 // Stuff that should be visible only for specific types of objects 0046 setProperty("illumination", ""); // Only shown for the moon 0047 setProperty("BVindex", ""); // Only shown for stars 0048 setupThumbnail(); 0049 0050 //Fill in the data fields 0051 //Contents depend on type of object 0052 QString objecttyp, str; 0053 0054 switch (selectedObject->type()) 0055 { 0056 case SkyObject::STAR: 0057 { 0058 StarObject *s = (StarObject *)selectedObject; 0059 0060 if (s->getHDIndex()) 0061 { 0062 setProperty("name", (QString("%1, HD %2").arg(s->longname()).arg(s->getHDIndex()))); 0063 } 0064 else 0065 { 0066 setProperty("name", s->longname()); 0067 } 0068 0069 objecttyp = s->sptype() + ' ' + i18n("star"); 0070 setProperty("magnitude", i18nc("number in magnitudes", "%1 mag", 0071 QLocale().toString(s->mag(), 'f', 2))); //show to hundredth place 0072 0073 if (s->getBVIndex() < 30.) 0074 { 0075 setProperty("BVindex", QString::number(s->getBVIndex(), 'f', 2)); 0076 } 0077 0078 //distance 0079 if (s->distance() > 2000. || s->distance() < 0.) // parallax < 0.5 mas 0080 { 0081 setProperty("distance", (QString(i18nc("larger than 2000 parsecs", "> 2000 pc")))); 0082 } 0083 else if (s->distance() > 50.) //show to nearest integer 0084 { 0085 setProperty("distance", 0086 (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 0)))); 0087 } 0088 else if (s->distance() > 10.0) //show to tenths place 0089 { 0090 setProperty("distance", 0091 (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 1)))); 0092 } 0093 else //show to hundredths place 0094 { 0095 setProperty("distance", 0096 (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 2)))); 0097 } 0098 0099 //Note multiplicity/variability in angular size label 0100 setProperty("angSize", QString()); 0101 if (s->isMultiple() && s->isVariable()) 0102 { 0103 QString multiple = QString(i18nc("the star is a multiple star", "multiple") + ','); 0104 setProperty("angSize", QString(multiple + '\n' + (i18nc("the star is a variable star", "variable")))); 0105 } 0106 else if (s->isMultiple()) 0107 { 0108 setProperty("angSize", i18nc("the star is a multiple star", "multiple")); 0109 } 0110 else if (s->isVariable()) 0111 { 0112 setProperty("angSize", (i18nc("the star is a variable star", "variable"))); 0113 } 0114 0115 break; //end of stars case 0116 } 0117 case SkyObject::ASTEROID: //[fall through to planets] 0118 case SkyObject::COMET: //[fall through to planets] 0119 case SkyObject::MOON: //[fall through to planets] 0120 case SkyObject::PLANET: 0121 { 0122 KSPlanetBase *ps = (KSPlanetBase *)selectedObject; 0123 0124 setProperty("name", ps->longname()); 0125 0126 //Type is "G5 star" for Sun 0127 if (ps->name() == "Sun") 0128 { 0129 objecttyp = i18n("G5 star"); 0130 } 0131 else if (ps->name() == "Moon") 0132 { 0133 objecttyp = ps->translatedName(); 0134 } 0135 else if (ps->name() == i18n("Pluto") || ps->name() == "Ceres" || 0136 ps->name() == "Eris") // TODO: Check if Ceres / Eris have translations and i18n() them 0137 { 0138 objecttyp = i18n("Dwarf planet"); 0139 } 0140 else 0141 { 0142 objecttyp = ps->typeName(); 0143 } 0144 0145 //The moon displays illumination fraction and updateMag is called to calculate moon's current magnitude 0146 if (selectedObject->name() == "Moon") 0147 { 0148 setProperty( 0149 "illumination", 0150 (QString("%1 %").arg(QLocale().toString(((KSMoon *)selectedObject)->illum() * 100., 'f', 0)))); 0151 ((KSMoon *)selectedObject)->updateMag(); 0152 } 0153 0154 // JM: Shouldn't we use the calculated magnitude? Disabling the following 0155 /* 0156 if(selectedObject->type() == SkyObject::COMET){ 0157 Data->Magnitude->setText(i18nc("number in magnitudes", "%1 mag", 0158 QLocale().toString( ((KSComet *)selectedObject)->getTotalMagnitudeParameter(), 'f', 2))); //show to hundredth place 0159 0160 } 0161 else{*/ 0162 setProperty("magnitude", (i18nc("number in magnitudes", "%1 mag", 0163 QLocale().toString(ps->mag(), 'f', 2)))); //show to hundredth place 0164 //} 0165 0166 //Distance from Earth. The moon requires a unit conversion 0167 if (ps->name() == "Moon") 0168 { 0169 setProperty("distance", (i18nc("distance in kilometers", "%1 km", 0170 QLocale().toString(ps->rearth() * AU_KM, 'f', 2)))); 0171 } 0172 else 0173 { 0174 setProperty("distance", (i18nc("distance in Astronomical Units", "%1 AU", 0175 QLocale().toString(ps->rearth(), 'f', 3)))); 0176 } 0177 0178 //Angular size; moon and sun in arcmin, others in arcsec 0179 if (ps->angSize()) 0180 { 0181 if (ps->name() == "Sun" || ps->name() == "Moon") 0182 { 0183 setProperty( 0184 "angSize", 0185 (i18nc( 0186 "angular size in arcminutes", "%1 arcmin", 0187 QLocale().toString( 0188 ps->angSize(), 'f', 0189 1)))); // Needn't be a plural form because sun / moon will never contract to 1 arcminute 0190 } 0191 else 0192 { 0193 setProperty("angSize", i18nc("angular size in arcseconds", "%1 arcsec", 0194 QLocale().toString(ps->angSize() * 60.0, 'f', 1))); 0195 } 0196 } 0197 else 0198 { 0199 setProperty("angSize", "--"); 0200 } 0201 0202 break; //end of planets/comets/asteroids case 0203 } 0204 case SkyObject::SUPERNOVA: 0205 { 0206 Supernova *sup = (Supernova *)selectedObject; 0207 0208 objecttyp = i18n("Supernova"); 0209 setProperty("name", sup->name()); 0210 setProperty("magnitude", (i18nc("number in magnitudes", "%1 mag", QLocale().toString(sup->mag(), 'f', 2)))); 0211 setProperty("distance", "---"); 0212 break; 0213 } 0214 default: //deep-sky objects 0215 { 0216 DeepSkyObject *dso = (DeepSkyObject *)selectedObject; 0217 0218 //Show all names recorded for the object 0219 QStringList nameList; 0220 if (!dso->longname().isEmpty() && dso->longname() != dso->name()) 0221 { 0222 nameList.append(dso->translatedLongName()); 0223 nameList.append(dso->translatedName()); 0224 } 0225 else 0226 { 0227 nameList.append(dso->translatedName()); 0228 } 0229 0230 if (!dso->translatedName2().isEmpty()) 0231 { 0232 nameList.append(dso->translatedName2()); 0233 } 0234 0235 if (dso->ugc() != 0) 0236 { 0237 nameList.append(QString("UGC %1").arg(dso->ugc())); 0238 } 0239 0240 if (dso->pgc() != 0) 0241 { 0242 nameList.append(QString("PGC %1").arg(dso->pgc())); 0243 } 0244 0245 setProperty("name", nameList.join(",")); 0246 0247 objecttyp = dso->typeName(); 0248 0249 if (dso->type() == SkyObject::RADIO_SOURCE) 0250 { 0251 //ta->MagLabel->setText(i18nc("integrated flux at a frequency", "Flux(%1):", dso->customCatalog()->fluxFrequency())); 0252 //Data->Magnitude->setText(i18nc("integrated flux value", "%1 %2", 0253 // QLocale().toString(dso->flux(), 'f', 1), dso->customCatalog()->fluxUnit())); //show to tenths place 0254 } 0255 else if (dso->mag() > 90.0) 0256 { 0257 setProperty("magnitude", "--"); 0258 } 0259 else 0260 { 0261 setProperty("magnitude", i18nc("number in magnitudes", "%1 mag", 0262 QLocale().toString(dso->mag(), 'f', 1))); //show to tenths place 0263 } 0264 0265 //No distances at this point... 0266 setProperty("distance", "--"); 0267 0268 //Only show decimal place for small angular sizes 0269 if (dso->a() > 10.0) 0270 { 0271 setProperty("angSize", 0272 i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 'f', 0))); 0273 } 0274 else if (dso->a()) 0275 { 0276 setProperty("angSize", 0277 i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 'f', 1))); 0278 } 0279 else 0280 { 0281 setProperty("angSize", "--"); 0282 } 0283 0284 break; 0285 } 0286 } 0287 0288 //Reset advanced properties 0289 setProperty("perihilion", ""); 0290 setProperty("orbitID", ""); 0291 setProperty("NEO", ""); 0292 setProperty("diameter", ""); 0293 setProperty("rotation", ""); 0294 setProperty("earthMOID", ""); 0295 setProperty("orbitClass", ""); 0296 setProperty("albedo", ""); 0297 setProperty("dimensions", ""); 0298 setProperty("period", ""); 0299 0300 // Add specifics data 0301 switch (selectedObject->type()) 0302 { 0303 case SkyObject::ASTEROID: 0304 { 0305 KSAsteroid *ast = (KSAsteroid *)selectedObject; 0306 0307 // Perihelion 0308 str.setNum(ast->getPerihelion()); 0309 setProperty("perihelion", QString(str + " AU")); 0310 // Earth MOID 0311 if (ast->getEarthMOID() == 0) 0312 str = ""; 0313 else 0314 str.setNum(ast->getEarthMOID()).append(" AU"); 0315 setProperty("earthMOID", str); 0316 // Orbit ID 0317 setProperty("orbitID", ast->getOrbitID()); 0318 // Orbit Class 0319 setProperty("orbitClass", ast->getOrbitClass()); 0320 // NEO 0321 if (ast->isNEO()) 0322 setProperty("NEO", "Yes"); 0323 else 0324 setProperty("NEO", "No"); 0325 // Albedo 0326 if (ast->getAlbedo() == 0.0) 0327 str = ""; 0328 else 0329 str.setNum(ast->getAlbedo()); 0330 setProperty("albedo", str); 0331 // Diameter 0332 if (ast->getDiameter() == 0.0) 0333 str = ""; 0334 else 0335 str.setNum(ast->getDiameter()).append(" km"); 0336 setProperty("diameter", str); 0337 // Dimensions 0338 if (ast->getDimensions().isEmpty()) 0339 setProperty("dimensions", ""); 0340 else 0341 setProperty("dimensions", QString(ast->getDimensions() + " km")); 0342 // Rotation period 0343 if (ast->getRotationPeriod() == 0.0) 0344 str = ""; 0345 else 0346 str.setNum(ast->getRotationPeriod()).append(" h"); 0347 setProperty("rotation", str); 0348 // Period 0349 if (ast->getPeriod() == 0.0) 0350 str = ""; 0351 else 0352 str.setNum(ast->getPeriod()).append(" y"); 0353 setProperty("period", str); 0354 0355 break; 0356 } 0357 case SkyObject::COMET: 0358 { 0359 KSComet *com = (KSComet *)selectedObject; 0360 0361 // Perihelion 0362 str.setNum(com->getPerihelion()); 0363 setProperty("perihelion", QString(str + " AU")); 0364 // Earth MOID 0365 if (com->getEarthMOID() == 0) 0366 str = ""; 0367 else 0368 str.setNum(com->getEarthMOID()).append(" AU"); 0369 setProperty("earthMOID", str); 0370 // Orbit ID 0371 setProperty("orbitID", com->getOrbitID()); 0372 // Orbit Class 0373 setProperty("orbitClass", com->getOrbitClass()); 0374 // NEO 0375 if (com->isNEO()) 0376 setProperty("NEO", "Yes"); 0377 else 0378 setProperty("NEO", "No"); 0379 // Albedo 0380 if (com->getAlbedo() == 0.0) 0381 str = ""; 0382 else 0383 str.setNum(com->getAlbedo()); 0384 setProperty("albedo", str); 0385 // Diameter 0386 if (com->getDiameter() == 0.0) 0387 str = ""; 0388 else 0389 str.setNum(com->getDiameter()).append(" km"); 0390 setProperty("diameter", str); 0391 // Dimensions 0392 if (com->getDimensions().isEmpty()) 0393 setProperty("dimensions", ""); 0394 else 0395 setProperty("dimensions", QString(com->getDimensions() + " km")); 0396 // Rotation period 0397 if (com->getRotationPeriod() == 0.0) 0398 str = ""; 0399 else 0400 str.setNum(com->getRotationPeriod()).append(" h"); 0401 setProperty("rotation", str); 0402 // Period 0403 if (com->getPeriod() == 0.0) 0404 str = ""; 0405 else 0406 str.setNum(com->getPeriod()).append(" y"); 0407 setProperty("period", str); 0408 0409 break; 0410 } 0411 } 0412 0413 //Common to all types: 0414 QString cname = KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(selectedObject); 0415 if (selectedObject->type() != SkyObject::CONSTELLATION) 0416 { 0417 cname = i18nc("%1 type of sky object (planet, asteroid etc), %2 name of a constellation", "%1 in %2", objecttyp, 0418 cname); 0419 } 0420 setProperty("typeInConstellation", cname); 0421 } 0422 0423 void DetailDialogLite::createPositionTab() 0424 { 0425 KStarsData *data = KStarsData::Instance(); 0426 KStarsDateTime ut = data->ut(); 0427 GeoLocation *geo = data->geo(); 0428 0429 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0430 0431 //Coordinates Section: 0432 //Don't use KLocale::formatNumber() for the epoch string, 0433 //because we don't want a thousands-place separator! 0434 QString sEpoch = QString::number(ut.epoch(), 'f', 1); 0435 //Replace the decimal point with localized decimal symbol 0436 sEpoch.replace('.', QLocale().decimalPoint()); 0437 0438 qDebug() << (selectedObject->deprecess(data->updateNum(), 2451545.0l)).ra0().toHMSString() 0439 << (selectedObject->deprecess(data->updateNum(), 2451545.0l)).dec0().toDMSString() << endl; 0440 //qDebug() << selectedObject->ra().toHMSString() << selectedObject->dec().toDMSString() << endl; 0441 setProperty("RALabel", i18n("RA (%1):", sEpoch)); 0442 setProperty("decLabel", i18n("Dec (%1):", sEpoch)); 0443 setProperty("RA", selectedObject->ra().toHMSString()); 0444 setProperty("dec", selectedObject->dec().toDMSString()); 0445 0446 selectedObject->EquatorialToHorizontal(data->lst(), data->geo()->lat()); 0447 0448 setProperty("az", selectedObject->az().toDMSString()); 0449 dms a; 0450 0451 if (Options::useAltAz()) 0452 a = selectedObject->alt(); 0453 else 0454 a = selectedObject->altRefracted(); 0455 setProperty("alt", a.toDMSString()); 0456 0457 // Display the RA0 and Dec0 for objects that are outside the solar system 0458 if (!selectedObject->isSolarSystem()) 0459 { 0460 setProperty("RA0", selectedObject->ra0().toHMSString()); 0461 setProperty("dec0", selectedObject->dec0().toDMSString()); 0462 } 0463 else 0464 { 0465 setProperty("RA0", "--"); 0466 setProperty("dec0", "--"); 0467 } 0468 0469 //Hour Angle can be negative, but dms HMS expressions cannot. 0470 //Here's a kludgy workaround: 0471 dms lst = geo->GSTtoLST(ut.gst()); 0472 dms ha(lst.Degrees() - selectedObject->ra().Degrees()); 0473 QChar sgn('+'); 0474 if (ha.Hours() > 12.0) 0475 { 0476 ha.setH(24.0 - ha.Hours()); 0477 sgn = '-'; 0478 } 0479 setProperty("HA", QString("%1%2").arg(sgn).arg(ha.toHMSString())); 0480 0481 //Airmass is approximated as the secant of the zenith distance, 0482 //equivalent to 1./sin(Alt). Beware of Inf at Alt=0! 0483 if (selectedObject->alt().Degrees() > 0.0) 0484 setProperty("airmass", QLocale().toString(selectedObject->airmass(), 'f', 2)); 0485 else 0486 setProperty("airmass", "--"); 0487 0488 //Rise/Set/Transit Section: 0489 0490 //Prepare time/position variables 0491 QTime rt = selectedObject->riseSetTime(ut, geo, true); //true = use rise time 0492 dms raz = selectedObject->riseSetTimeAz(ut, geo, true); //true = use rise time 0493 0494 //If transit time is before rise time, use transit time for tomorrow 0495 QTime tt = selectedObject->transitTime(ut, geo); 0496 dms talt = selectedObject->transitAltitude(ut, geo); 0497 if (tt < rt) 0498 { 0499 tt = selectedObject->transitTime(ut.addDays(1), geo); 0500 talt = selectedObject->transitAltitude(ut.addDays(1), geo); 0501 } 0502 0503 //If set time is before rise time, use set time for tomorrow 0504 QTime st = selectedObject->riseSetTime(ut, geo, false); //false = use set time 0505 dms saz = selectedObject->riseSetTimeAz(ut, geo, false); //false = use set time 0506 if (st < rt) 0507 { 0508 st = selectedObject->riseSetTime(ut.addDays(1), geo, false); //false = use set time 0509 saz = selectedObject->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time 0510 } 0511 0512 if (rt.isValid()) 0513 { 0514 setProperty("timeRise", QString().sprintf("%02d:%02d", rt.hour(), rt.minute())); 0515 setProperty("timeSet", QString().sprintf("%02d:%02d", st.hour(), st.minute())); 0516 setProperty("azRise", raz.toDMSString()); 0517 setProperty("azSet", saz.toDMSString()); 0518 } 0519 else 0520 { 0521 if (selectedObject->alt().Degrees() > 0.0) 0522 { 0523 setProperty("timeRise", i18n("Circumpolar")); 0524 setProperty("timeSet", i18n("Circumpolar")); 0525 } 0526 else 0527 { 0528 setProperty("timeRise", i18n("Never rises")); 0529 setProperty("timeSet", i18n("Never rises")); 0530 } 0531 0532 setProperty("azRise", i18nc("Not Applicable", "N/A")); 0533 setProperty("azSet", i18nc("Not Applicable", "N/A")); 0534 } 0535 0536 setProperty("timeTransit", QString().sprintf("%02d:%02d", tt.hour(), tt.minute())); 0537 setProperty("altTransit", talt.toDMSString()); 0538 0539 // Restore the position and other time-dependent parameters 0540 selectedObject->recomputeCoords(ut, geo); 0541 } 0542 0543 void DetailDialogLite::createLogTab() 0544 { 0545 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0546 //Don't create a log tab for an unnamed star 0547 if (selectedObject->name() == QString("star")) 0548 { 0549 setProperty("isLogOn", false); 0550 return; 0551 } 0552 setProperty("isLogOn", true); 0553 0554 if (selectedObject->userLog().isEmpty()) 0555 { 0556 setProperty("userLog", 0557 i18n("Record here observation logs and/or data on %1.", selectedObject->translatedName())); 0558 } 0559 else 0560 { 0561 setProperty("userLog", selectedObject->userLog()); 0562 } 0563 0564 /*//Automatically save the log contents when the widget loses focus 0565 connect( Log->UserLog, SIGNAL(focusOut()), this, SLOT(saveLogData()) );*/ 0566 } 0567 0568 void DetailDialogLite::createLinksTab() 0569 { 0570 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0571 0572 //No links for unnamed stars 0573 if (selectedObject->name() == QString("star")) 0574 { 0575 setProperty("isLinksOn", false); 0576 return; 0577 } 0578 0579 setProperty("isLinksOn", true); 0580 0581 QStringList newInfoList; 0582 foreach (const QString &s, selectedObject->InfoTitle()) 0583 newInfoList.append(i18nc("Image/info menu item (should be translated)", s.toLocal8Bit())); 0584 setProperty("infoTitleList", newInfoList); 0585 0586 QStringList newImageList; 0587 foreach (const QString &s, selectedObject->ImageTitle()) 0588 newImageList.append(i18nc("Image/info menu item (should be translated)", s.toLocal8Bit())); 0589 0590 setProperty("imageTitleList", newImageList); 0591 } 0592 0593 void DetailDialogLite::updateLocalDatabase(int type, const QString &search_line, const QString &replace_line) 0594 { 0595 QString TempFileName, file_line; 0596 QFile URLFile; 0597 QTemporaryFile TempFile; 0598 QTextStream *temp_stream = nullptr; 0599 QTextStream *out_stream = nullptr; 0600 bool replace = !replace_line.isEmpty(); 0601 0602 if (search_line.isEmpty()) 0603 return; 0604 0605 TempFile.setAutoRemove(false); 0606 TempFile.open(); 0607 TempFileName = TempFile.fileName(); 0608 0609 switch (type) 0610 { 0611 // Info Links 0612 case 0: 0613 // Get name for our local info_url file 0614 URLFile.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("info_url.dat")); 0615 break; 0616 0617 // Image Links 0618 case 1: 0619 // Get name for our local info_url file 0620 URLFile.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("image_url.dat")); 0621 break; 0622 } 0623 0624 if (!URLFile.open(QIODevice::ReadWrite)) 0625 { 0626 qDebug() << "DetailDialog: Failed to open " << URLFile.fileName(); 0627 qDebug() << "KStars cannot save to user database"; 0628 return; 0629 } 0630 0631 // Copy URL file to temp file 0632 TempFile.write(URLFile.readAll()); 0633 //Return pointers to initial positions 0634 TempFile.seek(0); 0635 //Clear URLFile 0636 URLFile.resize(0); 0637 0638 // Get streams; 0639 temp_stream = new QTextStream(&TempFile); 0640 out_stream = new QTextStream(&URLFile); 0641 0642 while (!temp_stream->atEnd()) 0643 { 0644 file_line = temp_stream->readLine(); 0645 // If we find a match, either replace, or remove (by skipping). 0646 if (file_line == search_line) 0647 { 0648 if (replace) 0649 (*out_stream) << replace_line << endl; 0650 else 0651 continue; 0652 } 0653 else 0654 (*out_stream) << file_line << endl; 0655 } 0656 0657 URLFile.close(); 0658 delete temp_stream; 0659 delete out_stream; 0660 } 0661 0662 void DetailDialogLite::addLink(const QString &url, const QString &desc, bool isImageLink) 0663 { 0664 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0665 0666 if (url.isEmpty() || desc.isEmpty()) 0667 return; //Do nothing if empty url or desc were provided 0668 0669 QString entry; 0670 QFile file; 0671 0672 if (isImageLink) 0673 { 0674 //Add link to object's ImageList, and descriptive text to its ImageTitle list 0675 selectedObject->ImageList().append(url); 0676 selectedObject->ImageTitle().append(desc); 0677 0678 //Also, update the user's custom image links database 0679 //check for user's image-links database. If it doesn't exist, create it. 0680 //determine filename in local user KDE directory tree. 0681 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("image_url.dat")); 0682 0683 if (!file.open(QIODevice::ReadWrite | QIODevice::Append)) 0684 { 0685 QString message = 0686 i18n("Custom image-links file could not be opened.\nLink cannot be recorded for future sessions."); 0687 qDebug() << message; 0688 return; 0689 } 0690 else 0691 { 0692 entry = selectedObject->name() + ':' + desc + ':' + url; 0693 QTextStream stream(&file); 0694 stream << entry << endl; 0695 file.close(); 0696 setProperty("imageTitleList", selectedObject->ImageTitle()); 0697 } 0698 } 0699 else 0700 { 0701 selectedObject->InfoList().append(url); 0702 selectedObject->InfoTitle().append(desc); 0703 0704 //check for user's image-links database. If it doesn't exist, create it. 0705 //determine filename in local user KDE directory tree. 0706 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("info_url.dat")); 0707 0708 if (!file.open(QIODevice::ReadWrite | QIODevice::Append)) 0709 { 0710 QString message = i18n( 0711 "Custom information-links file could not be opened.\nLink cannot be recorded for future sessions."); 0712 qDebug() << message; 0713 return; 0714 } 0715 else 0716 { 0717 entry = selectedObject->name() + ':' + desc + ':' + url; 0718 QTextStream stream(&file); 0719 stream << entry << endl; 0720 file.close(); 0721 setProperty("infoTitleList", selectedObject->InfoTitle()); 0722 } 0723 } 0724 } 0725 0726 void DetailDialogLite::removeLink(int itemIndex, bool isImage) 0727 { 0728 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0729 0730 QString currentItemURL, currentItemTitle, LineEntry, TempFileName, FileLine; 0731 QFile URLFile; 0732 QTemporaryFile TempFile; 0733 TempFile.setAutoRemove(false); 0734 TempFile.open(); 0735 TempFileName = TempFile.fileName(); 0736 0737 //Check if it is a valid index 0738 if (itemIndex < 0) 0739 { 0740 return; 0741 } 0742 else if (isImage && itemIndex >= selectedObject->ImageTitle().length()) 0743 { 0744 return; 0745 } 0746 else if (!isImage && itemIndex >= selectedObject->InfoTitle().length()) 0747 { 0748 return; 0749 } 0750 //if (title.isEmpty() || url.isEmpty()) return; 0751 0752 if (!isImage) //Information 0753 { 0754 currentItemTitle = selectedObject->InfoTitle()[itemIndex]; 0755 currentItemURL = selectedObject->InfoList()[itemIndex]; 0756 LineEntry = selectedObject->name(); 0757 LineEntry += ':'; 0758 LineEntry += currentItemTitle; 0759 LineEntry += ':'; 0760 LineEntry += currentItemURL; 0761 } 0762 else //Image 0763 { 0764 currentItemTitle = selectedObject->ImageTitle()[itemIndex]; 0765 currentItemURL = selectedObject->ImageList()[itemIndex]; 0766 LineEntry = selectedObject->name(); 0767 LineEntry += ':'; 0768 LineEntry += currentItemTitle; 0769 LineEntry += ':'; 0770 LineEntry += currentItemURL; 0771 } 0772 0773 /*if (KMessageBox::warningContinueCancel( 0, i18n("Are you sure you want to remove the %1 link?", currentItemTitle), i18n("Delete Confirmation"),KStandardGuiItem::del())!=KMessageBox::Continue) 0774 return;*/ 0775 0776 if (isImage) 0777 { 0778 selectedObject->ImageTitle().removeAt(itemIndex); 0779 selectedObject->ImageList().removeAt(itemIndex); 0780 } 0781 else 0782 { 0783 selectedObject->InfoTitle().removeAt(itemIndex); 0784 selectedObject->InfoList().removeAt(itemIndex); 0785 } 0786 0787 // Remove link from file 0788 updateLocalDatabase(isImage ? 1 : 0, LineEntry); 0789 0790 setProperty("infoTitleList", selectedObject->InfoTitle()); 0791 setProperty("imageTitleList", selectedObject->ImageTitle()); 0792 } 0793 0794 void DetailDialogLite::editLink(int itemIndex, bool isImage, const QString &desc, const QString &url) 0795 { 0796 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0797 0798 if (url.isEmpty() || desc.isEmpty()) 0799 return; //Do nothing if empty url or desc were provided 0800 0801 QString search_line, replace_line, currentItemTitle, currentItemURL; 0802 0803 //Check if it is a valid index 0804 if (itemIndex < 0) 0805 { 0806 return; 0807 } 0808 else if (isImage && itemIndex >= selectedObject->ImageTitle().length()) 0809 { 0810 return; 0811 } 0812 else if (!isImage && itemIndex >= selectedObject->InfoTitle().length()) 0813 { 0814 return; 0815 } 0816 0817 if (!isImage) //Information 0818 { 0819 currentItemTitle = selectedObject->InfoTitle()[itemIndex]; 0820 currentItemURL = selectedObject->InfoList()[itemIndex]; 0821 search_line = selectedObject->name(); 0822 search_line += ':'; 0823 search_line += currentItemTitle; 0824 search_line += ':'; 0825 search_line += currentItemURL; 0826 } 0827 else //Image 0828 { 0829 currentItemTitle = selectedObject->ImageTitle()[itemIndex]; 0830 currentItemURL = selectedObject->ImageList()[itemIndex]; 0831 search_line = selectedObject->name(); 0832 search_line += ':'; 0833 search_line += currentItemTitle; 0834 search_line += ':'; 0835 search_line += currentItemURL; 0836 } 0837 0838 bool go(true); 0839 0840 // If nothing changed, skip th action 0841 if (url == currentItemURL && desc == currentItemTitle) 0842 go = false; 0843 0844 if (go) 0845 { 0846 replace_line = selectedObject->name() + ':' + desc + ':' + url; 0847 0848 // Info Link 0849 if (!isImage) 0850 { 0851 selectedObject->InfoTitle().replace(itemIndex, desc); 0852 selectedObject->InfoList().replace(itemIndex, url); 0853 0854 // Image Links 0855 } 0856 else 0857 { 0858 selectedObject->ImageTitle().replace(itemIndex, desc); 0859 selectedObject->ImageList().replace(itemIndex, url); 0860 } 0861 0862 // Update local files 0863 updateLocalDatabase(isImage ? 1 : 0, search_line, replace_line); 0864 0865 setProperty("infoTitleList", selectedObject->InfoTitle()); 0866 setProperty("imageTitleList", selectedObject->ImageTitle()); 0867 } 0868 } 0869 0870 QString DetailDialogLite::getInfoURL(int index) 0871 { 0872 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0873 QStringList urls = selectedObject->InfoList(); 0874 if (index >= 0 && index < urls.size()) 0875 { 0876 return urls[index]; 0877 } 0878 else 0879 { 0880 return ""; 0881 } 0882 } 0883 0884 QString DetailDialogLite::getImageURL(int index) 0885 { 0886 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0887 QStringList urls = selectedObject->ImageList(); 0888 if (index >= 0 && index < urls.size()) 0889 { 0890 return urls[index]; 0891 } 0892 else 0893 { 0894 return ""; 0895 } 0896 } 0897 0898 void DetailDialogLite::setupThumbnail() 0899 { 0900 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0901 //No image if object is a star 0902 if (selectedObject->type() == SkyObject::STAR || selectedObject->type() == SkyObject::CATALOG_STAR) 0903 { 0904 /*Thumbnail->scaled( Data->Image->width(), Data->Image->height() ); 0905 Thumbnail->fill( Data->DataFrame->palette().color( QPalette::Window ) ); 0906 Data->Image->setPixmap( *Thumbnail );*/ 0907 setProperty("thumbnail", ""); 0908 return; 0909 } 0910 0911 //Try to load the object's image from disk 0912 //If no image found, load "no image" image 0913 QFile file; 0914 QString fname = "thumb-" + selectedObject->name().toLower().remove(' ') + ".png"; 0915 if (KSUtils::openDataFile(file, fname)) 0916 { 0917 file.close(); 0918 setProperty("thumbnail", file.fileName()); 0919 } 0920 else 0921 { 0922 setProperty("thumbnail", ""); 0923 } 0924 } 0925 0926 /*void DetailDialogLite::viewResource(int itemIndex, bool isImage) { 0927 QString url; 0928 if(isImage) { 0929 url = getImageURL(itemIndex); 0930 } else { 0931 url = getInfoURL(itemIndex); 0932 } 0933 QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); 0934 }*/ 0935 0936 void DetailDialogLite::saveLogData(const QString &userLog) 0937 { 0938 SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject(); 0939 0940 selectedObject->saveUserLog(userLog); 0941 }