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