7#include "imagingplanner.h"
9#include "artificialhorizoncomponent.h"
10#include "auxiliary/thememanager.h"
11#include "catalogscomponent.h"
12#include "constellationboundarylines.h"
13#include "dialogs/detaildialog.h"
14#include "dialogs/finddialog.h"
17#include "ekos/scheduler/schedulerjob.h"
20#include "flagmanager.h"
21#include "flagcomponent.h"
23#include "nameresolver.h"
24#include "imagingplanneroptions.h"
25#include "kplotwidget.h"
26#include "kplotobject.h"
30#include "ksnotification.h"
34#include "kstarsdata.h"
36#include "skymapcomposite.h"
38#include <QDesktopServices>
43#include <QNetworkReply>
44#include <QRegularExpression>
45#include <QSortFilterProxyModel>
46#include <QStandardItemModel>
51#define DPRINTF if (false) fprintf
75#define TYPE_ROLE (Qt::UserRole + 1)
76#define HOURS_ROLE (Qt::UserRole + 2)
77#define SIZE_ROLE (Qt::UserRole + 3)
78#define ALTITUDE_ROLE (Qt::UserRole + 4)
79#define MOON_ROLE (Qt::UserRole + 5)
80#define FLAGS_ROLE (Qt::UserRole + 6)
81#define NOTES_ROLE (Qt::UserRole + 7)
83#define PICKED_BIT ImagingPlannerDBEntry::PickedBit
84#define IMAGED_BIT ImagingPlannerDBEntry::ImagedBit
85#define IGNORED_BIT ImagingPlannerDBEntry::IgnoredBit
115 case SkyObject::OPEN_CLUSTER:
116 return Options::imagingPlannerAcceptOpenCluster();
117 case SkyObject::GLOBULAR_CLUSTER:
118 return Options::imagingPlannerAcceptGlobularCluster();
119 case SkyObject::GASEOUS_NEBULA:
120 return Options::imagingPlannerAcceptNebula();
121 case SkyObject::PLANETARY_NEBULA:
122 return Options::imagingPlannerAcceptPlanetary();
123 case SkyObject::SUPERNOVA_REMNANT:
124 return Options::imagingPlannerAcceptSupernovaRemnant();
125 case SkyObject::GALAXY:
126 return Options::imagingPlannerAcceptGalaxy();
127 case SkyObject::GALAXY_CLUSTER:
128 return Options::imagingPlannerAcceptGalaxyCluster();
129 case SkyObject::DARK_NEBULA:
130 return Options::imagingPlannerAcceptDarkNebula();
132 return Options::imagingPlannerAcceptOther();
139 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
142 const bool flag = model->
data(idx, FLAGS_ROLE).
toInt() & bit;
149 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
150 int currentFlags = 0;
152 currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
154 model->
setData(idx, val, FLAGS_ROLE);
160 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
163 const int currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
165 model->
setData(idx, val, FLAGS_ROLE);
171 if (flags & IMAGED_BIT) str.
append(
i18n(
"Imaged"));
172 if (flags & PICKED_BIT)
178 if (flags & IGNORED_BIT)
188void setupShowCallback(
bool checked,
189 void (*showOption)(
bool),
void (*showNotOption)(
bool),
190 void (*dontCareOption)(
bool),
194 Q_UNUSED(showCheckbox);
198 showNotOption(
false);
199 dontCareOption(
false);
202 Options::self()->save();
207 showNotOption(
false);
208 dontCareOption(
true);
211 Options::self()->save();
215void setupShowNotCallback(
bool checked,
216 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
219 Q_UNUSED(showNotCheckbox);
224 dontCareOption(
false);
227 Options::self()->save();
232 showNotOption(
false);
233 dontCareOption(
true);
236 Options::self()->save();
240void setupDontCareCallback(
bool checked,
241 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
247 showNotOption(
false);
248 dontCareOption(
true);
251 Options::self()->save();
258 showNotOption(
false);
259 dontCareOption(
true);
263 Options::self()->save();
272 "\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
277 auto match = re.match(input);
278 if (!
match.hasMatch())
281 return(
match.captured(0));
287 match = re.match(inp);
288 if (!
match.hasMatch())
291 return (
match.captured(0));
317 int column,
int role)
319 const double l =
left.siblingAtColumn(column).data(role).toDouble();
320 const double r =
right.siblingAtColumn(column).data(role).toDouble();
330 const QString l =
left.siblingAtColumn(column).data(role).toString();
331 const QString r =
right.siblingAtColumn(column).data(role).toString();
335 if (lList.
size() == 0 || rList.
size() == 0)
346 if (lList.
size() >= 2 && rList.
size() >= 2)
348 int lInt = lList[1].toInt();
349 int rInt = rList[1].toInt();
352 if (lInt > 0 && rInt > 0)
353 return -(lInt - rInt);
361void SchedulerUtils_setupJob(Ekos::SchedulerJob &job,
const QString &name,
bool isLead,
const QString &group,
362 const QString &train,
const dms &ra,
const dms &dec,
double djd,
double rotation,
const QUrl &sequenceUrl,
364 const QDateTime &completionTime,
int completionRepeats,
double minimumAltitude,
double minimumMoonSeparation,
365 double maxMoonAltitude,
366 bool enforceTwilight,
bool enforceArtificialHorizon,
bool track,
bool focus,
bool align,
bool guide)
370 job.setIsLead(isLead);
371 job.setOpticalTrain(train);
372 job.setPositionAngle(rotation);
378 job.setLeadJob(
nullptr);
380 job.setTargetCoords(ra, dec, djd);
381 job.setFITSFile(fitsUrl);
384 job.setStartupCondition(startup);
385 if (startup == Ekos::START_AT)
387 job.setStartupTime(startupTime);
390 job.setFileStartupCondition(job.getStartupCondition());
391 job.setStartAtTime(job.getStartupTime());
394 job.setMinAltitude(minimumAltitude);
395 job.setMinMoonSeparation(minimumMoonSeparation);
396 job.setMaxMoonAltitude(maxMoonAltitude);
400 job.setEnforceTwilight(enforceTwilight);
401 job.setEnforceArtificialHorizon(enforceArtificialHorizon);
404 job.setStepPipeline(Ekos::SchedulerJob::USE_NONE);
406 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_TRACK));
408 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_FOCUS));
410 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_ALIGN));
412 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_GUIDE));
415 job.setFileStartupCondition(job.getStartupCondition());
416 job.setStartAtTime(job.getStartupTime());
421 job.setSequenceFile(sequenceUrl);
422 job.setCompletionCondition(completion);
423 if (completion == Ekos::FINISH_AT)
424 job.setFinishAtTime(completionTime);
425 else if (completion == Ekos::FINISH_REPEAT)
427 job.setRepeatsRequired(completionRepeats);
428 job.setRepeatsRemaining(completionRepeats);
436void setupJob(Ekos::SchedulerJob &job,
const QString name,
double minAltitude,
double minMoonSeparation,
437 double maxMoonAltitude,
dms ra,
dms dec,
438 bool useArtificialHorizon)
441 double rotation = 0.0;
447 SchedulerUtils_setupJob(job, name,
true,
"",
449 rotation, sequenceURL,
QUrl(),
452 minAltitude, minMoonSeparation, maxMoonAltitude,
453 true, useArtificialHorizon,
454 true,
true,
true,
true);
458void getRunTimes(
const QDate &date,
const GeoLocation &geo,
double minAltitude,
double minMoonSeparation,
459 double maxMoonAltitude,
const dms &ra,
const dms &dec,
bool useArtificialHorizon,
QVector<QDateTime> *jobStartTimes,
462 jobStartTimes->
clear();
463 jobEndTimes->
clear();
464 constexpr int SCHEDULE_RESOLUTION_MINUTES = 10;
465 Ekos::SchedulerJob job;
466 setupJob(job,
"temp", minAltitude, minMoonSeparation, maxMoonAltitude, ra, dec, useArtificialHorizon);
473 startTime.setTimeZone(tz);
474 stopTime.setTimeZone(tz);
478 while (--maxIters >= 0)
480 QDateTime s = job.getNextPossibleStartTime(startTime, SCHEDULE_RESOLUTION_MINUTES,
false, stopTime);
485 QDateTime e = job.getNextEndTime(s, SCHEDULE_RESOLUTION_MINUTES, &constraintReason, stopTime);
493 if (e.
secsTo(stopTime) < 600)
503 double minMoonSeparation,
double maxMoonAltitude,
bool useArtificialHorizon)
506 getRunTimes(date, geo, minAltitude, minMoonSeparation, maxMoonAltitude,
object.ra0(),
object.dec0(), useArtificialHorizon,
509 if (jobStartTimes.
size() == 0 || jobEndTimes.
size() == 0)
513 double totalHours = 0.0;
514 for (
int i = 0; i < jobStartTimes.
size(); ++i)
515 totalHours += jobStartTimes[i].secsTo(jobEndTimes[i]) * 1.0 / 3600.0;
524int packString(
const QString &input, quint8 *p,
bool reallyPack)
527 quint32 len = str_data.
length();
528 const char *str = str_data.
data();
529 constexpr bool compatibilityMode =
false;
530 const quint8 *origP = p;
533 if (reallyPack) *p = 0xa0 | len;
536 else if (len <= std::numeric_limits<quint8>::max() &&
537 compatibilityMode ==
false)
539 if (reallyPack) *p = 0xd9;
541 if (reallyPack) *p = len;
544 else if (len <= std::numeric_limits<quint16>::max())
546 if (reallyPack) *p = 0xda;
557 if (reallyPack) memcpy(p, str, len);
558 return (p - origP) + len;
565 int size = packString(input,
nullptr,
false);
569 packString(input,
reinterpret_cast<quint8*
>(arr.
data()),
true);
587 result.
replace(remainingSpacesRegex, QStringLiteral(
""));
593bool downsampleImageFiles(
const QString &baseDir,
int maxHeight)
604 const QString subDir =
"REDUCED";
605 QDir directory(baseDir);
606 if (!directory.exists())
608 fprintf(stderr,
"downsampleImageFiles: Base directory doesn't exist\n");
616 fprintf(stderr,
"downsampleImageFiles: Failed making the output directory\n");
623 foreach (
QString filename, files)
628 if (img.height() > maxHeight)
637 if (!scaledImg.
save(jpgFilename,
"JPG"))
638 fprintf(stderr,
"downsampleImageFiles: Failed saving \"%s\"\n", writeFilename.
toLatin1().
data());
642 fprintf(stderr,
"downsampleImageFiles: saved \"%s\"\n", writeFilename.
toLatin1().
data());
645 fprintf(stderr,
"downsampleImageFiles: Wrote %d files\n", numSaved);
656 const int len = bInput.
size();
658 for (
int i = 0; i < len; ++i)
668 bInput.
replace(pos, 1, substitute);
677 auto massagedName =
name;
679 massagedName = massagedName.
replace(0, 4,
"sh2-");
680 massagedName = massagedName.
replace(
' ',
"");
686 if (files.size() > 0)
687 return files[0].absoluteFilePath();
690 for (
int i = 0; i < subDirs.size(); i++)
692 QDir subDir(subDirs[i].absoluteFilePath());
694 if (files.size() > 0)
695 return files[0].absoluteFilePath();
702 if (astrobinAbbrev ==
"ACC")
704 else if (astrobinAbbrev ==
"ASACC")
706 else if (astrobinAbbrev ==
"ANCCC")
708 else if (astrobinAbbrev ==
"ANCSACC")
709 return "CC-BY-SA-NC";
713QString creativeCommonsTooltipString(
const QString &astrobinAbbrev)
715 if (astrobinAbbrev ==
"ACC")
716 return "Atribution Creative Commons";
717 else if (astrobinAbbrev ==
"ASACC")
718 return "Atribution Share-Alike Creative Commons";
719 else if (astrobinAbbrev ==
"ANCCC")
720 return "Atribution Non-Commercial Creative Commons";
721 else if (astrobinAbbrev ==
"ANCSACC")
722 return "Atribution Non-Commercial Share-Alike Creative Commons";
741 double hoursAfterDusk = 0,
double hoursBeforeDawn = 0)
747 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
749 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
755 auto end = dawn.
addSecs(-hoursBeforeDawn * 3600);
764 while (t.secsTo(end) > 0)
766 double alt = getAltitude(geo, coords, t);
772 t = t.addSecs(60 * 20);
781 m_SortColumn = HOURS_COLUMN;
785bool CatalogFilter::filterAcceptsRow(
int row,
const QModelIndex &parent)
const
789 if (!acceptType(type))
return false;
793 if (!hasEnoughHours)
return false;
797 const bool isImaged =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IMAGED_BIT;
798 const bool passesImagedConstraints = !m_ImagedConstraintsEnabled || (isImaged == m_ImagedRequired);
799 if (!passesImagedConstraints)
return false;
801 const bool isIgnored =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IGNORED_BIT;
802 const bool passesIgnoredConstraints = !m_IgnoredConstraintsEnabled || (isIgnored == m_IgnoredRequired);
803 if (!passesIgnoredConstraints)
return false;
805 const bool isPicked =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & PICKED_BIT;
806 const bool passesPickedConstraints = !m_PickedConstraintsEnabled || (isPicked == m_PickedRequired);
807 if (!passesPickedConstraints)
return false;
810 if (m_Keyword.isEmpty() || !m_KeywordConstraintsEnabled)
return true;
812 const QString notes =
sourceModel()->data(notesIndex, NOTES_ROLE).toString();
814 const bool REMatches = m_KeywordRE.match(notes).hasMatch();
815 return (m_KeywordRequired == REMatches);
818void CatalogFilter::setMinHours(
double hours)
823void CatalogFilter::setImagedConstraints(
bool enabled,
bool required)
825 m_ImagedConstraintsEnabled = enabled;
826 m_ImagedRequired = required;
829void CatalogFilter::setPickedConstraints(
bool enabled,
bool required)
831 m_PickedConstraintsEnabled = enabled;
832 m_PickedRequired = required;
835void CatalogFilter::setIgnoredConstraints(
bool enabled,
bool required)
837 m_IgnoredConstraintsEnabled = enabled;
838 m_IgnoredRequired = required;
841void CatalogFilter::setKeywordConstraints(
bool enabled,
bool required,
const QString &keyword)
843 m_KeywordConstraintsEnabled = enabled;
844 m_KeywordRequired = required;
846 m_KeywordRE = QRegularExpression(keyword);
849void CatalogFilter::setSortColumn(
int column)
851 if (column == m_SortColumn)
852 m_ReverseSort = !m_ReverseSort;
853 m_SortColumn = column;
862 double compareVal = 0;
867 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
868 if (m_ReverseSort) compareVal = -compareVal;
872 compareVal = stringCompareFcn(left, right, TYPE_COLUMN,
Qt::DisplayRole);
873 if (m_ReverseSort) compareVal = -compareVal;
874 if (compareVal != 0)
break;
875 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
876 if (compareVal != 0)
break;
877 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
881 compareVal = floatCompareFcn(left, right, SIZE_COLUMN, SIZE_ROLE);
882 if (m_ReverseSort) compareVal = -compareVal;
883 if (compareVal != 0)
break;
884 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
885 if (compareVal != 0)
break;
886 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
888 case ALTITUDE_COLUMN:
890 compareVal = floatCompareFcn(left, right, ALTITUDE_COLUMN, ALTITUDE_ROLE);
891 if (m_ReverseSort) compareVal = -compareVal;
892 if (compareVal != 0)
break;
893 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
894 if (compareVal != 0)
break;
895 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
899 compareVal = floatCompareFcn(left, right, MOON_COLUMN, MOON_ROLE);
900 if (m_ReverseSort) compareVal = -compareVal;
901 if (compareVal != 0)
break;
902 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
903 if (compareVal != 0)
break;
904 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
906 case CONSTELLATION_COLUMN:
908 compareVal = stringCompareFcn(left, right, CONSTELLATION_COLUMN,
Qt::DisplayRole);
909 if (m_ReverseSort) compareVal = -compareVal;
910 if (compareVal != 0)
break;
911 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
912 if (compareVal != 0)
break;
913 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
917 compareVal = stringCompareFcn(left, right, COORD_COLUMN,
Qt::DisplayRole);
918 if (m_ReverseSort) compareVal = -compareVal;
919 if (compareVal != 0)
break;
920 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
921 if (compareVal != 0)
break;
922 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
927 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
928 if (m_ReverseSort) compareVal = -compareVal;
929 if (compareVal != 0)
break;
930 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
933 return compareVal < 0;
943void ImagingPlannerUI::setupIcons()
967 return KStarsData::Instance()->
geo();
970QDate ImagingPlanner::getDate()
const
972 return ui->DateEdit->date();
975ImagingPlanner::ImagingPlanner() :
QDialog(nullptr), m_networkManager(this), m_manager{ CatalogsDB::dso_db_path() }
977 ui =
new ImagingPlannerUI(
this);
983 setLayout(mainLayout);
985 setWindowTitle(
i18nc(
"@title:window",
"Imaging Planner"));
988 if (Options::imagingPlannerIndependentWindow())
1004void ImagingPlanner::setupHideButtons(
bool(*option)(),
void(*setOption)(
bool),
1014 Options::self()->save();
1023 Options::self()->save();
1031void ImagingPlanner::focusOnTable()
1033 ui->CatalogView->setFocus();
1036void ImagingPlanner::adjustWindowSize()
1038 const int keepWidth =
width();
1040 const int newHeight =
height();
1041 resize(keepWidth, newHeight);
1045void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox,
bool(*option)(),
void(*setOption)(
bool))
1051 Options::self()->save();
1052 m_CatalogSortModel->invalidate();
1054 ui->CatalogView->resizeColumnsToContents();
1060void ImagingPlanner::setupFilter2Buttons(
1062 bool(*yesOption)(),
bool(*noOption)(),
bool(*dontCareOption)(),
1063 void(*setYesOption)(
bool),
void(*setNoOption)(
bool),
void(*setDontCareOption)(
bool))
1069 setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1070 updateSortConstraints();
1071 m_CatalogSortModel->invalidate();
1072 ui->CatalogView->resizeColumnsToContents();
1078 setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1079 updateSortConstraints();
1080 m_CatalogSortModel->invalidate();
1081 ui->CatalogView->resizeColumnsToContents();
1085 connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
1087 setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1088 updateSortConstraints();
1089 m_CatalogSortModel->invalidate();
1090 ui->CatalogView->resizeColumnsToContents();
1101void ImagingPlanner::updateSortConstraints()
1103 m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
1104 ui->pickedCB->isChecked());
1105 m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
1106 ui->imagedCB->isChecked());
1107 m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
1108 ui->ignoredCB->isChecked());
1109 m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
1110 ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
1114void ImagingPlanner::initialize()
1116 if (KStarsData::Instance() ==
nullptr)
1123 connect(
this, &ImagingPlanner::popupSorry,
this, &ImagingPlanner::sorry);
1126 m_CatalogModel =
new QStandardItemModel(0, LAST_COLUMN);
1129 m_CatalogModel->setHorizontalHeaderLabels(
1132 m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
1133 i18n(
"Object Name--click header to sort ascending/descending."));
1134 m_CatalogModel->horizontalHeaderItem(
1135 HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
1136 m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
1137 i18n(
"Object Type--click header to sort ascending/descending."));
1138 m_CatalogModel->horizontalHeaderItem(
1139 SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
1140 m_CatalogModel->horizontalHeaderItem(
1141 ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
1142 m_CatalogModel->horizontalHeaderItem(
1143 MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
1144 m_CatalogModel->horizontalHeaderItem(
1145 CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
1146 m_CatalogModel->horizontalHeaderItem(
1147 COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
1149 m_CatalogSortModel =
new CatalogFilter(
this);
1151 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
1152 m_CatalogSortModel->setDynamicSortFilter(
true);
1154 ui->CatalogView->setModel(m_CatalogSortModel.data());
1155 ui->CatalogView->setSortingEnabled(
false);
1156 ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
1157 ui->CatalogView->resizeColumnsToContents();
1158 ui->CatalogView->verticalHeader()->setVisible(
false);
1159 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
1162 this, &ImagingPlanner::selectionChanged);
1167 auto utc = KStarsData::Instance()->
clock()->
utc();
1168 auto localTime = getGeo()->UTtoLT(utc);
1169 ui->DateEdit->
setDate(localTime.date());
1175 setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
1176 ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
1177 ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
1184 QString selection = currentObjectName();
1188 scrollToName(selection);
1212 checkTargets2(true);
1216 QString dir = QFileDialog::getExistingDirectory(this, tr(
"Downsample Directory"));
1219 if (downsampleImageFiles(dir, 300))
1220 fprintf(stderr,
"downsampling succeeded\n");
1222 fprintf(stderr,
"downsampling failed\n");
1227 Options::setImagingPlannerHideAstrobinDetails(
true);
1228 setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
1229 ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
1230 ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
1231 ui->AstrobinAward->setChecked(Options::astrobinAward());
1234 Options::setAstrobinAward(checked);
1235 Options::self()->save();
1238 ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
1241 Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
1242 Options::self()->save();
1245 ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
1248 Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
1249 Options::self()->save();
1260 setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
1261 ui->hideImageButton, ui->showImageButton,
1262 ui->ImageFrame, ui->HiddenImageFrame);
1265 Options::setImagingPlannerHideFilters(
true);
1266 setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
1267 ui->hideFilterTypesButton, ui->showFilterTypesButton,
1268 ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
1269 setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
1270 &Options::setImagingPlannerAcceptOpenCluster);
1271 setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
1272 setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
1273 &Options::setImagingPlannerAcceptGlobularCluster);
1274 setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
1275 setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
1276 &Options::setImagingPlannerAcceptSupernovaRemnant);
1277 setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
1278 setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
1279 &Options::setImagingPlannerAcceptGalaxyCluster);
1280 setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
1281 setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
1283 setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
1284 &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
1285 &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
1287 setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
1288 &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
1289 &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
1291 setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
1292 &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
1293 &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
1294 &Options::setImagingPlannerDontCareIgnored);
1296 ui->keywordEdit->setText(Options::imagingPlannerKeyword());
1297 ui->keywordEdit->setAcceptRichText(
false);
1298 m_Keyword = Options::imagingPlannerKeyword();
1299 setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
1300 &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
1301 &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
1302 &Options::setImagingPlannerDontCareKeyword);
1307 ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
1308 m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
1309 ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
1310 m_MinMoon = Options::imagingPlannerMinMoonSeparation();
1311 ui->maxMoonAltitude->setValue(Options::imagingPlannerMaxMoonAltitude());
1312 m_MaxMoonAltitude = Options::imagingPlannerMaxMoonAltitude();
1313 ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
1314 m_MinAltitude = Options::imagingPlannerMinAltitude();
1315 ui->minHours->setValue(Options::imagingPlannerMinHours());
1316 m_MinHours = Options::imagingPlannerMinHours();
1317 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1320 if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
1322 m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
1323 Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
1324 Options::self()->save();
1330 if (m_MinMoon == ui->minMoon->value())
1332 m_MinMoon = ui->minMoon->value();
1333 Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
1334 Options::self()->save();
1340 if (m_MaxMoonAltitude == ui->maxMoonAltitude->value())
1342 m_MaxMoonAltitude = ui->maxMoonAltitude->value();
1343 Options::setImagingPlannerMaxMoonAltitude(ui->maxMoonAltitude->value());
1344 Options::self()->save();
1350 if (m_MinAltitude == ui->minAltitude->value())
1352 m_MinAltitude = ui->minAltitude->value();
1353 Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
1354 Options::self()->save();
1360 if (m_MinHours == ui->minHours->value())
1362 m_MinHours = ui->minHours->value();
1363 Options::setImagingPlannerMinHours(ui->minHours->value());
1364 Options::self()->save();
1365 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1366 m_CatalogSortModel->invalidate();
1367 ui->CatalogView->resizeColumnsToContents();
1371 updateSortConstraints();
1373 m_CatalogSortModel->setMinHours(ui->minHours->value());
1375 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
1384 ui->userNotesLabel->setVisible(true);
1385 ui->userNotesEdit->setText(ui->userNotes->text());
1386 ui->userNotesEdit->setVisible(true);
1387 ui->userNotesEditButton->setVisible(false);
1388 ui->userNotesDoneButton->setVisible(true);
1389 ui->userNotes->setVisible(false);
1390 ui->userNotesLabel->setVisible(true);
1391 ui->userNotesOpenLink->setVisible(false);
1392 ui->userNotesOpenLink2->setVisible(false);
1393 ui->userNotesOpenLink3->setVisible(false);
1399 QString urlString = findUrl(ui->userNotes->text());
1400 if (urlString.isEmpty())
1402 QDesktopServices::openUrl(QUrl(urlString));
1407 QString urlString = findUrl(ui->userNotes->text(), 2);
1408 if (urlString.isEmpty())
1410 QDesktopServices::openUrl(QUrl(urlString));
1415 QString urlString = findUrl(ui->userNotes->text(), 3);
1416 if (urlString.isEmpty())
1418 QDesktopServices::openUrl(QUrl(urlString));
1427 m_CatalogSortModel->setSortColumn(column);
1428 m_CatalogSortModel->invalidate();
1429 ui->CatalogView->resizeColumnsToContents();
1437 qRegisterMetaType<QList<QStandardItem *>>(
"QList<QStandardItem *>");
1438 connect(
this, &ImagingPlanner::addRow,
this, &ImagingPlanner::addRowSlot);
1448 installEventFilters();
1451void ImagingPlanner::installEventFilters()
1455 ui->SearchText->installEventFilter(
this);
1456 ui->userNotesEdit->installEventFilter(
this);
1457 ui->keywordEdit->installEventFilter(
this);
1458 ui->ImagePreviewCreditLink->installEventFilter(
this);
1459 ui->ImagePreviewCredit->installEventFilter(
this);
1460 ui->ImagePreview->installEventFilter(
this);
1461 ui->CatalogView->viewport()->installEventFilter(
this);
1462 ui->CatalogView->installEventFilter(
this);
1463 ui->helpButton->installEventFilter(
this);
1466void ImagingPlanner::removeEventFilters()
1468 ui->SearchText->removeEventFilter(
this);
1469 ui->userNotesEdit->removeEventFilter(
this);
1470 ui->keywordEdit->removeEventFilter(
this);
1471 ui->ImagePreviewCreditLink->removeEventFilter(
this);
1472 ui->ImagePreviewCredit->removeEventFilter(
this);
1473 ui->ImagePreview->removeEventFilter(
this);
1474 ui->CatalogView->viewport()->removeEventFilter(
this);
1475 ui->helpButton->removeEventFilter(
this);
1478void ImagingPlanner::openOptionsMenu()
1480 QSharedPointer<ImagingPlannerOptions> options(
new ImagingPlannerOptions(
this));
1486void ImagingPlanner::getHelp()
1489 const QUrl url(
"https://docs.kde.org/trunk5/en/kstars/kstars/kstars.pdf#tool-imaging-planner");
1494KSMoon *ImagingPlanner::getMoon()
1496 if (KStarsData::Instance() ==
nullptr)
1502 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1503 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1505 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1506 KSNumbers numbers(midnight.
djd());
1507 moon->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1513void ImagingPlanner::updateMoon()
1515 KSMoon *moon = getMoon();
1520 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1521 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1522 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1523 KSNumbers numbers(midnight.
djd());
1525 sun->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1529 ui->moonPercentLabel->setText(QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0,
'f', 0));
1532bool ImagingPlanner::scrollToName(
const QString &name)
1536 QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0),
Qt::EditRole,
1538 if(matchList.count() >= 1)
1541 for (
int i = 0; i < matchList.count(); i++)
1543 QString nn = ui->CatalogView->model()->data(matchList[i],
Qt::DisplayRole).toString();
1550 ui->CatalogView->scrollTo(matchList[bestIndex]);
1551 ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
1557void ImagingPlanner::searchSlot()
1559 if (m_loadingCatalog)
1561 QString origName = ui->SearchText->toPlainText().trimmed();
1562 QString
name = tweakNames(origName);
1563 ui->SearchText->setPlainText(name);
1567 if (!scrollToName(name))
1568 KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
1571 ui->SearchText->clear();
1572 ui->SearchText->setPlainText(
"");
1575void ImagingPlanner::initUserNotes()
1577 ui->userNotesLabel->setVisible(
true);
1578 ui->userNotesEdit->setVisible(
false);
1579 ui->userNotesEditButton->setVisible(
true);
1580 ui->userNotesDoneButton->setVisible(
false);
1581 ui->userNotes->setVisible(
true);
1582 ui->userNotesLabel->setVisible(
true);
1583 ui->userNotesOpenLink->setVisible(
false);
1584 ui->userNotesOpenLink2->setVisible(
false);
1585 ui->userNotesOpenLink3->setVisible(
false);
1588void ImagingPlanner::disableUserNotes()
1590 ui->userNotesEdit->setVisible(
false);
1591 ui->userNotesEditButton->setVisible(
false);
1592 ui->userNotesDoneButton->setVisible(
false);
1593 ui->userNotes->setVisible(
false);
1594 ui->userNotesLabel->setVisible(
false);
1595 ui->userNotesOpenLink->setVisible(
false);
1596 ui->userNotesOpenLink2->setVisible(
false);
1597 ui->userNotesOpenLink3->setVisible(
false);
1600void ImagingPlanner::userNotesEditFinished()
1602 const QString ¬es = ui->userNotesEdit->toPlainText().
trimmed();
1603 ui->userNotes->setText(notes);
1604 ui->userNotesLabel->setVisible(notes.
isEmpty());
1605 ui->userNotesEdit->setVisible(
false);
1606 ui->userNotesEditButton->setVisible(
true);
1607 ui->userNotesDoneButton->setVisible(
false);
1608 ui->userNotes->setVisible(
true);
1609 ui->userNotesLabel->setVisible(
true);
1610 setCurrentObjectNotes(notes);
1611 setupNotesLinks(notes);
1613 auto o = currentCatalogObject();
1615 saveToDB(currentObjectName(), currentObjectFlags(), notes);
1618void ImagingPlanner::updateNotes(
const QString ¬es)
1620 ui->userNotes->setMaximumWidth(ui->RightPanel->width() - 125);
1622 ui->userNotes->setText(notes);
1623 ui->userNotesLabel->setVisible(notes.
isEmpty());
1624 setupNotesLinks(notes);
1627void ImagingPlanner::setupNotesLinks(
const QString ¬es)
1629 QString
link = findUrl(notes);
1630 ui->userNotesOpenLink->setVisible(!
link.isEmpty());
1631 if (!
link.isEmpty())
1632 ui->userNotesOpenLink->setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
1634 link = findUrl(notes, 2);
1635 ui->userNotesOpenLink2->setVisible(!
link.isEmpty());
1636 if (!
link.isEmpty())
1637 ui->userNotesOpenLink2->setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
1639 link = findUrl(notes, 3);
1640 ui->userNotesOpenLink3->setVisible(!
link.isEmpty());
1641 if (!
link.isEmpty())
1642 ui->userNotesOpenLink3->setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
1645bool ImagingPlanner::internetNameSearch(
const QString &name,
bool abellPlanetary,
int abellNumber,
1649 QElapsedTimer timer;
1651 QString filteredName =
name;
1655 QString resolverName = filteredName;
1659 resolverName = QString(
"PN A66 %1").
arg(abellNumber);
1666 CatalogObject
object = cedata.second;
1669 if (
object.
name() ==
object.name2())
1670 object.setName2(filteredName);
1671 object.setName(filteredName);
1674 m_manager.add_object(CatalogsDB::user_catalog_id,
object);
1675 const auto &added_object =
1676 m_manager.get_object(
object.getId(), CatalogsDB::user_catalog_id);
1678 if (added_object.first)
1680 *catObject = KStarsData::Instance()
1682 ->catalogsComponent()
1686 DPRINTF(stderr,
"***** Found %s using name resolver (%.1fs)\n",
name.
toLatin1().
data(),
1691bool isAbellPlanetary(
const QString &name,
int *number)
1697 auto match = abellRE.match(name);
1698 if (
match.hasMatch())
1716 std::list<CatalogObject> objs =
1717 m_manager.find_objects_by_name(filteredName, 1,
true);
1721 int abellNumber = 0;
1722 bool abellPlanetary = isAbellPlanetary(name, &abellNumber);
1723 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1726 if (objs.size() == 0 && filteredName.
size() > 0)
1729 const QString capitalized = capitalize(filteredName);
1730 objs = m_manager.find_objects_by_name(capitalized, 1,
true);
1731 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1734 if (objs.size() == 0)
1737 const QString lowerCase = filteredName.
toLower();
1738 objs = m_manager.find_objects_by_name(lowerCase, 1,
true);
1739 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1748 QString name2 = filteredName;
1750 objs = m_manager.find_objects_by_name(name2, 1,
true);
1754 QString name2 = filteredName;
1756 objs = m_manager.find_objects_by_name(name2, 1,
true);
1759 if (objs.size() == 0 && !abellPlanetary)
1760 objs = m_manager.find_objects_by_name(filteredName.
toLower(), 20,
false);
1761 if (objs.size() == 0)
1762 return internetNameSearch(filteredName, abellPlanetary, abellNumber, catObject);
1764 if (objs.size() == 0)
1768 *catObject = objs.front();
1769 if (objs.size() >= 1)
1771 bool foundIt =
false;
1772 QString addSpace = filteredName;
1774 QString addComma = filteredName;
1776 QString sh2Fix = filteredName;
1778 for (
const auto &obj : objs)
1796 if (objs.size() == 1)
1797 DPRINTF(stderr,
" ========> \"%s\" had 1 match \"%s\", but not trusting it!!!!\n",
name.
toLatin1().
data(),
1798 objs.front().name().toLatin1().data());
1800 if (internetNameSearch(filteredName, abellPlanetary, abellNumber, catObject))
1803 DPRINTF(stderr,
"Didn't find %s (%s) -- Not using name \"%s\" name2 \"%s\" longname \"%s\"\n",
1818 auto o = m_CatalogHash.find(lName);
1819 if (o == m_CatalogHash.end())
1824void ImagingPlanner::clearObjects()
1830 m_CatalogHash.clear();
1838 if (getObject(lName) !=
nullptr)
1840 DPRINTF(stderr,
"Didn't add \"%s\" because it's already there\n",
name.
toLatin1().
data());
1845 if (!getKStarsCatalogObject(lName, &o))
1847 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
1850 m_CatalogHash[lName] = o;
1851 return &(m_CatalogHash[lName]);
1856bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal,
const QString &name,
int flags)
1858 CatalogObject *
object = addObject(name);
1859 if (
object ==
nullptr)
1862 auto getItemWithUserRole = [](
const QString & itemText) -> QStandardItem *
1864 QStandardItem *ret =
new QStandardItem(itemText);
1871 QList<QStandardItem *> itemList;
1872 for (
int i = 0; i < LAST_COLUMN; ++i)
1874 if (i == NAME_COLUMN)
1876 itemList.
append(getItemWithUserRole(name));
1878 else if (i == HOURS_COLUMN)
1880 double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
1881 ui->maxMoonAltitude->value(), ui->useArtificialHorizon->isChecked());
1882 auto hoursItem = getItemWithUserRole(QString(
"%1").arg(runHours, 0,
'f', 1));
1883 hoursItem->setData(runHours, HOURS_ROLE);
1884 itemList.
append(hoursItem);
1886 else if (i == TYPE_COLUMN)
1888 auto typeItem = getItemWithUserRole(QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
1889 typeItem->setData(object->
type(), TYPE_ROLE);
1890 itemList.
append(typeItem);
1892 else if (i == SIZE_COLUMN)
1894 double size = std::max(object->
a(), object->
b());
1895 auto sizeItem = getItemWithUserRole(QString(
"%1'").arg(
size, 0,
'f', 1));
1896 sizeItem->setData(
size, SIZE_ROLE);
1897 itemList.
append(sizeItem);
1899 else if (i == ALTITUDE_COLUMN)
1901 const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
1902 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
1903 auto altItem = getItemWithUserRole(QString(
"%1º").arg(altitude, 0,
'f', 0));
1904 altItem->setData(altitude, ALTITUDE_ROLE);
1905 itemList.
append(altItem);
1907 else if (i == MOON_COLUMN)
1909 KSMoon *moon = getMoon();
1915 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1916 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1918 KSNumbers numbers(midnight.
djd());
1922 auto moonItem = getItemWithUserRole(QString(
"%1º").arg(separation, 0,
'f', 0));
1923 moonItem->setData(separation, MOON_ROLE);
1924 itemList.
append(moonItem);
1928 auto moonItem = getItemWithUserRole(QString(
""));
1929 moonItem->setData(-1, MOON_ROLE);
1932 else if (i == CONSTELLATION_COLUMN)
1934 QString cname = KStarsData::Instance()
1936 ->constellationBoundary()
1937 ->constellationName(
object);
1939 auto constellationItem = getItemWithUserRole(cname);
1940 itemList.
append(constellationItem);
1942 else if (i == COORD_COLUMN)
1944 itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
1946 else if (i == FLAGS_COLUMN)
1948 QStandardItem *flag = getItemWithUserRole(
"flag");
1949 flag->
setData(flags, FLAGS_ROLE);
1952 else if (i == NOTES_COLUMN)
1954 QStandardItem *notes = getItemWithUserRole(
"notes");
1955 notes->
setData(QString(), NOTES_ROLE);
1960 DPRINTF(stderr,
"Bug in addCatalogItem() !\n");
1965 emit addRow(itemList);
1971 m_CatalogModel->appendRow(itemList);
1975void ImagingPlanner::recompute()
1977 setStatus(
i18n(
"Updating tables..."));
1980 m_CatalogSortModel->setSourceModel(
nullptr);
1982 QElapsedTimer timer;
1985 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1986 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1987 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
1988 KSAlmanac ksal(ut, getGeo());
1990 for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
1992 const QString &
name = m_CatalogModel->item(i, 0)->text();
1993 const CatalogObject *catalogEntry = getObject(name);
1994 if (catalogEntry ==
nullptr)
1996 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n",
name.
toLatin1().
data());
1999 double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
2000 ui->minMoon->value(), ui->maxMoonAltitude->value(), ui->useArtificialHorizon->isChecked());
2001 QString hoursText = QString(
"%1").arg(runHours, 0,
'f', 1);
2002 QStandardItem *hItem =
new QStandardItem(hoursText);
2005 hItem->
setData(runHours, HOURS_ROLE);
2006 m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
2009 const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
2010 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
2011 QString altText = QString(
"%1º").arg(altitude, 0,
'f', 0);
2012 auto altItem =
new QStandardItem(altText);
2014 altItem->setData(altitude, ALTITUDE_ROLE);
2015 m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
2017 KSMoon *moon = getMoon();
2023 auto tz = QTimeZone(getGeo()->TZ() * 3600);
2024 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
2026 KSNumbers numbers(midnight.
djd());
2030 QString moonText = QString(
"%1º").arg(separation, 0,
'f', 0);
2031 auto moonItem =
new QStandardItem(moonText);
2033 moonItem->setData(separation, MOON_ROLE);
2034 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
2038 auto moonItem =
new QStandardItem(
"");
2040 moonItem->setData(-1, MOON_ROLE);
2041 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
2045 const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
2047 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
2048 const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
2050 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
2053 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
2055 DPRINTF(stderr,
"Recompute took %.1fs\n", timer.
elapsed() / 1000.0);
2066bool ALREADY_CHECKING =
false;
2067int ALREADY_CHECKING_INDEX = -1;
2069struct ObjectNeighbor
2071 CatalogObject object;
2074 ObjectNeighbor(CatalogObject o,
double d, QString nei) : object(o), distance(d), neighbor(nei) {}
2080void ImagingPlanner::checkTargets2(
bool backwards)
2082 if (ALREADY_CHECKING)
2085 ALREADY_CHECKING_INDEX--;
2087 ALREADY_CHECKING_INDEX++;
2089 if (sortedAddedObjects.size() == 0)
2091 fprintf(stderr,
"No TARGETS\n");
2094 if (ALREADY_CHECKING_INDEX >= sortedAddedObjects.size())
2095 ALREADY_CHECKING_INDEX = 0;
2096 else if (ALREADY_CHECKING_INDEX < 0)
2097 ALREADY_CHECKING_INDEX = sortedAddedObjects.size() - 1;
2098 KStarsDateTime time = KStarsData::Instance()->
clock()->
utc();
2099 dms lst = getGeo()->GSTtoLST(time.
gst());
2100 CatalogObject &o = sortedAddedObjects[ALREADY_CHECKING_INDEX].object;
2102 fprintf(stderr,
"%d: %s\n", ALREADY_CHECKING_INDEX, o.
name().
toLatin1().
data());
2105 bool keepGround = Options::showGround();
2106 bool keepAnimatedSlew = Options::useAnimatedSlewing();
2107 Options::setShowGround(
false);
2108 Options::setUseAnimatedSlewing(
false);
2112 Options::setShowGround(keepGround);
2113 Options::setUseAnimatedSlewing(keepAnimatedSlew);
2119void ImagingPlanner::checkTargets(
bool justCheckCurrentCatalog)
2121 if (ALREADY_CHECKING)
2123 checkTargets2(
false);
2126 ALREADY_CHECKING =
true;
2129 FlagComponent *flags = KStarsData::Instance()->
skyComposite()->flags();
2130 for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
2131 int rows = m_CatalogModel->rowCount();
2134 for (
int i = 0; i < rows; ++i)
2136 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
2137 auto object = getObject(name);
2141 flags->
add(SkyPoint(object->
ra(), object->
dec()),
"J2000.0",
"", name,
Qt::red);
2144 fprintf(stderr,
"Added %d flags\n", numFlags);
2148 QList<QString> targets;
2149 QList<QString> newObjects;
2150 if (!justCheckCurrentCatalog)
2156 QFile inputFile(fileName);
2159 QTextStream in(&inputFile);
2162 const QString line = in.readLine().trimmed();
2163 if (line.
size() > 0 && line[0] !=
'#' && newObjects.
indexOf(line) == -1)
2168 if (newObjects.
size() == 0)
2170 fprintf(stderr,
"No New Targets\n");
2175 QList<CatalogObject> addedObjects;
2176 sortedAddedObjects.clear();
2178 int count = 0, good = 0;
2179 for (
int i = 0; i < rows; ++i)
2181 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
2183 auto o = getObject(name);
2191 fprintf(stderr,
"********** %d/%d targets found. %d unique test objects\n", good, count, newObjects.
size());
2195 if (!justCheckCurrentCatalog)
2197 fprintf(stderr,
"Adding: ");
2198 for (
const auto &name : newObjects)
2200 if (getObject(name) !=
nullptr)
2205 CatalogObject object;
2206 if (!getKStarsCatalogObject(name, &
object))
2211 object.
setRA(
object.ra0());
2212 object.setDec(
object.dec0());
2215 fprintf(stderr,
"%s had primary name %s -- reverting.\n",
2217 object.setName(name);
2223 fprintf(stderr,
"\n--------------------------------------------------------\n");
2227 for (
int i = 0; i < addedObjects.
size(); ++i)
2229 auto &
object = addedObjects[i];
2230 double closest = 1e9;
2231 QString closestName;
2232 for (
int j = 0; j < targets.
size(); ++j)
2234 if (justCheckCurrentCatalog && i == j)
2236 auto name2 = targets[j];
2237 auto object2 = getObject(name2);
2238 if (object2 ==
nullptr)
2240 fprintf(stderr,
"********************************************************* O2 for targets[%d]: %s null!\n", j,
2244 object2->setRA(object2->ra0());
2245 object2->setDec(object2->dec0());
2246 const dms dist =
object.angularDistanceTo(object2);
2247 const double arcsecDist = dist.
Degrees() * 3600.0;
2248 if (closest > arcsecDist)
2250 closest = arcsecDist;
2251 closestName = name2;
2255 sortedAddedObjects.
push_back(ObjectNeighbor(addedObjects[i], closest, closestName));
2259 if (justCheckCurrentCatalog)
2261 fprintf(stderr,
"%7.1f %-10s closest %s\n", closest / 60.0,
object.
name().toLatin1().data(),
2266 double closestNew = 1e9;
2267 QString closestNewName;
2268 for (
int j = 0; j < addedObjects.
size() - 1; ++j)
2270 if (i == j)
continue;
2271 auto object2 = addedObjects[j];
2272 object2.setRA(object2.ra0());
2273 object2.setDec(object2.dec0());
2274 const dms dist =
object.angularDistanceTo(&object2);
2275 const double arcsecDist = dist.
Degrees() * 3600.0;
2276 if (closestNew > arcsecDist)
2278 closestNew = arcsecDist;
2279 closestNewName = object2.name();
2282 fprintf(stderr,
"%7.1f %-10s (closest %s) (closestNew %5.0f' %-10s)\n",
2283 closest / 60.0,
object.
name().toLatin1().data(), closestName.
toLatin1().
data(),
2285 flags->
add(SkyPoint(
object.ra(),
object.
dec()),
"J2000.0",
"", QString(
"%1").arg(
object.
name()),
Qt::yellow);
2288 std::sort(sortedAddedObjects.begin(), sortedAddedObjects.end(),
2289 [](
const ObjectNeighbor & a,
const ObjectNeighbor & b)
2291 return a.distance > b.distance;
2293 if (justCheckCurrentCatalog)
2295 fprintf(stderr,
"Sorted: ------------------------------------------\n");
2296 for (
const auto &o : sortedAddedObjects)
2297 fprintf(stderr,
"%7.1f %-10s closest %s\n",
2299 o.neighbor.toLatin1().data());
2301 fprintf(stderr,
"DONE. ------------------------------------------\n");
2305QString ImagingPlanner::defaultDirectory()
const
2319QFileInfoList findDefaultDirectories()
2322 QDir kDir(kstarsDir);
2325 nameFilters <<
"ImagingPlanner*";
2326 QFileInfoList dirs1 = kDir.entryInfoList(nameFilters);
2331 dirs1.append(dirs2);
2332 std::sort(dirs1.begin(), dirs1.end(), sortOldest);
2339QString ImagingPlanner::findDefaultCatalog()
const
2341 QFileInfoList subDirs = findDefaultDirectories();
2342 for(
const auto &dd : subDirs)
2344 QDir subDir(dd.absoluteFilePath());
2345 const QStringList csvFilter({
"*.csv"});
2347 if (files.size() > 0)
2352 for (
const auto &file : files)
2355 firstFile = file.absoluteFilePath();
2357 return file.absoluteFilePath();
2366void ImagingPlanner::loadInitialCatalog()
2368 QString catalog = Options::imagingPlannerCatalogPath();
2370 catalog = findDefaultCatalog();
2373 KSNotification::sorry(
2374 i18n(
"You need to load a catalog to start using this tool.\n"
2375 "Use the Load Catalog button if you have one.\n"
2376 "See Data -> Download New Data if not..."));
2377 setStatus(
i18n(
"No Catalog!"));
2380 loadCatalog(catalog);
2383void ImagingPlanner::setStatus(
const QString &message)
2385 ui->statusLabel->setText(message);
2388void ImagingPlanner::catalogLoaded()
2390 DPRINTF(stderr,
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
2396 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
2397 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
2399 m_CatalogSortModel->invalidate();
2401 ui->CatalogView->resizeColumnsToContents();
2404 auto index = ui->CatalogView->
model()->
index(0, 0);
2406 ui->CatalogView->selectionModel()->select(index,
2408 ui->CatalogView->setFocus();
2415void ImagingPlanner::updateStatus()
2417 if (currentObjectName().isEmpty())
2419 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2420 const int totalCatalogObjects = m_CatalogModel->rowCount();
2422 if (numDisplayedObjects > 0)
2423 setStatus(
i18n(
"Select an object."));
2424 else if (totalCatalogObjects > 0)
2425 setStatus(
i18n(
"Check Filters to unhide objects."));
2427 setStatus(
i18n(
"Load a Catalog."));
2434void ImagingPlanner::showEvent(
QShowEvent * e)
2437 if (m_initialShow ==
false)
2439 m_initialShow =
true;
2447void ImagingPlanner::slotClose()
2453QUrl ImagingPlanner::getAstrobinUrl(
const QString &target,
bool requireAwards,
bool requireSomeFilters,
double minRadius,
2456 QString myQuery = QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").arg(target);
2459 auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
2460 QDate today = localTime.date();
2461 myQuery.
append(QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
2464 myQuery.
append(QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
2466 if (requireSomeFilters)
2467 myQuery.
append(QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
2469 if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
2470 myQuery.
append(QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
2475 QByteArray packed = pack(b);
2477 QByteArray compressed = qCompress(packed).remove(0, 4);
2479 QByteArray b64 = compressed.
toBase64();
2481 replaceByteArrayChars(b64,
'+', QByteArray(
"%2B"));
2482 replaceByteArrayChars(b64,
'=', QByteArray(
"%3D"));
2483 replaceByteArrayChars(b,
'"', QByteArray(
"%22"));
2484 replaceByteArrayChars(b,
':', QByteArray(
"%3A"));
2485 replaceByteArrayChars(b,
'[', QByteArray(
"%5B"));
2486 replaceByteArrayChars(b,
']', QByteArray(
"%5D"));
2487 replaceByteArrayChars(b,
',', QByteArray(
"%2C"));
2488 replaceByteArrayChars(b,
'\'', QByteArray(
"%27"));
2489 replaceByteArrayChars(b,
'{', QByteArray(
"%7B"));
2490 replaceByteArrayChars(b,
'}', QByteArray(
"%7D"));
2492 QString url = QString(
"https://app.astrobin.com/search?p=%1").arg(b64.
toStdString().c_str());
2496void ImagingPlanner::popupAstrobin(
const QString &target)
2498 QString newStr = replaceSpaceWith(target,
"-");
2501 const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(),
false, Options::astrobinMinRadius(),
2502 Options::astrobinMaxRadius());
2511bool ImagingPlanner::checkIfPageExists(
const QString &urlString)
2516 QUrl url(urlString);
2517 QNetworkRequest request(url);
2518 QNetworkReply *reply = m_networkManager.get(request);
2535 fprintf(stderr,
"checkIfPageExists --> success\n");
2541 fprintf(stderr,
"checkIfPageExists --> it doesn't exist\n");
2547 fprintf(stderr,
"checkIfPageExists --> timed out\n");
2554void ImagingPlanner::adjustSpecialWebPageButton(
const QString &name)
2560 toolTip =
i18n(
"Search the Professor Seligman online site for NGC images.");
2565 toolTip =
i18n(
"Search the Professor Seligman online site for information about IC objects..");
2570 label =
"Sharpless";
2571 toolTip =
i18n(
"Search the galaxymap.org online site for information about Sharpless2 objects.");
2577 toolTip =
i18n(
"Search Nasa's online site for information about Messier objects..");
2582 toolTip =
i18n(
"Search Emil Ivanov's online site for information about VDB objects.");
2589 const int num = numberPart.
toInt(&ok);
2593 ui->searchSpecialWebPageImages->setText(catalog);
2594 ui->searchSpecialWebPageImages2->setText(catalog);
2595 ui->searchSpecialWebPageImages->setEnabled(
true);
2596 ui->searchSpecialWebPageImages2->setEnabled(
true);
2597 ui->searchSpecialWebPageImages->setToolTip(
toolTip);
2598 ui->searchSpecialWebPageImages2->setToolTip(
toolTip);
2602 ui->searchSpecialWebPageImages->setText(
"");
2603 ui->searchSpecialWebPageImages2->setText(
"");
2604 ui->searchSpecialWebPageImages->setEnabled(
false);
2605 ui->searchSpecialWebPageImages2->setEnabled(
false);
2606 ui->searchSpecialWebPageImages->setToolTip(
"");
2607 ui->searchSpecialWebPageImages2->setToolTip(
"");
2611void ImagingPlanner::searchSpecialWebPageImages()
2614 const QString
objectName = currentObjectName();
2619 const QString numberPart =
objectName.mid(3).trimmed();
2620 const int num = numberPart.
toInt(&ok);
2622 urlString = QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3")
2623 .
arg(num / 100).
arg(num % 100 < 50 ?
"" :
"a").
arg(num);
2627 const QString numberPart =
objectName.mid(2).trimmed();
2628 const int num = numberPart.
toInt(&ok);
2630 urlString = QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3")
2631 .
arg(num / 100).
arg(num % 100 < 50 ?
"" :
"a").
arg(num);
2635 const QString numberPart =
objectName.mid(3).trimmed();
2636 const int num = numberPart.
toInt(&ok);
2638 urlString = QString(
"http://galaxymap.org/cat/view/sharpless/%1").
arg(num);
2642 const QString numberPart =
objectName.mid(1).trimmed();
2643 const int num = numberPart.
toInt(&ok);
2645 urlString = QString(
"https://science.nasa.gov/mission/hubble/science/"
2646 "explore-the-night-sky/hubble-messier-catalog/messier-%1").
arg(num);
2650 const QString numberPart =
objectName.mid(3).trimmed();
2651 const int num = numberPart.
toInt(&ok);
2654 urlString = QString(
"https://www.irida-observatory.org/CCD/VdB%1/VdB%1.html").
arg(num);
2655 if (checkIfPageExists(urlString))
2656 fprintf(stderr,
"It exists\n");
2659 fprintf(stderr,
"It doesn't exist\n");
2660 urlString =
"https://www.emilivanov.com/CCD%20Images/Catalog_VdB.htm";
2669void ImagingPlanner::searchSimbad()
2672 QString
name = currentObjectName();
2674 int abellNumber = 0;
2675 bool abellPlanetary = isAbellPlanetary(name, &abellNumber);
2677 name = QString(
"PN A66 %1").
arg(abellNumber);
2679 name.
replace(QRegularExpression(
"sh2\\s*"),
"sh2-");
2688 QString urlStr = QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1"
2689 "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
2695void ImagingPlanner::searchWikipedia()
2698 QString wikipediaAddress =
"https://en.wikipedia.org";
2699 QString
name = currentObjectName();
2702 DPRINTF(stderr,
"NULL object sent to Wikipedia.\n");
2708 QString urlStr = QString(
"%1/w/index.php?search=%2").
arg(wikipediaAddress).
arg(replaceSpaceWith(name,
"_"));
2713void ImagingPlanner::searchAstrobin()
2716 QString
name = currentObjectName();
2719 popupAstrobin(name);
2722bool ImagingPlanner::eventFilter(
QObject * obj,
QEvent * event)
2724 if (m_loadingCatalog)
2730 m_InitialLoad =
false;
2731 setStatus(
i18n(
"Loading Catalogs..."));
2736 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>(
event);
2738 if ((obj == ui->helpButton) &&
2741 (mouseEvent->
modifiers() & Qt::KeyboardModifier::ShiftModifier) &&
2742 (mouseEvent->
modifiers() & Qt::KeyboardModifier::ControlModifier) &&
2743 (mouseEvent->
modifiers() & Qt::KeyboardModifier::AltModifier))
2747 ui->DevelFrame->setVisible(!ui->DevelFrame->isVisible());
2758 else if ((obj == ui->CatalogView->viewport()) &&
2762 int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
2763 QStringList selectedNames;
2764 for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
2766 selectedNames.
append(r.siblingAtColumn(0).
data().toString());
2767 bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
2768 if (isPicked) numPicked++;
2769 else numNotPicked++;
2770 bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
2771 if (isImaged) numImaged++;
2772 else numNotImaged++;
2773 bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
2774 if (isIgnored) numIgnored++;
2775 else numNotIgnored++;
2778 if (selectedNames.
size() == 0)
2782 m_PopupMenu =
new ImagingPlannerPopup;
2784 const bool imaged = numImaged > 0;
2785 const bool picked = numPicked > 0;
2786 const bool ignored = numIgnored > 0;
2787 m_PopupMenu->init(
this, selectedNames,
2788 (numImaged > 0 && numNotImaged > 0) ?
nullptr : &imaged,
2789 (numPicked > 0 && numNotPicked > 0) ?
nullptr : &picked,
2790 (numIgnored > 0 && numNotIgnored > 0) ?
nullptr : &ignored);
2792 m_PopupMenu->popup(
pos);
2796 userNotesEditFinished();
2799 keywordEditFinished();
2810 keywordEditFinished();
2811 ui->keywordEdit->clearFocus();
2834 else if ((obj == ui->ImagePreview ||
2835 obj == ui->ImagePreviewCredit ||
2836 obj == ui->ImagePreviewCreditLink) &&
2839 if (!ui->ImagePreviewCreditLink->text().isEmpty())
2841 QUrl url(ui->ImagePreviewCreditLink->text());
2849void ImagingPlanner::keywordEditFinished()
2851 QString kwd = ui->keywordEdit->toPlainText().trimmed();
2852 ui->keywordEdit->clear();
2853 ui->keywordEdit->setText(kwd);
2854 if (m_Keyword != kwd)
2857 Options::setImagingPlannerKeyword(kwd);
2858 Options::self()->save();
2859 updateSortConstraints();
2860 m_CatalogSortModel->invalidate();
2861 ui->CatalogView->resizeColumnsToContents();
2866void ImagingPlanner::setDefaultImage()
2868 ui->ImagePreview->setPixmap(m_NoImagePixmap);
2869 ui->ImagePreview->update();
2870 ui->ImagePreviewCredit->setText(
"");
2871 ui->ImagePreviewCreditLink->setText(
"");
2876 if (m_loadingCatalog)
2879 Q_UNUSED(deselected);
2880 if (selected.
indexes().size() == 0)
2888 auto selection = selected.
indexes()[0];
2889 QString
name = selection.
data().toString();
2890 CatalogObject *
object = getObject(name);
2891 if (
object ==
nullptr)
2898 ui->ImagePreviewCredit->setText(
"");
2899 ui->ImagePreviewCreditLink->setText(
"");
2902 CatalogImageInfo catalogImageInfo;
2903 if (findCatalogImageInfo(name, &catalogImageInfo))
2905 QString filename = catalogImageInfo.m_Filename;
2906 if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
2908 QString imageFullPath = filename;
2909 if (QFileInfo(filename).isRelative())
2911 QString catDir = QFileInfo(Options::imagingPlannerCatalogPath()).absolutePath();
2912 imageFullPath = QString(
"%1%2%3").
arg(catDir)
2915 if (!QFile(imageFullPath).exists())
2916 DPRINTF(stderr,
"Image for \"%s\" -- \"%s\" doesn't exist\n",
2920 if (!catalogImageInfo.m_Link.
isEmpty())
2922 ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
2923 ui->ImagePreview->setToolTip(
"Click to see original");
2924 ui->ImagePreviewCreditLink->setToolTip(
"Click to see original");
2928 ui->ImagePreviewCreditLink->setText(
"");
2929 ui->ImagePreview->setToolTip(
"");
2930 ui->ImagePreviewCreditLink->setToolTip(
"");
2933 if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
2935 ui->ImagePreviewCredit->setText(
2936 QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
2937 .arg(creativeCommonsString(catalogImageInfo.m_License)));
2938 ui->ImagePreviewCredit->setToolTip(
2939 QString(
"Original image license: %1")
2940 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2942 else if (!catalogImageInfo.m_Author.
isEmpty())
2944 ui->ImagePreviewCredit->setText(
2945 QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
2946 ui->ImagePreviewCredit->setToolTip(
"");
2948 else if (!catalogImageInfo.m_License.
isEmpty())
2950 ui->ImagePreviewCredit->setText(
2951 QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
2952 ui->ImagePreviewCredit->setToolTip(
2953 QString(
"Original image license: %1")
2954 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2958 ui->ImagePreviewCredit->setText(
"");
2959 ui->ImagePreviewCredit->setToolTip(
"");
2965 object->load_image();
2966 auto image =
object->image();
2972 const QString foundFilename = findObjectImage(name);
2975 constexpr int thumbHeight = 300, thumbWidth = 400;
2976 const QImage img = QImage(foundFilename);
2977 const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
2979 ui->ImagePreview->setPixmap(
2990 adjustSpecialWebPageButton(currentObjectName());
2993void ImagingPlanner::updateDisplays()
2998 if (!currentCatalogObject())
3000 if (ui->CatalogView->model()->rowCount() > 0)
3002 auto index = ui->CatalogView->
model()->
index(0, 0);
3003 ui->CatalogView->selectionModel()->select(index,
3008 auto object = currentCatalogObject();
3011 updateDetails(*
object, currentObjectFlags());
3012 updateNotes(currentObjectNotes());
3013 plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
3020void ImagingPlanner::updateDetails(
const CatalogObject &
object,
int flags)
3022 ui->infoObjectName->setText(
object.
name());
3023 ui->infoSize->setText(QString(
"%1' x %2'").arg(
object.a(), 0,
'f', 1).arg(
object.b(), 0,
'f', 1));
3025 QPalette
palette = ui->infoObjectLongName->palette();
3028 ui->infoObjectLongName->setPalette(
palette);
3029 if (
object.longname().isEmpty() || (
object.longname() ==
object.
name()))
3030 ui->infoObjectLongName->clear();
3032 ui->infoObjectLongName->setText(QString(
"(%1)").arg(
object.longname()));
3036 auto noon = KStarsDateTime(getDate(), QTime(12, 0, 0));
3037 QTime riseTime =
object.riseSetTime(noon, getGeo(),
true);
3038 QTime setTime =
object.riseSetTime(noon, getGeo(),
false);
3039 QTime transitTime =
object.transitTime(noon, getGeo());
3040 dms transitAltitude =
object.transitAltitude(noon, getGeo());
3043 KSMoon *moon = getMoon();
3046 const double separation = ui->CatalogView->selectionModel()->currentIndex()
3047 .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
3049 if (separation >= 0)
3050 moonString = QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0,
'f', 1);
3053 QString riseSetString;
3055 riseSetString = QString(
"%1 %2 @ %3º")
3060 riseSetString = QString(
"%1 %2")
3064 riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
3071 riseSetString = QString(
"%1 %2")
3075 riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
3082 riseSetString = QString(
"%1 %2 %3 %4")
3088 riseSetString = QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
3096 if (moonString.
size() > 0)
3097 riseSetString.
append(QString(
", %1").arg(moonString));
3098 ui->infoRiseSet->setText(riseSetString);
3100 palette = ui->infoObjectFlags->palette();
3102 ui->infoObjectFlags->setPalette(
palette);
3103 ui->infoObjectFlags->setText(flagString(flags));
3112void ImagingPlanner::plotAltitudeGraph(
const QDate &date,
const dms &ra,
const dms &dec)
3114 auto altitudeGraph = ui->altitudeGraph;
3115 altitudeGraph->setAltitudeAxis(-20.0, 90.0);
3118 QVector<QDateTime> jobStartTimes, jobEndTimes;
3119 getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ui->maxMoonAltitude->value(), ra, dec,
3120 ui->useArtificialHorizon->isChecked(),
3121 &jobStartTimes, &jobEndTimes);
3123 auto tz = QTimeZone(getGeo()->TZ() * 3600);
3124 KStarsDateTime midnight = KStarsDateTime(date.
addDays(1), QTime(0, 1));
3127 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
3128 KSAlmanac ksal(ut, getGeo());
3129 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
3131 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
3134 Ekos::SchedulerJob job;
3135 setupJob(job,
"temp", ui->minAltitude->value(), ui->minMoon->value(), ui->maxMoonAltitude->value(), ra, dec,
3136 ui->useArtificialHorizon->isChecked());
3138 QVector<double> times, alts;
3139 QDateTime plotStart = dusk;
3144 plotStart = plotStart.
addSecs(-1 * 3600);
3147 auto plotEnd = dawn.
addSecs(1 * 3600);
3150 while (t.secsTo(plotEnd) > 0)
3152 SkyPoint coords = job.getTargetCoords();
3153 double alt = getAltitude(getGeo(), coords, t);
3155 double hour = midnight.
secsTo(t) / 3600.0;
3157 t = t.addSecs(60 * 10);
3160 altitudeGraph->plot(getGeo(), &ksal, times, alts);
3162 for (
int i = 0; i < jobStartTimes.
size(); ++i)
3164 auto startTime = jobStartTimes[i];
3165 auto stopTime = jobEndTimes[i];
3166 if (startTime < plotStart) startTime = plotStart;
3167 if (stopTime > plotEnd) stopTime = plotEnd;
3170 stopTime.setTimeZone(tz);
3172 QVector<double> runTimes, runAlts;
3177 while (t.secsTo(stopTime) > 0)
3179 SkyPoint coords = job.getTargetCoords();
3180 double alt = getAltitude(getGeo(), coords, t);
3182 double hour = midnight.
secsTo(t) / 3600.0;
3184 t = t.addSecs(60 * 10);
3186 altitudeGraph->plotOverlay(runTimes, runAlts);
3190void ImagingPlanner::updateCounts()
3192 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
3193 const int totalCatalogObjects = m_CatalogModel->rowCount();
3194 if (numDisplayedObjects == 1)
3195 ui->tableCount->setText(QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
3197 ui->tableCount->setText(QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
3200void ImagingPlanner::moveBackOneDay()
3203 QString selection = currentObjectName();
3204 ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
3208 scrollToName(selection);
3211void ImagingPlanner::moveForwardOneDay()
3213 QString selection = currentObjectName();
3214 ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
3218 scrollToName(selection);
3221QString ImagingPlanner::currentObjectName()
const
3223 QString
name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).
data(
3230 QString
name = currentObjectName();
3231 return getObject(name);
3236void ImagingPlanner::objectDetails()
3238 CatalogObject *current = currentCatalogObject();
3239 if (current ==
nullptr)
3241 auto ut = KStarsData::Instance()->
ut();
3243 QPointer<DetailDialog> dd =
3249void ImagingPlanner::centerOnSkymap()
3251 if (!Options::imagingPlannerCenterOnSkyMap())
3253 reallyCenterOnSkymap();
3256void ImagingPlanner::reallyCenterOnSkymap()
3258 CatalogObject *current = currentCatalogObject();
3259 if (current ==
nullptr)
3265 DPRINTF(stderr,
"found a 0,0 object\n");
3270 KStarsDateTime time = KStarsData::Instance()->
clock()->
utc();
3271 dms lst = getGeo()->GSTtoLST(time.
gst());
3276 bool keepGround = Options::showGround();
3277 bool keepAnimatedSlew = Options::useAnimatedSlewing();
3278 Options::setShowGround(
false);
3279 Options::setUseAnimatedSlewing(
false);
3285 Options::setShowGround(keepGround);
3286 Options::setUseAnimatedSlewing(keepAnimatedSlew);
3289void ImagingPlanner::setSelection(
int flag,
bool enabled)
3291 auto rows = ui->CatalogView->selectionModel()->selectedRows();
3300 QList<QModelIndex> sourceIndeces;
3301 for (
int i = 0; i < rows.size(); ++i)
3303 auto proxyIndex = rows[i].siblingAtColumn(FLAGS_COLUMN);
3304 auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
3305 sourceIndeces.
append(sourceIndex);
3308 for (
int i = 0; i < sourceIndeces.
size(); ++i)
3310 auto &sourceIndex = sourceIndeces[i];
3314 setFlag(sourceIndex, flag, m_CatalogModel.data());
3316 clearFlag(sourceIndex, flag, m_CatalogModel.data());
3318 QString
name = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
3319 int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3320 QString notes = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).
toString();
3321 saveToDB(name, flags, notes);
3323 if (flag == IMAGED_BIT)
3324 highlightImagedObject(sourceIndex,
enabled);
3325 if (flag == PICKED_BIT)
3326 highlightPickedObject(sourceIndex,
enabled);
3331void ImagingPlanner::highlightImagedObject(
const QModelIndex &index,
bool imaged)
3334 QColor m_DefaultCellBackground(36, 35, 35);
3335 QColor m_ImagedObjectBackground(10, 65, 10);
3336 QString themeName = KSTheme::Manager::instance()->currentThemeName().
toLatin1().
data();
3337 if (themeName ==
"High Key" || themeName ==
"Default" || themeName ==
"White Balance")
3339 m_DefaultCellBackground = QColor(240, 240, 240);
3340 m_ImagedObjectBackground = QColor(180, 240, 180);
3342 for (
int col = 0; col < LAST_COLUMN; ++col)
3345 m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground,
Qt::BackgroundRole);
3349void ImagingPlanner::highlightPickedObject(
const QModelIndex &index,
bool picked)
3351 for (
int col = 0; col < LAST_COLUMN; ++col)
3355 auto ff = qvariant_cast<QFont>(
font);
3357 ff.setItalic(picked);
3358 ff.setUnderline(picked);
3364void ImagingPlanner::setSelectionPicked()
3366 setSelection(PICKED_BIT,
true);
3369void ImagingPlanner::setSelectionNotPicked()
3371 setSelection(PICKED_BIT,
false);
3374void ImagingPlanner::setSelectionImaged()
3376 setSelection(IMAGED_BIT,
true);
3379void ImagingPlanner::setSelectionNotImaged()
3381 setSelection(IMAGED_BIT,
false);
3384void ImagingPlanner::setSelectionIgnored()
3386 setSelection(IGNORED_BIT,
true);
3389void ImagingPlanner::setSelectionNotIgnored()
3391 setSelection(IGNORED_BIT,
false);
3394int ImagingPlanner::currentObjectFlags()
3396 auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(FLAGS_COLUMN);
3397 const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
3400 return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
3403QString ImagingPlanner::currentObjectNotes()
3405 auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(NOTES_COLUMN);
3406 const bool hasNotes = ui->CatalogView->
model()->
data(index, NOTES_ROLE).
canConvert<QString>();
3409 return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
3412void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
3414 auto index = ui->CatalogView->selectionModel()->currentIndex();
3419 auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
3421 m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
3424ImagingPlannerPopup::ImagingPlannerPopup() :
QMenu(nullptr)
3433void ImagingPlannerPopup::init(ImagingPlanner * planner,
const QStringList &names,
3434 const bool * imaged,
const bool * picked,
const bool * ignored)
3437 if (names.
size() == 0)
return;
3440 if (names.
size() == 1)
3442 else if (names.
size() <= 3)
3445 for (
int i = 1; i < names.
size(); i++)
3446 title.append(QString(
", %1").arg(names[i]));
3449 title =
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
3453 QString word = names.
size() == 1 ? names[0] :
i18n(
"objects");
3455 if (imaged ==
nullptr)
3457 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3458 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3461 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3463 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3465 if (picked ==
nullptr)
3467 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3468 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3471 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3473 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3476 if (ignored ==
nullptr)
3478 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3479 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3483 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3485 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3488 addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
3492ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
bool picked,
bool imaged,
3493 bool ignored,
const QString ¬es) : m_Name(
name), m_Notes(notes)
3498ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
int flags,
const QString ¬es)
3499 : m_Name(
name), m_Flags(flags), m_Notes(notes)
3503void ImagingPlannerDBEntry::getFlags(
bool * picked,
bool * imaged,
bool * ignored)
3505 *picked = m_Flags & PickedBit;
3506 *imaged = m_Flags & ImagedBit;
3507 *ignored = m_Flags & IgnoredBit;
3511void ImagingPlannerDBEntry::setFlags(
bool picked,
bool imaged,
bool ignored)
3514 if (picked) m_Flags |= PickedBit;
3515 if (imaged) m_Flags |= ImagedBit;
3516 if (ignored) m_Flags |= IgnoredBit;
3519void ImagingPlanner::saveToDB(
const QString &name,
bool picked,
bool imaged,
3520 bool ignored,
const QString ¬es)
3522 ImagingPlannerDBEntry e(name, 0, notes);
3523 e.setFlags(picked, imaged, ignored);
3527void ImagingPlanner::saveToDB(
const QString &name,
int flags,
const QString ¬es)
3529 ImagingPlannerDBEntry e(name, flags, notes);
3534void ImagingPlanner::loadFromDB()
3539 m_CatalogSortModel->setSourceModel(
nullptr);
3541 auto tz = QTimeZone(getGeo()->TZ() * 3600);
3542 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
3543 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
3544 KSAlmanac ksal(ut, getGeo());
3546 QList<ImagingPlannerDBEntry>
list;
3548 QHash<QString, ImagingPlannerDBEntry> dbData;
3549 QHash<QString, int> dbNotes;
3550 for (
const auto &entry : list)
3552 dbData[entry.m_Name] = entry;
3555 int rows = m_CatalogModel->rowCount();
3556 for (
int i = 0; i < rows; ++i)
3558 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
3559 auto entry = dbData.
find(name);
3560 if (entry != dbData.
end())
3562 QVariant f = entry->m_Flags;
3563 m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
3564 if (entry->m_Flags & IMAGED_BIT)
3565 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3566 if (entry->m_Flags & PICKED_BIT)
3567 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3568 QVariant n = entry->m_Notes;
3569 m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
3573 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
3576void ImagingPlanner::loadImagedFile()
3578 if (m_loadingCatalog)
3586 QFile inputFile(fileName);
3590 QStringList failedNames;
3591 QTextStream in(&inputFile);
3597 name = tweakNames(name);
3598 if (getObject(name))
3601 auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
3602 QVariant value(name);
3604 if (matches.size() > 0)
3606 setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
3607 highlightImagedObject(matches[0],
true);
3610 QString
name = m_CatalogModel->
data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
3611 int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3612 QString notes = m_CatalogModel->
data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
3613 saveToDB(name, flags, notes);
3617 DPRINTF(stderr,
"ooops! internal inconsitency--got an object but match didn't work");
3621 failedNames.
append(name);
3624 if (failedNames.
size() == 0)
3627 KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
3629 KSNotification::sorry(
i18n(
"Empty file"));
3633 int num = std::min((
int)failedNames.
size(), 10);
3634 QString sample = QString(
"\"%1\"").arg(failedNames[0]);
3635 for (
int i = 1; i < num; ++i)
3636 sample.
append(QString(
" \"%1\"").arg(failedNames[i]));
3637 if (numSuccess == 0 && failedNames.
size() <= 10)
3638 KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
3639 else if (numSuccess == 0)
3640 KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
3641 else if (numSuccess > 0 && failedNames.
size() <= 10)
3642 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
3643 numSuccess, failedNames.
size() == 1 ?
"this" :
"these", sample));
3645 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
3646 numSuccess, failedNames.
size(), sample));
3651 KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
3655void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
3657 m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
3660bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo * info)
3663 if (
result == m_CatalogImageInfoMap.end())
3665 if (
result->m_Filename.isEmpty())
3671void ImagingPlanner::loadCatalogViaMenu()
3673 QString startDir = Options::imagingPlannerCatalogPath();
3675 startDir = defaultDirectory();
3684void ImagingPlanner::loadCatalog(
const QString &path)
3686 removeEventFilters();
3693 m_loadingCatalog =
true;
3694 loadCatalogFromFile(path);
3702 m_loadingCatalog =
false;
3703 installEventFilters();
3706 if (m_CatalogSortModel->rowCount() > 0)
3708 auto name = m_CatalogSortModel->index(0, 0).
data().toString();
3710 QItemSelection selection, deselection;
3711 selection.
select(m_CatalogSortModel->index(0, 0), m_CatalogSortModel->index(0, 0));
3712 selectionChanged(selection, deselection);
3716CatalogImageInfo::CatalogImageInfo(
const QString &csv)
3721 QStringList columns = line.
split(
",");
3722 if (columns.
size() < 1 || columns[0].isEmpty())
3725 m_Name = columns[column++];
3726 if (columns.
size() <= column)
return;
3727 m_Filename = columns[column++];
3728 if (columns.
size() <= column)
return;
3729 m_Author = columns[column++];
3730 if (columns.
size() <= column)
return;
3731 m_Link = columns[column++];
3732 if (columns.
size() <= column)
return;
3733 m_License = columns[column++];
3754void ImagingPlanner::loadCatalogFromFile(
QString path,
bool reset)
3756 QFile inputFile(path);
3760 m_numMissingImage = 0;
3762 int numMissingImage = 0, numWithImage = 0;
3763 if (!inputFile.exists())
3765 emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
3768 QStringList objectNames;
3771 const auto tz = QTimeZone(getGeo()->TZ() * 3600);
3772 const KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
3773 const KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
3774 const KSAlmanac ksal(ut, getGeo());
3778 Options::setImagingPlannerCatalogPath(path);
3779 Options::self()->save();
3780 if (m_CatalogModel->rowCount() > 0)
3781 m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
3784 QTextStream in(&inputFile);
3787 CatalogImageInfo info(in.readLine().trimmed());
3788 const QString
name = info.m_Name;
3796 const auto match = re.match(name);
3797 if (
match.hasMatch())
3799 const QString catFilename =
match.captured(1);
3800 if (catFilename.
isEmpty())
continue;
3801 const QFileInfo fInfo(catFilename);
3803 QString catFullPath = catFilename;
3804 if (!fInfo.isAbsolute())
3806 const QString catDir = QFileInfo(path).absolutePath();
3807 catFullPath = QString(
"%1%2%3").
arg(catDir)
3810 if (catFullPath != path)
3811 loadCatalogFromFile(catFullPath,
false);
3821 const auto match = re.match(name);
3822 if (
match.hasMatch())
3824 const QString catFilename =
match.captured(1);
3825 if (catFilename.
isEmpty())
continue;
3826 const QFileInfo fInfo(catFilename);
3828 QString catFullPath = catFilename;
3829 if (!fInfo.isAbsolute())
3831 const QString catDir = QFileInfo(path).absolutePath();
3832 catFullPath = QString(
"%1%2%3").
arg(catDir)
3835 std::pair<bool, QString> out = m_manager.import_catalog(catFullPath,
false);
3836 DPRINTF(stderr,
"Load of KStars catalog %s %s%s\n", catFullPath.
toLatin1().
data(),
3837 out.first ?
"succeeded." :
"failed: ", out.second.toLatin1().data());
3846 const auto match = re.match(name);
3847 if (
match.hasMatch())
3849 const QString catIDstr =
match.captured(1);
3850 if (catIDstr.
isEmpty())
continue;
3853 const int catID = catIDstr.
toInt(&ok);
3854 if (ok && m_manager.catalog_exists(catID))
3856 const std::pair<bool, QString> out = m_manager.remove_catalog(catID);
3857 DPRINTF(stderr,
"Removal of out-of-date catalog %d %s%s\n", catID,
3858 out.first ?
"succeeded." :
"failed: ", out.second.toLatin1().data());
3863 objectNames.
append(name);
3864 if (!info.m_Filename.isEmpty())
3867 QFileInfo fInfo(info.m_Filename);
3868 if (fInfo.isRelative())
3869 info.m_Filename = QString(
"%1%2%3").arg(QFileInfo(path).absolutePath())
3871 addCatalogImageInfo(info);
3882 int num = 0, numBad = 0, iteration = 0;
3884 for (
const auto &name : objectNames)
3886 setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
3887 if (addCatalogItem(ksal, name, 0)) num++;
3894 m_numWithImage += numWithImage;
3895 m_numMissingImage += numMissingImage;
3896 DPRINTF(stderr,
"Catalog %s: %d of %d have catalog images\n",
3901 emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
3905void ImagingPlanner::sorry(
const QString &message)
3907 KSNotification::sorry(message);
a dms subclass that caches its sine and cosine values every time the angle is changed.
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
CatalogObject & insertStaticObject(const CatalogObject &obj)
Insert an object obj into m_static_objects and return a reference to the newly inserted object.
static QString processSearchText(QString searchText)
Do some post processing on the search text to interpret what the user meant This could include replac...
int size()
Return the numbers of flags.
void remove(int index)
Remove a flag.
void add(const SkyPoint &flagPoint, QString epoch, QString image, QString label, QColor labelColor)
Add a flag.
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
A class that implements methods to find sun rise, sun set, twilight begin / end times,...
Provides necessary information about the Moon.
void findPhase(const KSSun *Sun=nullptr)
Determine the phase angle of the moon, and assign the appropriate moon image.
const QImage & image() const
void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false) override
Update position of the planet (reimplemented from SkyPoint)
bool AddImagingPlannerEntry(const ImagingPlannerDBEntry &entry)
Adds a new Imaging Planner row into the database.
bool GetAllImagingPlannerEntries(QList< ImagingPlannerDBEntry > *entryList)
Gets all the Imaging Planner rows from the database.
const KStarsDateTime & ut() const
Q_INVOKABLE SimClock * clock()
SkyMapComposite * skyComposite()
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addSecs(double s) const
void setDate(const QDate &d)
Assign the Date according to a QDate object.
static KStars * Instance()
KStarsData * data() const
const KStarsDateTime & utc() const
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
void setClickedPoint(const SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
void setClickedObject(SkyObject *o)
Set the ClickedObject pointer to the argument.
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
void slotCenter()
Center the display at the point ClickedPoint.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
virtual QString name(void) const
virtual QString longname(void) const
QString name2(void) const
TYPE
The type classification of the SkyObject.
The sky coordinates of a point in the sky.
const CachingDms & dec() const
const CachingDms & ra0() const
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
void setRA(dms &r)
Sets RA, the current Right Ascension.
const CachingDms & ra() const
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
const CachingDms & dec0() const
void setDec0(dms d)
Sets Dec0, the catalog Declination.
An angle, stored as degrees, but expressible in many ways.
const double & Degrees() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
Type type(const QSqlDatabase &db)
StartupCondition
Conditions under which a SchedulerJob may start.
QMap< QString, uint16_t > CapturedFramesMap
mapping signature --> frames count
CompletionCondition
Conditions under which a SchedulerJob may complete.
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT CopyJob * move(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
KIOCORE_EXPORT QString number(KIO::filesize_t size)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
QString name(const QVariant &location)
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString label(StandardShortcut id)
void initialize(StandardShortcut id)
std::pair< bool, CatalogObject > resolveName(const QString &name)
Resolve the name of the given DSO and extract data from various sources.
virtual QVariant data(const QModelIndex &index, int role) const const=0
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual QModelIndex parent(const QModelIndex &index) const const=0
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
qsizetype length() const const
QByteArray & replace(QByteArrayView before, QByteArrayView after)
void resize(qsizetype newSize, char c)
qsizetype size() const const
QByteArray toBase64(Base64Options options) const const
std::string toStdString() const const
void processEvents(QEventLoop::ProcessEventsFlags flags)
QDate addDays(qint64 ndays) const const
QString toString(QStringView format, QCalendar cal) const const
QDateTime addSecs(qint64 s) const const
bool isValid() const const
qint64 secsTo(const QDateTime &other) const const
void setTimeZone(const QTimeZone &toZone)
void dateChanged(QDate date)
bool openUrl(const QUrl &url)
QString absolutePath() const const
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
bool exists() const const
bool mkpath(const QString &dirPath) const const
qint64 elapsed() const const
int exec(ProcessEventsFlags flags)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QDateTime birthTime() const const
iterator find(const Key &key)
QIcon fromTheme(const QString &name)
bool save(QIODevice *device, const char *format, int quality) const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
QImage scaledToHeight(int height, Qt::TransformationMode mode) const const
QModelIndexList indexes() const const
void select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
void append(QList< T > &&value)
qsizetype indexOf(const AT &value, qsizetype from) const const
void push_back(parameter_type value)
qsizetype size() const const
bool isValid() const const
const QAbstractItemModel * model() const const
QModelIndex siblingAtColumn(int column) const const
int globalX() const const
int globalY() const const
NetworkError error() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
QString tr(const char *sourceText, const char *disambiguation, int n)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
qsizetype capturedStart(QStringView name) const const
bool hasMatch() const const
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
virtual QVariant data(int role) const const
virtual void setData(const QVariant &value, int role)
void setTextAlignment(Qt::Alignment alignment)
QString & append(QChar ch)
QString arg(Args &&... args) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
qsizetype size() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QByteArray toLatin1() const const
QString toLower() const const
QString toUpper() const const
QByteArray toUtf8() const const
QString trimmed() const const
QTextStream & dec(QTextStream &stream)
QTextStream & endl(QTextStream &stream)
QTextStream & fixed(QTextStream &stream)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
bool isValid(int h, int m, int s, int ms)
QString toString(QStringView format) const const
void setInterval(int msec)
bool isActive() const const
bool isEmpty() const const
bool canConvert() const const
int toInt(bool *ok) const const
QString toString() const const