1 /*
2     SPDX-FileCopyrightText: 2016 Artem Fedoskin <afedoskin3@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "detaildialoglite.h"
8 
9 #include "constellationboundarylines.h"
10 #include "deepskyobject.h"
11 #include "kspaths.h"
12 #include "ksutils.h"
13 #include "Options.h"
14 #include "skymapcomposite.h"
15 #include "skymaplite.h"
16 #include "starobject.h"
17 #include "kstarslite/skyobjectlite.h"
18 #include "skyobjects/ksasteroid.h"
19 #include "skyobjects/kscomet.h"
20 #include "skyobjects/ksmoon.h"
21 #include "skyobjects/ksplanetbase.h"
22 #include "skyobjects/supernova.h"
23 
24 #include <QDesktopServices>
25 #include <QTemporaryFile>
26 
DetailDialogLite()27 DetailDialogLite::DetailDialogLite()
28 {
29     setProperty("isLinksOn", true);
30     setProperty("isLogOn", true);
31 }
32 
initialize()33 void DetailDialogLite::initialize()
34 {
35     connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createGeneralTab()));
36     connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createPositionTab()));
37     connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createLogTab()));
38     connect(SkyMapLite::Instance(), SIGNAL(objectLiteChanged()), this, SLOT(createLinksTab()));
39 }
40 
createGeneralTab()41 void DetailDialogLite::createGeneralTab()
42 {
43     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
44 
45     // Stuff that should be visible only for specific types of objects
46     setProperty("illumination", ""); // Only shown for the moon
47     setProperty("BVindex", "");      // Only shown for stars
48     setupThumbnail();
49 
50     //Fill in the data fields
51     //Contents depend on type of object
52     QString objecttyp, str;
53 
54     switch (selectedObject->type())
55     {
56         case SkyObject::STAR:
57         {
58             StarObject *s = (StarObject *)selectedObject;
59 
60             if (s->getHDIndex())
61             {
62                 setProperty("name", (QString("%1, HD %2").arg(s->longname()).arg(s->getHDIndex())));
63             }
64             else
65             {
66                 setProperty("name", s->longname());
67             }
68 
69             objecttyp = s->sptype() + ' ' + i18n("star");
70             setProperty("magnitude", i18nc("number in magnitudes", "%1 mag",
71                                            QLocale().toString(s->mag(), 'f', 2))); //show to hundredth place
72 
73             if (s->getBVIndex() < 30.)
74             {
75                 setProperty("BVindex", QString::number(s->getBVIndex(), 'f', 2));
76             }
77 
78             //distance
79             if (s->distance() > 2000. || s->distance() < 0.) // parallax < 0.5 mas
80             {
81                 setProperty("distance", (QString(i18nc("larger than 2000 parsecs", "> 2000 pc"))));
82             }
83             else if (s->distance() > 50.) //show to nearest integer
84             {
85                 setProperty("distance",
86                             (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 0))));
87             }
88             else if (s->distance() > 10.0) //show to tenths place
89             {
90                 setProperty("distance",
91                             (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 1))));
92             }
93             else //show to hundredths place
94             {
95                 setProperty("distance",
96                             (i18nc("number in parsecs", "%1 pc", QLocale().toString(s->distance(), 'f', 2))));
97             }
98 
99             //Note multiplicity/variability in angular size label
100             setProperty("angSize", QString());
101             if (s->isMultiple() && s->isVariable())
102             {
103                 QString multiple = QString(i18nc("the star is a multiple star", "multiple") + ',');
104                 setProperty("angSize", QString(multiple + '\n' + (i18nc("the star is a variable star", "variable"))));
105             }
106             else if (s->isMultiple())
107             {
108                 setProperty("angSize", i18nc("the star is a multiple star", "multiple"));
109             }
110             else if (s->isVariable())
111             {
112                 setProperty("angSize", (i18nc("the star is a variable star", "variable")));
113             }
114 
115             break; //end of stars case
116         }
117         case SkyObject::ASTEROID: //[fall through to planets]
118         case SkyObject::COMET:    //[fall through to planets]
119         case SkyObject::MOON:     //[fall through to planets]
120         case SkyObject::PLANET:
121         {
122             KSPlanetBase *ps = (KSPlanetBase *)selectedObject;
123 
124             setProperty("name", ps->longname());
125 
126             //Type is "G5 star" for Sun
127             if (ps->name() == "Sun")
128             {
129                 objecttyp = i18n("G5 star");
130             }
131             else if (ps->name() == "Moon")
132             {
133                 objecttyp = ps->translatedName();
134             }
135             else if (ps->name() == i18n("Pluto") || ps->name() == "Ceres" ||
136                      ps->name() == "Eris") // TODO: Check if Ceres / Eris have translations and i18n() them
137             {
138                 objecttyp = i18n("Dwarf planet");
139             }
140             else
141             {
142                 objecttyp = ps->typeName();
143             }
144 
145             //The moon displays illumination fraction and updateMag is called to calculate moon's current magnitude
146             if (selectedObject->name() == "Moon")
147             {
148                 setProperty(
149                     "illumination",
150                     (QString("%1 %").arg(QLocale().toString(((KSMoon *)selectedObject)->illum() * 100., 'f', 0))));
151                 ((KSMoon *)selectedObject)->updateMag();
152             }
153 
154             // JM: Shouldn't we use the calculated magnitude? Disabling the following
155             /*
156                     if(selectedObject->type() == SkyObject::COMET){
157                         Data->Magnitude->setText(i18nc("number in magnitudes", "%1 mag",
158                                                  QLocale().toString( ((KSComet *)selectedObject)->getTotalMagnitudeParameter(), 'f', 2)));  //show to hundredth place
159 
160                     }
161                     else{*/
162             setProperty("magnitude", (i18nc("number in magnitudes", "%1 mag",
163                                             QLocale().toString(ps->mag(), 'f', 2)))); //show to hundredth place
164             //}
165 
166             //Distance from Earth.  The moon requires a unit conversion
167             if (ps->name() == "Moon")
168             {
169                 setProperty("distance", (i18nc("distance in kilometers", "%1 km",
170                                                QLocale().toString(ps->rearth() * AU_KM, 'f', 2))));
171             }
172             else
173             {
174                 setProperty("distance", (i18nc("distance in Astronomical Units", "%1 AU",
175                                                QLocale().toString(ps->rearth(), 'f', 3))));
176             }
177 
178             //Angular size; moon and sun in arcmin, others in arcsec
179             if (ps->angSize())
180             {
181                 if (ps->name() == "Sun" || ps->name() == "Moon")
182                 {
183                     setProperty(
184                         "angSize",
185                         (i18nc(
186                             "angular size in arcminutes", "%1 arcmin",
187                             QLocale().toString(
188                                 ps->angSize(), 'f',
189                                 1)))); // Needn't be a plural form because sun / moon will never contract to 1 arcminute
190                 }
191                 else
192                 {
193                     setProperty("angSize", i18nc("angular size in arcseconds", "%1 arcsec",
194                                                  QLocale().toString(ps->angSize() * 60.0, 'f', 1)));
195                 }
196             }
197             else
198             {
199                 setProperty("angSize", "--");
200             }
201 
202             break; //end of planets/comets/asteroids case
203         }
204         case SkyObject::SUPERNOVA:
205         {
206             Supernova *sup = (Supernova *)selectedObject;
207 
208             objecttyp = i18n("Supernova");
209             setProperty("name", sup->name());
210             setProperty("magnitude", (i18nc("number in magnitudes", "%1 mag", QLocale().toString(sup->mag(), 'f', 2))));
211             setProperty("distance", "---");
212             break;
213         }
214         default: //deep-sky objects
215         {
216             DeepSkyObject *dso = (DeepSkyObject *)selectedObject;
217 
218             //Show all names recorded for the object
219             QStringList nameList;
220             if (!dso->longname().isEmpty() && dso->longname() != dso->name())
221             {
222                 nameList.append(dso->translatedLongName());
223                 nameList.append(dso->translatedName());
224             }
225             else
226             {
227                 nameList.append(dso->translatedName());
228             }
229 
230             if (!dso->translatedName2().isEmpty())
231             {
232                 nameList.append(dso->translatedName2());
233             }
234 
235             if (dso->ugc() != 0)
236             {
237                 nameList.append(QString("UGC %1").arg(dso->ugc()));
238             }
239 
240             if (dso->pgc() != 0)
241             {
242                 nameList.append(QString("PGC %1").arg(dso->pgc()));
243             }
244 
245             setProperty("name", nameList.join(","));
246 
247             objecttyp = dso->typeName();
248 
249             if (dso->type() == SkyObject::RADIO_SOURCE)
250             {
251                 //ta->MagLabel->setText(i18nc("integrated flux at a frequency", "Flux(%1):", dso->customCatalog()->fluxFrequency()));
252                 //Data->Magnitude->setText(i18nc("integrated flux value", "%1 %2",
253                 //                             QLocale().toString(dso->flux(), 'f', 1), dso->customCatalog()->fluxUnit()));  //show to tenths place
254             }
255             else if (dso->mag() > 90.0)
256             {
257                 setProperty("magnitude", "--");
258             }
259             else
260             {
261                 setProperty("magnitude", i18nc("number in magnitudes", "%1 mag",
262                                                QLocale().toString(dso->mag(), 'f', 1))); //show to tenths place
263             }
264 
265             //No distances at this point...
266             setProperty("distance", "--");
267 
268             //Only show decimal place for small angular sizes
269             if (dso->a() > 10.0)
270             {
271                 setProperty("angSize",
272                             i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 'f', 0)));
273             }
274             else if (dso->a())
275             {
276                 setProperty("angSize",
277                             i18nc("angular size in arcminutes", "%1 arcmin", QLocale().toString(dso->a(), 'f', 1)));
278             }
279             else
280             {
281                 setProperty("angSize", "--");
282             }
283 
284             break;
285         }
286     }
287 
288     //Reset advanced properties
289     setProperty("perihilion", "");
290     setProperty("orbitID", "");
291     setProperty("NEO", "");
292     setProperty("diameter", "");
293     setProperty("rotation", "");
294     setProperty("earthMOID", "");
295     setProperty("orbitClass", "");
296     setProperty("albedo", "");
297     setProperty("dimensions", "");
298     setProperty("period", "");
299 
300     // Add specifics data
301     switch (selectedObject->type())
302     {
303         case SkyObject::ASTEROID:
304         {
305             KSAsteroid *ast = (KSAsteroid *)selectedObject;
306 
307             // Perihelion
308             str.setNum(ast->getPerihelion());
309             setProperty("perihelion", QString(str + " AU"));
310             // Earth MOID
311             if (ast->getEarthMOID() == 0)
312                 str = "";
313             else
314                 str.setNum(ast->getEarthMOID()).append(" AU");
315             setProperty("earthMOID", str);
316             // Orbit ID
317             setProperty("orbitID", ast->getOrbitID());
318             // Orbit Class
319             setProperty("orbitClass", ast->getOrbitClass());
320             // NEO
321             if (ast->isNEO())
322                 setProperty("NEO", "Yes");
323             else
324                 setProperty("NEO", "No");
325             // Albedo
326             if (ast->getAlbedo() == 0.0)
327                 str = "";
328             else
329                 str.setNum(ast->getAlbedo());
330             setProperty("albedo", str);
331             // Diameter
332             if (ast->getDiameter() == 0.0)
333                 str = "";
334             else
335                 str.setNum(ast->getDiameter()).append(" km");
336             setProperty("diameter", str);
337             // Dimensions
338             if (ast->getDimensions().isEmpty())
339                 setProperty("dimensions", "");
340             else
341                 setProperty("dimensions", QString(ast->getDimensions() + " km"));
342             // Rotation period
343             if (ast->getRotationPeriod() == 0.0)
344                 str = "";
345             else
346                 str.setNum(ast->getRotationPeriod()).append(" h");
347             setProperty("rotation", str);
348             // Period
349             if (ast->getPeriod() == 0.0)
350                 str = "";
351             else
352                 str.setNum(ast->getPeriod()).append(" y");
353             setProperty("period", str);
354 
355             break;
356         }
357         case SkyObject::COMET:
358         {
359             KSComet *com = (KSComet *)selectedObject;
360 
361             // Perihelion
362             str.setNum(com->getPerihelion());
363             setProperty("perihelion", QString(str + " AU"));
364             // Earth MOID
365             if (com->getEarthMOID() == 0)
366                 str = "";
367             else
368                 str.setNum(com->getEarthMOID()).append(" AU");
369             setProperty("earthMOID", str);
370             // Orbit ID
371             setProperty("orbitID", com->getOrbitID());
372             // Orbit Class
373             setProperty("orbitClass", com->getOrbitClass());
374             // NEO
375             if (com->isNEO())
376                 setProperty("NEO", "Yes");
377             else
378                 setProperty("NEO", "No");
379             // Albedo
380             if (com->getAlbedo() == 0.0)
381                 str = "";
382             else
383                 str.setNum(com->getAlbedo());
384             setProperty("albedo", str);
385             // Diameter
386             if (com->getDiameter() == 0.0)
387                 str = "";
388             else
389                 str.setNum(com->getDiameter()).append(" km");
390             setProperty("diameter", str);
391             // Dimensions
392             if (com->getDimensions().isEmpty())
393                 setProperty("dimensions", "");
394             else
395                 setProperty("dimensions", QString(com->getDimensions() + " km"));
396             // Rotation period
397             if (com->getRotationPeriod() == 0.0)
398                 str = "";
399             else
400                 str.setNum(com->getRotationPeriod()).append(" h");
401             setProperty("rotation", str);
402             // Period
403             if (com->getPeriod() == 0.0)
404                 str = "";
405             else
406                 str.setNum(com->getPeriod()).append(" y");
407             setProperty("period", str);
408 
409             break;
410         }
411     }
412 
413     //Common to all types:
414     QString cname = KStarsData::Instance()->skyComposite()->constellationBoundary()->constellationName(selectedObject);
415     if (selectedObject->type() != SkyObject::CONSTELLATION)
416     {
417         cname = i18nc("%1 type of sky object (planet, asteroid etc), %2 name of a constellation", "%1 in %2", objecttyp,
418                       cname);
419     }
420     setProperty("typeInConstellation", cname);
421 }
422 
createPositionTab()423 void DetailDialogLite::createPositionTab()
424 {
425     KStarsData *data  = KStarsData::Instance();
426     KStarsDateTime ut = data->ut();
427     GeoLocation *geo  = data->geo();
428 
429     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
430 
431     //Coordinates Section:
432     //Don't use KLocale::formatNumber() for the epoch string,
433     //because we don't want a thousands-place separator!
434     QString sEpoch = QString::number(ut.epoch(), 'f', 1);
435     //Replace the decimal point with localized decimal symbol
436     sEpoch.replace('.', QLocale().decimalPoint());
437 
438     qDebug() << (selectedObject->deprecess(data->updateNum(), 2451545.0l)).ra0().toHMSString()
439              << (selectedObject->deprecess(data->updateNum(), 2451545.0l)).dec0().toDMSString() << endl;
440     //qDebug() << selectedObject->ra().toHMSString() << selectedObject->dec().toDMSString() << endl;
441     setProperty("RALabel", i18n("RA (%1):", sEpoch));
442     setProperty("decLabel", i18n("Dec (%1):", sEpoch));
443     setProperty("RA", selectedObject->ra().toHMSString());
444     setProperty("dec", selectedObject->dec().toDMSString());
445 
446     selectedObject->EquatorialToHorizontal(data->lst(), data->geo()->lat());
447 
448     setProperty("az", selectedObject->az().toDMSString());
449     dms a;
450 
451     if (Options::useAltAz())
452         a = selectedObject->alt();
453     else
454         a = selectedObject->altRefracted();
455     setProperty("alt", a.toDMSString());
456 
457     // Display the RA0 and Dec0 for objects that are outside the solar system
458     if (!selectedObject->isSolarSystem())
459     {
460         setProperty("RA0", selectedObject->ra0().toHMSString());
461         setProperty("dec0", selectedObject->dec0().toDMSString());
462     }
463     else
464     {
465         setProperty("RA0", "--");
466         setProperty("dec0", "--");
467     }
468 
469     //Hour Angle can be negative, but dms HMS expressions cannot.
470     //Here's a kludgy workaround:
471     dms lst = geo->GSTtoLST(ut.gst());
472     dms ha(lst.Degrees() - selectedObject->ra().Degrees());
473     QChar sgn('+');
474     if (ha.Hours() > 12.0)
475     {
476         ha.setH(24.0 - ha.Hours());
477         sgn = '-';
478     }
479     setProperty("HA", QString("%1%2").arg(sgn).arg(ha.toHMSString()));
480 
481     //Airmass is approximated as the secant of the zenith distance,
482     //equivalent to 1./sin(Alt).  Beware of Inf at Alt=0!
483     if (selectedObject->alt().Degrees() > 0.0)
484         setProperty("airmass", QLocale().toString(selectedObject->airmass(), 'f', 2));
485     else
486         setProperty("airmass", "--");
487 
488     //Rise/Set/Transit Section:
489 
490     //Prepare time/position variables
491     QTime rt = selectedObject->riseSetTime(ut, geo, true);   //true = use rise time
492     dms raz  = selectedObject->riseSetTimeAz(ut, geo, true); //true = use rise time
493 
494     //If transit time is before rise time, use transit time for tomorrow
495     QTime tt = selectedObject->transitTime(ut, geo);
496     dms talt = selectedObject->transitAltitude(ut, geo);
497     if (tt < rt)
498     {
499         tt   = selectedObject->transitTime(ut.addDays(1), geo);
500         talt = selectedObject->transitAltitude(ut.addDays(1), geo);
501     }
502 
503     //If set time is before rise time, use set time for tomorrow
504     QTime st = selectedObject->riseSetTime(ut, geo, false);   //false = use set time
505     dms saz  = selectedObject->riseSetTimeAz(ut, geo, false); //false = use set time
506     if (st < rt)
507     {
508         st  = selectedObject->riseSetTime(ut.addDays(1), geo, false);   //false = use set time
509         saz = selectedObject->riseSetTimeAz(ut.addDays(1), geo, false); //false = use set time
510     }
511 
512     if (rt.isValid())
513     {
514         setProperty("timeRise", QString().sprintf("%02d:%02d", rt.hour(), rt.minute()));
515         setProperty("timeSet", QString().sprintf("%02d:%02d", st.hour(), st.minute()));
516         setProperty("azRise", raz.toDMSString());
517         setProperty("azSet", saz.toDMSString());
518     }
519     else
520     {
521         if (selectedObject->alt().Degrees() > 0.0)
522         {
523             setProperty("timeRise", i18n("Circumpolar"));
524             setProperty("timeSet", i18n("Circumpolar"));
525         }
526         else
527         {
528             setProperty("timeRise", i18n("Never rises"));
529             setProperty("timeSet", i18n("Never rises"));
530         }
531 
532         setProperty("azRise", i18nc("Not Applicable", "N/A"));
533         setProperty("azSet", i18nc("Not Applicable", "N/A"));
534     }
535 
536     setProperty("timeTransit", QString().sprintf("%02d:%02d", tt.hour(), tt.minute()));
537     setProperty("altTransit", talt.toDMSString());
538 
539     // Restore the position and other time-dependent parameters
540     selectedObject->recomputeCoords(ut, geo);
541 }
542 
createLogTab()543 void DetailDialogLite::createLogTab()
544 {
545     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
546     //Don't create a log tab for an unnamed star
547     if (selectedObject->name() == QString("star"))
548     {
549         setProperty("isLogOn", false);
550         return;
551     }
552     setProperty("isLogOn", true);
553 
554     if (selectedObject->userLog().isEmpty())
555     {
556         setProperty("userLog",
557                     i18n("Record here observation logs and/or data on %1.", selectedObject->translatedName()));
558     }
559     else
560     {
561         setProperty("userLog", selectedObject->userLog());
562     }
563 
564     /*//Automatically save the log contents when the widget loses focus
565     connect( Log->UserLog, SIGNAL(focusOut()), this, SLOT(saveLogData()) );*/
566 }
567 
createLinksTab()568 void DetailDialogLite::createLinksTab()
569 {
570     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
571 
572     //No links for unnamed stars
573     if (selectedObject->name() == QString("star"))
574     {
575         setProperty("isLinksOn", false);
576         return;
577     }
578 
579     setProperty("isLinksOn", true);
580 
581     QStringList newInfoList;
582     foreach (const QString &s, selectedObject->InfoTitle())
583         newInfoList.append(i18nc("Image/info menu item (should be translated)", s.toLocal8Bit()));
584     setProperty("infoTitleList", newInfoList);
585 
586     QStringList newImageList;
587     foreach (const QString &s, selectedObject->ImageTitle())
588         newImageList.append(i18nc("Image/info menu item (should be translated)", s.toLocal8Bit()));
589 
590     setProperty("imageTitleList", newImageList);
591 }
592 
updateLocalDatabase(int type,const QString & search_line,const QString & replace_line)593 void DetailDialogLite::updateLocalDatabase(int type, const QString &search_line, const QString &replace_line)
594 {
595     QString TempFileName, file_line;
596     QFile URLFile;
597     QTemporaryFile TempFile;
598     QTextStream *temp_stream = nullptr;
599     QTextStream *out_stream  = nullptr;
600     bool replace             = !replace_line.isEmpty();
601 
602     if (search_line.isEmpty())
603         return;
604 
605     TempFile.setAutoRemove(false);
606     TempFile.open();
607     TempFileName = TempFile.fileName();
608 
609     switch (type)
610     {
611         // Info Links
612         case 0:
613             // Get name for our local info_url file
614             URLFile.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("info_url.dat"));
615             break;
616 
617         // Image Links
618         case 1:
619             // Get name for our local info_url file
620             URLFile.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("image_url.dat"));
621             break;
622     }
623 
624     if (!URLFile.open(QIODevice::ReadWrite))
625     {
626         qDebug() << "DetailDialog: Failed to open " << URLFile.fileName();
627         qDebug() << "KStars cannot save to user database";
628         return;
629     }
630 
631     // Copy URL file to temp file
632     TempFile.write(URLFile.readAll());
633     //Return pointers to initial positions
634     TempFile.seek(0);
635     //Clear URLFile
636     URLFile.resize(0);
637 
638     // Get streams;
639     temp_stream = new QTextStream(&TempFile);
640     out_stream  = new QTextStream(&URLFile);
641 
642     while (!temp_stream->atEnd())
643     {
644         file_line = temp_stream->readLine();
645         // If we find a match, either replace, or remove (by skipping).
646         if (file_line == search_line)
647         {
648             if (replace)
649                 (*out_stream) << replace_line << endl;
650             else
651                 continue;
652         }
653         else
654             (*out_stream) << file_line << endl;
655     }
656 
657     URLFile.close();
658     delete temp_stream;
659     delete out_stream;
660 }
661 
addLink(const QString & url,const QString & desc,bool isImageLink)662 void DetailDialogLite::addLink(const QString &url, const QString &desc, bool isImageLink)
663 {
664     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
665 
666     if (url.isEmpty() || desc.isEmpty())
667         return; //Do nothing if empty url or desc were provided
668 
669     QString entry;
670     QFile file;
671 
672     if (isImageLink)
673     {
674         //Add link to object's ImageList, and descriptive text to its ImageTitle list
675         selectedObject->ImageList().append(url);
676         selectedObject->ImageTitle().append(desc);
677 
678         //Also, update the user's custom image links database
679         //check for user's image-links database.  If it doesn't exist, create it.
680         //determine filename in local user KDE directory tree.
681         file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("image_url.dat"));
682 
683         if (!file.open(QIODevice::ReadWrite | QIODevice::Append))
684         {
685             QString message =
686                 i18n("Custom image-links file could not be opened.\nLink cannot be recorded for future sessions.");
687             qDebug() << message;
688             return;
689         }
690         else
691         {
692             entry = selectedObject->name() + ':' + desc + ':' + url;
693             QTextStream stream(&file);
694             stream << entry << endl;
695             file.close();
696             setProperty("imageTitleList", selectedObject->ImageTitle());
697         }
698     }
699     else
700     {
701         selectedObject->InfoList().append(url);
702         selectedObject->InfoTitle().append(desc);
703 
704         //check for user's image-links database.  If it doesn't exist, create it.
705         //determine filename in local user KDE directory tree.
706         file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("info_url.dat"));
707 
708         if (!file.open(QIODevice::ReadWrite | QIODevice::Append))
709         {
710             QString message = i18n(
711                 "Custom information-links file could not be opened.\nLink cannot be recorded for future sessions.");
712             qDebug() << message;
713             return;
714         }
715         else
716         {
717             entry = selectedObject->name() + ':' + desc + ':' + url;
718             QTextStream stream(&file);
719             stream << entry << endl;
720             file.close();
721             setProperty("infoTitleList", selectedObject->InfoTitle());
722         }
723     }
724 }
725 
removeLink(int itemIndex,bool isImage)726 void DetailDialogLite::removeLink(int itemIndex, bool isImage)
727 {
728     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
729 
730     QString currentItemURL, currentItemTitle, LineEntry, TempFileName, FileLine;
731     QFile URLFile;
732     QTemporaryFile TempFile;
733     TempFile.setAutoRemove(false);
734     TempFile.open();
735     TempFileName = TempFile.fileName();
736 
737     //Check if it is a valid index
738     if (itemIndex < 0)
739     {
740         return;
741     }
742     else if (isImage && itemIndex >= selectedObject->ImageTitle().length())
743     {
744         return;
745     }
746     else if (!isImage && itemIndex >= selectedObject->InfoTitle().length())
747     {
748         return;
749     }
750     //if (title.isEmpty() || url.isEmpty()) return;
751 
752     if (!isImage) //Information
753     {
754         currentItemTitle = selectedObject->InfoTitle()[itemIndex];
755         currentItemURL   = selectedObject->InfoList()[itemIndex];
756         LineEntry        = selectedObject->name();
757         LineEntry += ':';
758         LineEntry += currentItemTitle;
759         LineEntry += ':';
760         LineEntry += currentItemURL;
761     }
762     else //Image
763     {
764         currentItemTitle = selectedObject->ImageTitle()[itemIndex];
765         currentItemURL   = selectedObject->ImageList()[itemIndex];
766         LineEntry        = selectedObject->name();
767         LineEntry += ':';
768         LineEntry += currentItemTitle;
769         LineEntry += ':';
770         LineEntry += currentItemURL;
771     }
772 
773     /*if (KMessageBox::warningContinueCancel( 0, i18n("Are you sure you want to remove the %1 link?", currentItemTitle), i18n("Delete Confirmation"),KStandardGuiItem::del())!=KMessageBox::Continue)
774         return;*/
775 
776     if (isImage)
777     {
778         selectedObject->ImageTitle().removeAt(itemIndex);
779         selectedObject->ImageList().removeAt(itemIndex);
780     }
781     else
782     {
783         selectedObject->InfoTitle().removeAt(itemIndex);
784         selectedObject->InfoList().removeAt(itemIndex);
785     }
786 
787     // Remove link from file
788     updateLocalDatabase(isImage ? 1 : 0, LineEntry);
789 
790     setProperty("infoTitleList", selectedObject->InfoTitle());
791     setProperty("imageTitleList", selectedObject->ImageTitle());
792 }
793 
editLink(int itemIndex,bool isImage,const QString & desc,const QString & url)794 void DetailDialogLite::editLink(int itemIndex, bool isImage, const QString &desc, const QString &url)
795 {
796     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
797 
798     if (url.isEmpty() || desc.isEmpty())
799         return; //Do nothing if empty url or desc were provided
800 
801     QString search_line, replace_line, currentItemTitle, currentItemURL;
802 
803     //Check if it is a valid index
804     if (itemIndex < 0)
805     {
806         return;
807     }
808     else if (isImage && itemIndex >= selectedObject->ImageTitle().length())
809     {
810         return;
811     }
812     else if (!isImage && itemIndex >= selectedObject->InfoTitle().length())
813     {
814         return;
815     }
816 
817     if (!isImage) //Information
818     {
819         currentItemTitle = selectedObject->InfoTitle()[itemIndex];
820         currentItemURL   = selectedObject->InfoList()[itemIndex];
821         search_line      = selectedObject->name();
822         search_line += ':';
823         search_line += currentItemTitle;
824         search_line += ':';
825         search_line += currentItemURL;
826     }
827     else //Image
828     {
829         currentItemTitle = selectedObject->ImageTitle()[itemIndex];
830         currentItemURL   = selectedObject->ImageList()[itemIndex];
831         search_line      = selectedObject->name();
832         search_line += ':';
833         search_line += currentItemTitle;
834         search_line += ':';
835         search_line += currentItemURL;
836     }
837 
838     bool go(true);
839 
840     // If nothing changed, skip th action
841     if (url == currentItemURL && desc == currentItemTitle)
842         go = false;
843 
844     if (go)
845     {
846         replace_line = selectedObject->name() + ':' + desc + ':' + url;
847 
848         // Info Link
849         if (!isImage)
850         {
851             selectedObject->InfoTitle().replace(itemIndex, desc);
852             selectedObject->InfoList().replace(itemIndex, url);
853 
854             // Image Links
855         }
856         else
857         {
858             selectedObject->ImageTitle().replace(itemIndex, desc);
859             selectedObject->ImageList().replace(itemIndex, url);
860         }
861 
862         // Update local files
863         updateLocalDatabase(isImage ? 1 : 0, search_line, replace_line);
864 
865         setProperty("infoTitleList", selectedObject->InfoTitle());
866         setProperty("imageTitleList", selectedObject->ImageTitle());
867     }
868 }
869 
getInfoURL(int index)870 QString DetailDialogLite::getInfoURL(int index)
871 {
872     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
873     QStringList urls          = selectedObject->InfoList();
874     if (index >= 0 && index < urls.size())
875     {
876         return urls[index];
877     }
878     else
879     {
880         return "";
881     }
882 }
883 
getImageURL(int index)884 QString DetailDialogLite::getImageURL(int index)
885 {
886     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
887     QStringList urls          = selectedObject->ImageList();
888     if (index >= 0 && index < urls.size())
889     {
890         return urls[index];
891     }
892     else
893     {
894         return "";
895     }
896 }
897 
setupThumbnail()898 void DetailDialogLite::setupThumbnail()
899 {
900     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
901     //No image if object is a star
902     if (selectedObject->type() == SkyObject::STAR || selectedObject->type() == SkyObject::CATALOG_STAR)
903     {
904         /*Thumbnail->scaled( Data->Image->width(), Data->Image->height() );
905         Thumbnail->fill( Data->DataFrame->palette().color( QPalette::Window ) );
906         Data->Image->setPixmap( *Thumbnail );*/
907         setProperty("thumbnail", "");
908         return;
909     }
910 
911     //Try to load the object's image from disk
912     //If no image found, load "no image" image
913     QFile file;
914     QString fname = "thumb-" + selectedObject->name().toLower().remove(' ') + ".png";
915     if (KSUtils::openDataFile(file, fname))
916     {
917         file.close();
918         setProperty("thumbnail", file.fileName());
919     }
920     else
921     {
922         setProperty("thumbnail", "");
923     }
924 }
925 
926 /*void DetailDialogLite::viewResource(int itemIndex, bool isImage) {
927     QString url;
928     if(isImage) {
929         url = getImageURL(itemIndex);
930     } else {
931         url = getInfoURL(itemIndex);
932     }
933     QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
934 }*/
935 
saveLogData(const QString & userLog)936 void DetailDialogLite::saveLogData(const QString &userLog)
937 {
938     SkyObject *selectedObject = SkyMapLite::Instance()->getClickedObjectLite()->getObject();
939 
940     selectedObject->saveUserLog(userLog);
941 }
942