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 <QRegularExpression>
44#include <QSortFilterProxyModel>
45#include <QStandardItemModel>
50#define DPRINTF if (false) fprintf
77#define TYPE_ROLE (Qt::UserRole + 1)
78#define HOURS_ROLE (Qt::UserRole + 2)
79#define SIZE_ROLE (Qt::UserRole + 3)
80#define ALTITUDE_ROLE (Qt::UserRole + 4)
81#define MOON_ROLE (Qt::UserRole + 5)
82#define FLAGS_ROLE (Qt::UserRole + 6)
83#define NOTES_ROLE (Qt::UserRole + 7)
85#define PICKED_BIT ImagingPlannerDBEntry::PickedBit
86#define IMAGED_BIT ImagingPlannerDBEntry::ImagedBit
87#define IGNORED_BIT ImagingPlannerDBEntry::IgnoredBit
113 case SkyObject::OPEN_CLUSTER:
114 return Options::imagingPlannerAcceptOpenCluster();
115 case SkyObject::GLOBULAR_CLUSTER:
116 return Options::imagingPlannerAcceptGlobularCluster();
117 case SkyObject::GASEOUS_NEBULA:
118 return Options::imagingPlannerAcceptNebula();
119 case SkyObject::PLANETARY_NEBULA:
120 return Options::imagingPlannerAcceptPlanetary();
121 case SkyObject::SUPERNOVA_REMNANT:
122 return Options::imagingPlannerAcceptSupernovaRemnant();
123 case SkyObject::GALAXY:
124 return Options::imagingPlannerAcceptGalaxy();
125 case SkyObject::GALAXY_CLUSTER:
126 return Options::imagingPlannerAcceptGalaxyCluster();
127 case SkyObject::DARK_NEBULA:
128 return Options::imagingPlannerAcceptDarkNebula();
130 return Options::imagingPlannerAcceptOther();
137 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
140 const bool flag = model->
data(idx, FLAGS_ROLE).
toInt() & bit;
147 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
148 int currentFlags = 0;
150 currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
152 model->
setData(idx, val, FLAGS_ROLE);
158 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
161 const int currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
163 model->
setData(idx, val, FLAGS_ROLE);
169 if (flags & IMAGED_BIT) str.
append(
i18n(
"Imaged"));
170 if (flags & PICKED_BIT)
176 if (flags & IGNORED_BIT)
186void setupShowCallback(
bool checked,
187 void (*showOption)(
bool),
void (*showNotOption)(
bool),
188 void (*dontCareOption)(
bool),
192 Q_UNUSED(showCheckbox);
196 showNotOption(
false);
197 dontCareOption(
false);
200 Options::self()->save();
205 showNotOption(
false);
206 dontCareOption(
true);
209 Options::self()->save();
213void setupShowNotCallback(
bool checked,
214 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
217 Q_UNUSED(showNotCheckbox);
222 dontCareOption(
false);
225 Options::self()->save();
230 showNotOption(
false);
231 dontCareOption(
true);
234 Options::self()->save();
238void setupDontCareCallback(
bool checked,
239 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
245 showNotOption(
false);
246 dontCareOption(
true);
249 Options::self()->save();
256 showNotOption(
false);
257 dontCareOption(
true);
261 Options::self()->save();
270 "\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
275 auto match = re.match(input);
276 if (!
match.hasMatch())
279 return(
match.captured(0));
285 match = re.match(inp);
286 if (!
match.hasMatch())
289 return (
match.captured(0));
315 int column,
int role)
317 const double l =
left.siblingAtColumn(column).data(role).toDouble();
318 const double r =
right.siblingAtColumn(column).data(role).toDouble();
328 const QString l =
left.siblingAtColumn(column).data(role).toString();
329 const QString r =
right.siblingAtColumn(column).data(role).toString();
333 if (lList.
size() == 0 || rList.
size() == 0)
344 if (lList.
size() >= 2 && rList.
size() >= 2)
346 int lInt = lList[1].toInt();
347 int rInt = rList[1].toInt();
350 if (lInt > 0 && rInt > 0)
351 return -(lInt - rInt);
359#include "ekos/scheduler/schedulerjob.h"
360void SchedulerUtils_setupJob(Ekos::SchedulerJob &job,
const QString &name,
bool isLead,
const QString &group,
361 const QString &train,
const dms &ra,
const dms &dec,
double djd,
double rotation,
const QUrl &sequenceUrl,
363 const QDateTime &completionTime,
int completionRepeats,
double minimumAltitude,
double minimumMoonSeparation,
364 bool enforceWeather,
bool enforceTwilight,
bool enforceArtificialHorizon,
bool track,
bool focus,
bool align,
bool guide)
368 job.setIsLead(isLead);
369 job.setOpticalTrain(train);
370 job.setPositionAngle(rotation);
376 job.setLeadJob(
nullptr);
378 job.setTargetCoords(ra, dec, djd);
379 job.setFITSFile(fitsUrl);
382 job.setStartupCondition(startup);
383 if (startup == Ekos::START_AT)
385 job.setStartupTime(startupTime);
388 job.setFileStartupCondition(job.getStartupCondition());
389 job.setStartAtTime(job.getStartupTime());
393 job.setMinAltitude(minimumAltitude);
394 job.setMinMoonSeparation(minimumMoonSeparation);
397 job.setEnforceWeather(enforceWeather);
399 job.setEnforceTwilight(enforceTwilight);
400 job.setEnforceArtificialHorizon(enforceArtificialHorizon);
403 job.setStepPipeline(Ekos::SchedulerJob::USE_NONE);
405 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_TRACK));
407 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_FOCUS));
409 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_ALIGN));
411 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_GUIDE));
414 job.setFileStartupCondition(job.getStartupCondition());
415 job.setStartAtTime(job.getStartupTime());
420 job.setSequenceFile(sequenceUrl);
421 job.setCompletionCondition(completion);
422 if (completion == Ekos::FINISH_AT)
423 job.setFinishAtTime(completionTime);
424 else if (completion == Ekos::FINISH_REPEAT)
426 job.setRepeatsRequired(completionRepeats);
427 job.setRepeatsRemaining(completionRepeats);
435void setupJob(Ekos::SchedulerJob &job,
const QString name,
double minAltitude,
double minMoonSeparation,
dms ra,
dms dec,
436 bool useArtificialHorizon)
439 double rotation = 0.0;
445 SchedulerUtils_setupJob(job, name,
true,
"",
447 rotation, sequenceURL,
QUrl(),
450 minAltitude, minMoonSeparation,
451 false,
true, useArtificialHorizon,
452 true,
true,
true,
true);
456void getRunTimes(
const QDate &date,
const GeoLocation &geo,
double minAltitude,
double minMoonSeparation,
460 jobStartTimes->
clear();
461 jobEndTimes->
clear();
462 constexpr int SCHEDULE_RESOLUTION_MINUTES = 10;
463 Ekos::SchedulerJob job;
464 setupJob(job,
"temp", minAltitude, minMoonSeparation, ra, dec, useArtificialHorizon);
471 startTime.setTimeZone(tz);
472 stopTime.setTimeZone(tz);
476 while (--maxIters >= 0)
478 QDateTime s = job.getNextPossibleStartTime(startTime, SCHEDULE_RESOLUTION_MINUTES,
false, stopTime);
483 QDateTime e = job.getNextEndTime(s, SCHEDULE_RESOLUTION_MINUTES, &constraintReason, stopTime);
491 if (e.
secsTo(stopTime) < 600)
501 double minMoonSeparation,
bool useArtificialHorizon)
504 getRunTimes(date, geo, minAltitude, minMoonSeparation,
object.ra0(),
object.dec0(), useArtificialHorizon, &jobStartTimes,
506 if (jobStartTimes.
size() == 0 || jobEndTimes.
size() == 0)
510 double totalHours = 0.0;
511 for (
int i = 0; i < jobStartTimes.
size(); ++i)
512 totalHours += jobStartTimes[i].secsTo(jobEndTimes[i]) * 1.0 / 3600.0;
521int packString(
const QString &input, quint8 *p,
bool reallyPack)
524 quint32 len = str_data.
length();
525 const char *str = str_data.
data();
526 constexpr bool compatibilityMode =
false;
527 const quint8 *origP = p;
530 if (reallyPack) *p = 0xa0 | len;
533 else if (len <= std::numeric_limits<quint8>::max() &&
534 compatibilityMode ==
false)
536 if (reallyPack) *p = 0xd9;
538 if (reallyPack) *p = len;
541 else if (len <= std::numeric_limits<quint16>::max())
543 if (reallyPack) *p = 0xda;
554 if (reallyPack) memcpy(p, str, len);
555 return (p - origP) + len;
562 int size = packString(input,
nullptr,
false);
566 packString(input,
reinterpret_cast<quint8*
>(arr.
data()),
true);
576 newStr = newStr.
replace(0, 4,
"sh2-");
577 newStr = newStr.
replace(
' ',
"");
581bool downsampleImageFiles(
const QString &baseDir,
int maxHeight)
592 const QString subDir =
"REDUCED";
593 QDir directory(baseDir);
594 if (!directory.exists())
596 fprintf(stderr,
"downsampleImageFiles: Base directory doesn't exist\n");
604 fprintf(stderr,
"downsampleImageFiles: Failed making the output directory\n");
611 foreach (
QString filename, files)
616 if (img.height() > maxHeight)
625 if (!scaledImg.
save(jpgFilename,
"JPG"))
626 fprintf(stderr,
"downsampleImageFiles: Failed saving \"%s\"\n", writeFilename.
toLatin1().
data());
630 fprintf(stderr,
"downsampleImageFiles: saved \"%s\"\n", writeFilename.
toLatin1().
data());
633 fprintf(stderr,
"downsampleImageFiles: Wrote %d files\n", numSaved);
644 const int len = bInput.
size();
646 for (
int i = 0; i < len; ++i)
656 bInput.
replace(pos, 1, substitute);
664 QString massagedName = massageObjectName(name);
669 if (files.size() > 0)
670 return files[0].absoluteFilePath();
673 for (
int i = 0; i < subDirs.size(); i++)
675 QDir subDir(subDirs[i].absoluteFilePath());
677 if (files.size() > 0)
678 return files[0].absoluteFilePath();
685 if (astrobinAbbrev ==
"ACC")
687 else if (astrobinAbbrev ==
"ASACC")
689 else if (astrobinAbbrev ==
"ANCCC")
691 else if (astrobinAbbrev ==
"ANCSACC")
692 return "CC-BY-SA-NC";
696QString creativeCommonsTooltipString(
const QString &astrobinAbbrev)
698 if (astrobinAbbrev ==
"ACC")
699 return "Atribution Creative Commons";
700 else if (astrobinAbbrev ==
"ASACC")
701 return "Atribution Share-Alike Creative Commons";
702 else if (astrobinAbbrev ==
"ANCCC")
703 return "Atribution Non-Commercial Creative Commons";
704 else if (astrobinAbbrev ==
"ANCSACC")
705 return "Atribution Non-Commercial Share-Alike Creative Commons";
720 return p.
alt().Degrees();
724 double hoursAfterDusk = 0,
double hoursBeforeDawn = 0)
730 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
732 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
738 auto end = dawn.
addSecs(-hoursBeforeDawn * 3600);
749 while (t.secsTo(end) > 0)
751 double alt = getAltitude(geo, coords, t);
757 t = t.addSecs(60 * 20);
766 m_SortColumn = HOURS_COLUMN;
770bool CatalogFilter::filterAcceptsRow(
int row,
const QModelIndex &parent)
const
774 if (!acceptType(type))
return false;
778 if (!hasEnoughHours)
return false;
783 const bool passesImagedConstraints = !m_ImagedConstraintsEnabled || (isImaged == m_ImagedRequired);
784 if (!passesImagedConstraints)
return false;
786 const bool isIgnored =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IGNORED_BIT;
787 const bool passesIgnoredConstraints = !m_IgnoredConstraintsEnabled || (isIgnored == m_IgnoredRequired);
788 if (!passesIgnoredConstraints)
return false;
790 const bool isPicked =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & PICKED_BIT;
791 const bool passesPickedConstraints = !m_PickedConstraintsEnabled || (isPicked == m_PickedRequired);
792 if (!passesPickedConstraints)
return false;
795 if (m_Keyword.
isEmpty() || !m_KeywordConstraintsEnabled)
return true;
800 return (m_KeywordRequired == REMatches);
803void CatalogFilter::setMinHours(
double hours)
808void CatalogFilter::setImagedConstraints(
bool enabled,
bool required)
810 m_ImagedConstraintsEnabled = enabled;
811 m_ImagedRequired = required;
814void CatalogFilter::setPickedConstraints(
bool enabled,
bool required)
816 m_PickedConstraintsEnabled = enabled;
817 m_PickedRequired = required;
820void CatalogFilter::setIgnoredConstraints(
bool enabled,
bool required)
822 m_IgnoredConstraintsEnabled = enabled;
823 m_IgnoredRequired = required;
826void CatalogFilter::setKeywordConstraints(
bool enabled,
bool required,
const QString &keyword)
828 m_KeywordConstraintsEnabled = enabled;
829 m_KeywordRequired = required;
834void CatalogFilter::setSortColumn(
int column)
836 if (column == m_SortColumn)
837 m_ReverseSort = !m_ReverseSort;
838 m_SortColumn = column;
847 double compareVal = 0;
852 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
853 if (m_ReverseSort) compareVal = -compareVal;
857 compareVal = stringCompareFcn(left, right, TYPE_COLUMN,
Qt::DisplayRole);
858 if (m_ReverseSort) compareVal = -compareVal;
859 if (compareVal != 0)
break;
860 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
861 if (compareVal != 0)
break;
862 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
866 compareVal = floatCompareFcn(left, right, SIZE_COLUMN, SIZE_ROLE);
867 if (m_ReverseSort) compareVal = -compareVal;
868 if (compareVal != 0)
break;
869 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
870 if (compareVal != 0)
break;
871 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
873 case ALTITUDE_COLUMN:
875 compareVal = floatCompareFcn(left, right, ALTITUDE_COLUMN, ALTITUDE_ROLE);
876 if (m_ReverseSort) compareVal = -compareVal;
877 if (compareVal != 0)
break;
878 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
879 if (compareVal != 0)
break;
880 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
884 compareVal = floatCompareFcn(left, right, MOON_COLUMN, MOON_ROLE);
885 if (m_ReverseSort) compareVal = -compareVal;
886 if (compareVal != 0)
break;
887 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
888 if (compareVal != 0)
break;
889 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
891 case CONSTELLATION_COLUMN:
893 compareVal = stringCompareFcn(left, right, CONSTELLATION_COLUMN,
Qt::DisplayRole);
894 if (m_ReverseSort) compareVal = -compareVal;
895 if (compareVal != 0)
break;
896 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
897 if (compareVal != 0)
break;
898 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
902 compareVal = stringCompareFcn(left, right, COORD_COLUMN,
Qt::DisplayRole);
903 if (m_ReverseSort) compareVal = -compareVal;
904 if (compareVal != 0)
break;
905 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
906 if (compareVal != 0)
break;
907 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
912 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
913 if (m_ReverseSort) compareVal = -compareVal;
914 if (compareVal != 0)
break;
915 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
918 return compareVal < 0;
928void ImagingPlannerUI::setupIcons()
952 return KStarsData::Instance()->
geo();
955QDate ImagingPlanner::getDate()
const
957 return ui->DateEdit->date();
960ImagingPlanner::ImagingPlanner() :
QDialog(nullptr), m_manager{ CatalogsDB::dso_db_path() }
962 ui =
new ImagingPlannerUI(
this);
968 setLayout(mainLayout);
970 setWindowTitle(
i18nc(
"@title:window",
"Imaging Planner"));
973 if (Options::imagingPlannerIndependentWindow())
988void ImagingPlanner::setupHideButtons(
bool(*option)(),
void(*setOption)(
bool),
998 Options::self()->save();
1007 Options::self()->save();
1015void ImagingPlanner::focusOnTable()
1020void ImagingPlanner::adjustWindowSize()
1022 const int keepWidth =
width();
1024 const int newHeight =
height();
1025 resize(keepWidth, newHeight);
1029void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox,
bool(*option)(),
void(*setOption)(
bool))
1035 Options::self()->save();
1036 m_CatalogSortModel->invalidate();
1038 ui->CatalogView->resizeColumnsToContents();
1044void ImagingPlanner::setupFilter2Buttons(
1046 bool(*yesOption)(),
bool(*noOption)(),
bool(*dontCareOption)(),
1047 void(*setYesOption)(
bool),
void(*setNoOption)(
bool),
void(*setDontCareOption)(
bool))
1053 setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1054 updateSortConstraints();
1055 m_CatalogSortModel->invalidate();
1056 ui->CatalogView->resizeColumnsToContents();
1062 setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1063 updateSortConstraints();
1064 m_CatalogSortModel->invalidate();
1065 ui->CatalogView->resizeColumnsToContents();
1069 connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
1071 setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1072 updateSortConstraints();
1073 m_CatalogSortModel->invalidate();
1074 ui->CatalogView->resizeColumnsToContents();
1085void ImagingPlanner::updateSortConstraints()
1087 m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
1088 ui->pickedCB->isChecked());
1089 m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
1090 ui->imagedCB->isChecked());
1091 m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
1092 ui->ignoredCB->isChecked());
1093 m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
1094 ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
1098void ImagingPlanner::initialize()
1100 if (KStarsData::Instance() ==
nullptr)
1107 connect(
this, &ImagingPlanner::popupSorry,
this, &ImagingPlanner::sorry);
1113 m_CatalogModel->setHorizontalHeaderLabels(
1116 m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
1117 i18n(
"Object Name--click header to sort ascending/descending."));
1118 m_CatalogModel->horizontalHeaderItem(
1119 HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
1120 m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
1121 i18n(
"Object Type--click header to sort ascending/descending."));
1122 m_CatalogModel->horizontalHeaderItem(
1123 SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
1124 m_CatalogModel->horizontalHeaderItem(
1125 ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
1126 m_CatalogModel->horizontalHeaderItem(
1127 MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
1128 m_CatalogModel->horizontalHeaderItem(
1129 CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
1130 m_CatalogModel->horizontalHeaderItem(
1131 COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
1133 m_CatalogSortModel =
new CatalogFilter(
this);
1135 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
1136 m_CatalogSortModel->setDynamicSortFilter(
true);
1138 ui->CatalogView->setModel(m_CatalogSortModel.
data());
1139 ui->CatalogView->setSortingEnabled(
false);
1140 ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
1141 ui->CatalogView->resizeColumnsToContents();
1144 ui->CatalogView->verticalHeader()->
setVisible(
false);
1145 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
1148 this, &ImagingPlanner::selectionChanged);
1153 auto utc = KStarsData::Instance()->
clock()->
utc();
1154 auto localTime = getGeo()->UTtoLT(utc);
1155 ui->DateEdit->setDate(localTime.date());
1161 setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
1162 ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
1163 ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
1170 QString selection = currentObjectName();
1174 scrollToName(selection);
1190 Options::setImagingPlannerHideAstrobinDetails(
true);
1191 setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
1192 ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
1193 ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
1194 ui->AstrobinAward->setChecked(Options::astrobinAward());
1197 Options::setAstrobinAward(checked);
1198 Options::self()->save();
1201 ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
1204 Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
1205 Options::self()->save();
1208 ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
1211 Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
1212 Options::self()->save();
1226 setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
1227 ui->hideImageButton, ui->showImageButton,
1228 ui->ImageFrame, ui->HiddenImageFrame);
1231 Options::setImagingPlannerHideFilters(
true);
1232 setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
1233 ui->hideFilterTypesButton, ui->showFilterTypesButton,
1234 ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
1235 setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
1236 &Options::setImagingPlannerAcceptOpenCluster);
1237 setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
1238 setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
1239 &Options::setImagingPlannerAcceptGlobularCluster);
1240 setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
1241 setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
1242 &Options::setImagingPlannerAcceptSupernovaRemnant);
1243 setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
1244 setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
1245 &Options::setImagingPlannerAcceptGalaxyCluster);
1246 setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
1247 setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
1249 setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
1250 &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
1251 &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
1253 setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
1254 &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
1255 &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
1257 setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
1258 &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
1259 &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
1260 &Options::setImagingPlannerDontCareIgnored);
1262 ui->keywordEdit->setText(Options::imagingPlannerKeyword());
1263 ui->keywordEdit->setAcceptRichText(
false);
1264 m_Keyword = Options::imagingPlannerKeyword();
1265 setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
1266 &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
1267 &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
1268 &Options::setImagingPlannerDontCareKeyword);
1274 ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
1275 m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
1276 ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
1277 m_MinMoon = Options::imagingPlannerMinMoonSeparation();
1278 ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
1279 m_MinAltitude = Options::imagingPlannerMinAltitude();
1280 ui->minHours->setValue(Options::imagingPlannerMinHours());
1281 m_MinHours = Options::imagingPlannerMinHours();
1282 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1285 if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
1287 m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
1288 Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
1289 Options::self()->save();
1295 if (m_MinMoon == ui->minMoon->value())
1297 m_MinMoon = ui->minMoon->value();
1298 Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
1299 Options::self()->save();
1305 if (m_MinAltitude == ui->minAltitude->value())
1307 m_MinAltitude = ui->minAltitude->value();
1308 Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
1309 Options::self()->save();
1315 if (m_MinHours == ui->minHours->value())
1317 m_MinHours = ui->minHours->value();
1318 Options::setImagingPlannerMinHours(ui->minHours->value());
1319 Options::self()->save();
1320 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1321 m_CatalogSortModel->invalidate();
1322 ui->CatalogView->resizeColumnsToContents();
1326 updateSortConstraints();
1328 m_CatalogSortModel->setMinHours(ui->minHours->value());
1330 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
1340 ui->userNotesLabel->setVisible(true);
1341 ui->userNotesEdit->setText(ui->userNotes->text());
1342 ui->userNotesEdit->setVisible(true);
1343 ui->userNotesEditButton->setVisible(false);
1344 ui->userNotesDoneButton->setVisible(true);
1345 ui->userNotes->setVisible(false);
1346 ui->userNotesLabel->setVisible(true);
1347 ui->userNotesOpenLink->setVisible(false);
1348 ui->userNotesOpenLink2->setVisible(false);
1349 ui->userNotesOpenLink3->setVisible(false);
1355 QString urlString = findUrl(ui->userNotes->text());
1356 if (urlString.isEmpty())
1358 QDesktopServices::openUrl(QUrl(urlString));
1363 QString urlString = findUrl(ui->userNotes->text(), 2);
1364 if (urlString.isEmpty())
1366 QDesktopServices::openUrl(QUrl(urlString));
1371 QString urlString = findUrl(ui->userNotes->text(), 3);
1372 if (urlString.isEmpty())
1374 QDesktopServices::openUrl(QUrl(urlString));
1384 m_CatalogSortModel->setSortColumn(column);
1385 m_CatalogSortModel->invalidate();
1386 ui->CatalogView->resizeColumnsToContents();
1395 qRegisterMetaType<QList<QStandardItem *>>(
"QList<QStandardItem *>");
1396 connect(
this, &ImagingPlanner::addRow,
this, &ImagingPlanner::addRowSlot);
1405void ImagingPlanner::openOptionsMenu()
1413void ImagingPlanner::getHelp()
1423 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/MESSIER", 300))
1424 fprintf(stderr,
"downsampling succeeded\n");
1426 fprintf(stderr,
"downsampling failed\n");
1428 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/OTHER", 300))
1429 fprintf(stderr,
"downsampling succeeded\n");
1431 fprintf(stderr,
"downsampling failed\n");
1433 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/CALDWELL", 300))
1434 fprintf(stderr,
"downsampling succeeded\n");
1436 fprintf(stderr,
"downsampling failed\n");
1438 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/AWARDS", 300))
1439 fprintf(stderr,
"downsampling succeeded\n");
1441 fprintf(stderr,
"downsampling failed\n");
1443 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/HERSCHEL12", 300))
1444 fprintf(stderr,
"downsampling succeeded\n");
1446 fprintf(stderr,
"downsampling failed\n");
1449 const QUrl url(
"https://docs.kde.org/trunk5/en/kstars/kstars/kstars.pdf#tool-imaging-planner");
1454KSMoon *ImagingPlanner::getMoon()
1456 if (KStarsData::Instance() ==
nullptr)
1462 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1465 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1467 moon->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1473void ImagingPlanner::updateMoon()
1475 KSMoon *moon = getMoon();
1480 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1482 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1485 sun->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1489 ui->moonPercentLabel->setText(
QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0,
'f', 0));
1492bool ImagingPlanner::scrollToName(
const QString &name)
1496 QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0),
Qt::EditRole,
1498 if(matchList.count() >= 1)
1501 for (
int i = 0; i < matchList.count(); i++)
1510 ui->CatalogView->scrollTo(matchList[bestIndex]);
1511 ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
1517void ImagingPlanner::searchSlot()
1519 QString origName = ui->SearchText->toPlainText().trimmed();
1521 ui->SearchText->setPlainText(name);
1525 if (!scrollToName(name))
1526 KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
1529 ui->SearchText->clear();
1530 ui->SearchText->setPlainText(
"");
1533void ImagingPlanner::initUserNotes()
1546void ImagingPlanner::disableUserNotes()
1558void ImagingPlanner::userNotesEditFinished()
1560 const QString ¬es = ui->userNotesEdit->toPlainText().trimmed();
1561 ui->userNotes->setText(notes);
1568 setCurrentObjectNotes(notes);
1569 setupNotesLinks(notes);
1571 auto o = currentCatalogObject();
1573 saveToDB(currentObjectName(), currentObjectFlags(), notes);
1576void ImagingPlanner::updateNotes(
const QString ¬es)
1580 ui->userNotes->setText(notes);
1582 setupNotesLinks(notes);
1585void ImagingPlanner::setupNotesLinks(
const QString ¬es)
1589 if (!
link.isEmpty())
1590 ui->userNotesOpenLink->
setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
1592 link = findUrl(notes, 2);
1594 if (!
link.isEmpty())
1595 ui->userNotesOpenLink2->
setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
1597 link = findUrl(notes, 3);
1599 if (!
link.isEmpty())
1600 ui->userNotesOpenLink3->
setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
1610 std::list<CatalogObject> objs =
1628 if (objs.size() == 0)
1630 if (objs.size() == 0)
1644 m_manager.
add_object(CatalogsDB::user_catalog_id, cedata.second);
1645 const auto &added_object =
1646 m_manager.
get_object(cedata.second.getId(), CatalogsDB::user_catalog_id);
1649 if (added_object.first)
1651 *catObject = KStarsData::Instance()
1653 ->catalogsComponent()
1656 DPRINTF(stderr,
"***** Found %s using name resolver (%.1fs)\n",
name.
toLatin1().
data(),
1657 timer.elapsed() / 1000.0);
1662 if (objs.size() == 0)
1666 *catObject = objs.front();
1667 if (objs.size() > 1)
1669 QString addSpace = filteredName;
1671 for (
const auto &obj : objs)
1691 auto o = m_CatalogHash.
find(lName);
1692 if (o == m_CatalogHash.
end())
1697void ImagingPlanner::clearObjects()
1703 m_CatalogHash.
clear();
1711 if (getObject(lName) !=
nullptr)
1713 DPRINTF(stderr,
"Didn't add \"%s\" because it's already there\n",
name.
toLatin1().
data());
1718 if (!getKStarsCatalogObject(lName, &o))
1720 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
1723 m_CatalogHash[lName] = o;
1724 return &(m_CatalogHash[lName]);
1729bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal,
const QString &name,
int flags)
1732 if (
object ==
nullptr)
1745 for (
int i = 0; i < LAST_COLUMN; ++i)
1747 if (i == NAME_COLUMN)
1749 itemList.
append(getItemWithUserRole(name));
1751 else if (i == HOURS_COLUMN)
1753 double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
1754 ui->useArtificialHorizon->isChecked());
1755 auto hoursItem = getItemWithUserRole(
QString(
"%1").arg(runHours, 0,
'f', 1));
1756 hoursItem->setData(runHours, HOURS_ROLE);
1757 itemList.
append(hoursItem);
1759 else if (i == TYPE_COLUMN)
1761 auto typeItem = getItemWithUserRole(
QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
1762 typeItem->setData(object->
type(), TYPE_ROLE);
1763 itemList.
append(typeItem);
1765 else if (i == SIZE_COLUMN)
1767 double size = std::max(object->
a(), object->
b());
1768 auto sizeItem = getItemWithUserRole(
QString(
"%1'").arg(
size, 0,
'f', 1));
1769 sizeItem->setData(
size, SIZE_ROLE);
1770 itemList.
append(sizeItem);
1772 else if (i == ALTITUDE_COLUMN)
1775 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
1776 auto altItem = getItemWithUserRole(
QString(
"%1º").arg(altitude, 0,
'f', 0));
1777 altItem->setData(altitude, ALTITUDE_ROLE);
1778 itemList.
append(altItem);
1780 else if (i == MOON_COLUMN)
1782 KSMoon *moon = getMoon();
1788 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1795 auto moonItem = getItemWithUserRole(
QString(
"%1º").arg(separation, 0,
'f', 0));
1796 moonItem->setData(separation, MOON_ROLE);
1797 itemList.
append(moonItem);
1801 auto moonItem = getItemWithUserRole(
QString(
""));
1802 moonItem->setData(-1, MOON_ROLE);
1805 else if (i == CONSTELLATION_COLUMN)
1807 QString cname = KStarsData::Instance()
1809 ->constellationBoundary()
1810 ->constellationName(
object);
1812 auto constellationItem = getItemWithUserRole(cname);
1813 itemList.
append(constellationItem);
1815 else if (i == COORD_COLUMN)
1817 itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
1819 else if (i == FLAGS_COLUMN)
1822 flag->
setData(flags, FLAGS_ROLE);
1825 else if (i == NOTES_COLUMN)
1833 DPRINTF(stderr,
"Bug in addCatalogItem() !\n");
1838 emit addRow(itemList);
1844 m_CatalogModel->appendRow(itemList);
1848void ImagingPlanner::recompute()
1850 setStatus(
i18n(
"Updating tables..."));
1853 m_CatalogSortModel->setSourceModel(
nullptr);
1858 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1863 for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
1865 const QString &
name = m_CatalogModel->item(i, 0)->text();
1867 if (catalogEntry ==
nullptr)
1869 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n",
name.
toLatin1().
data());
1872 double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
1873 ui->minMoon->value(), ui->useArtificialHorizon->isChecked());
1878 hItem->
setData(runHours, HOURS_ROLE);
1879 m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
1883 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
1887 altItem->setData(altitude, ALTITUDE_ROLE);
1888 m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
1890 KSMoon *moon = getMoon();
1896 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1906 moonItem->setData(separation, MOON_ROLE);
1907 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1913 moonItem->setData(-1, MOON_ROLE);
1914 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1918 const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
1920 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
1921 const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
1923 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
1926 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
1928 DPRINTF(stderr,
"Recompute took %.1fs\n", timer.elapsed() / 1000.0);
1935void ImagingPlanner::checkTargets()
1939 fprintf(stderr,
"****************** check objects (%d)***************\n", flags->
size());
1940 for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
1941 fprintf(stderr,
"Removed, now %d\n", flags->
size());
1943 int rows = m_CatalogModel->rowCount();
1947 for (
int i = 0; i < rows; ++i)
1949 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
1951 accepted[i] = getObject(name) !=
nullptr;
1953 auto object = getObject(name);
1957 fprintf(stderr,
"%d ", i);
1961 for (
int i = 0; i < targets.
size(); ++i)
1967 object->setRA(object->
ra0());
1968 object->setDec(object->
dec0());
1969 for (
int j = 0; j < targets.
size(); ++j)
1971 if (i == j)
continue;
1973 auto name2 = targets[j];
1974 auto object2 = getObject(name2);
1975 object2->setRA(object2->ra0());
1976 object2->setDec(object2->dec0());
1977 const dms dist =
object->angularDistanceTo(object2);
1978 const double arcsecDist = dist.
Degrees() * 3600.0;
1979 if (arcsecDist < 120)
1981 fprintf(stderr,
"dist %10s (%s %s) to %10s (%s %s) = %.0f\" %s\n",
1983 object->
ra().toHMSString().toLatin1().data(),
1984 object->
dec().toDMSString().toLatin1().data(),
1986 object2->ra().toHMSString().toLatin1().data(),
1987 object2->dec().toDMSString().toLatin1().data(),
1994 fprintf(stderr,
"Done\n");
2001QString ImagingPlanner::defaultDirectory()
const
2009QString ImagingPlanner::findDefaultCatalog()
const
2013 for (
int i = 0; i < subDirs.size(); i++)
2016 const QDir subDir(subDirs[i].absoluteFilePath());
2019 if (files.size() > 0)
2024 for (
const auto &file : files)
2027 firstFile = file.absoluteFilePath();
2029 return file.absoluteFilePath();
2038void ImagingPlanner::loadInitialCatalog()
2040 QString catalog = Options::imagingPlannerCatalogPath();
2042 catalog = findDefaultCatalog();
2045 KSNotification::sorry(
i18n(
"You need to load a catalog to start using this tool.\nSee Data -> Download New Data..."));
2046 setStatus(
i18n(
"No Catalog!"));
2049 loadCatalog(catalog);
2052void ImagingPlanner::setStatus(
const QString &message)
2054 ui->statusLabel->setText(message);
2058void ImagingPlanner::catalogLoaded()
2060 DPRINTF(stderr,
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
2066 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
2067 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
2069 m_CatalogSortModel->invalidate();
2071 ui->CatalogView->resizeColumnsToContents();
2074 auto index = ui->CatalogView->model()->index(0, 0);
2076 ui->CatalogView->selectionModel()->select(index,
2085void ImagingPlanner::updateStatus()
2087 if (currentObjectName().isEmpty())
2089 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2090 const int totalCatalogObjects = m_CatalogModel->rowCount();
2092 if (numDisplayedObjects > 0)
2093 setStatus(
i18n(
"Select an object."));
2094 else if (totalCatalogObjects > 0)
2095 setStatus(
i18n(
"Check Filters to unhide objects."));
2097 setStatus(
i18n(
"Load a Catalog."));
2107 if (m_initialResultsLoad ==
false)
2110 m_initialResultsLoad =
true;
2121void ImagingPlanner::slotClose()
2127QUrl ImagingPlanner::getAstrobinUrl(
const QString &target,
bool requireAwards,
bool requireSomeFilters,
double minRadius,
2130 QString myQuery =
QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").
arg(target);
2133 auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
2134 QDate today = localTime.date();
2135 myQuery.
append(
QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
2138 myQuery.
append(
QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
2140 if (requireSomeFilters)
2141 myQuery.
append(
QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
2143 if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
2144 myQuery.
append(
QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
2155 replaceByteArrayChars(b64,
'+',
QByteArray(
"%2B"));
2156 replaceByteArrayChars(b64,
'=',
QByteArray(
"%3D"));
2157 replaceByteArrayChars(b,
'"',
QByteArray(
"%22"));
2158 replaceByteArrayChars(b,
':',
QByteArray(
"%3A"));
2159 replaceByteArrayChars(b,
'[',
QByteArray(
"%5B"));
2160 replaceByteArrayChars(b,
']',
QByteArray(
"%5D"));
2161 replaceByteArrayChars(b,
',',
QByteArray(
"%2C"));
2162 replaceByteArrayChars(b,
'\'',
QByteArray(
"%27"));
2163 replaceByteArrayChars(b,
'{',
QByteArray(
"%7B"));
2164 replaceByteArrayChars(b,
'}',
QByteArray(
"%7D"));
2170void ImagingPlanner::popupAstrobin(
const QString &target)
2172 QString newStr = massageObjectName(target);
2175 const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(),
false, Options::astrobinMinRadius(),
2176 Options::astrobinMaxRadius());
2182void ImagingPlanner::searchNGCICImages()
2185 auto o = currentCatalogObject();
2188 fprintf(stderr,
"NULL object sent to searchNGCICImages.\n");
2194 num = o->name().mid(3).toInt();
2195 QString urlString =
QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3").
arg(num / 100).
arg(
2196 num % 100 < 50 ?
"" :
"a").
arg(num);
2202 num = o->name().mid(2).toInt();
2203 QString urlString =
QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3").
arg(num / 100).
arg(
2204 num % 100 < 50 ?
"" :
"a").
arg(num);
2210void ImagingPlanner::searchSimbad()
2222 QString urlStr =
QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1"
2223 "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
2229void ImagingPlanner::searchWikipedia()
2232 QString wikipediaAddress =
"https://en.wikipedia.org";
2236 fprintf(stderr,
"NULL object sent to Wikipedia.\n");
2254 .
arg(wikipediaAddress).
arg(massageObjectName(name));
2258 QUrl(
QString(
"%1/wiki/%2").arg(wikipediaAddress).arg(massagedName)));
2261void ImagingPlanner::searchAstrobin()
2267 popupAstrobin(name);
2270bool ImagingPlanner::eventFilter(
QObject * obj,
QEvent * event)
2274 m_InitialLoad =
false;
2276 setStatus(
i18n(
"Loading Catalogs..."));
2277 loadInitialCatalog();
2282 if ((obj == ui->CatalogView->viewport()) &&
2287 int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
2289 for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
2291 selectedNames.
append(r.siblingAtColumn(0).
data().toString());
2292 bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
2293 if (isPicked) numPicked++;
2294 else numNotPicked++;
2295 bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
2296 if (isImaged) numImaged++;
2297 else numNotImaged++;
2298 bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
2299 if (isIgnored) numIgnored++;
2300 else numNotIgnored++;
2303 if (selectedNames.
size() == 0)
2307 m_PopupMenu =
new ImagingPlannerPopup;
2309 const bool imaged = numImaged > 0;
2310 const bool picked = numPicked > 0;
2311 const bool ignored = numIgnored > 0;
2312 m_PopupMenu->init(
this, selectedNames,
2313 (numImaged > 0 && numNotImaged > 0) ?
nullptr : &imaged,
2314 (numPicked > 0 && numNotPicked > 0) ?
nullptr : &picked,
2315 (numIgnored > 0 && numNotIgnored > 0) ?
nullptr : &ignored);
2317 m_PopupMenu->popup(
pos);
2321 userNotesEditFinished();
2324 keywordEditFinished();
2335 keywordEditFinished();
2359 else if ((obj == ui->ImagePreview ||
2360 obj == ui->ImagePreviewCredit ||
2361 obj == ui->ImagePreviewCreditLink) &&
2364 if (!ui->ImagePreviewCreditLink->text().isEmpty())
2366 QUrl url(ui->ImagePreviewCreditLink->text());
2374void ImagingPlanner::keywordEditFinished()
2376 QString kwd = ui->keywordEdit->toPlainText().trimmed();
2377 ui->keywordEdit->clear();
2378 ui->keywordEdit->setText(kwd);
2379 if (m_Keyword != kwd)
2382 Options::setImagingPlannerKeyword(kwd);
2383 Options::self()->save();
2384 updateSortConstraints();
2385 m_CatalogSortModel->invalidate();
2386 ui->CatalogView->resizeColumnsToContents();
2391void ImagingPlanner::setDefaultImage()
2393 ui->ImagePreview->setPixmap(m_NoImagePixmap);
2394 ui->ImagePreview->
update();
2395 ui->ImagePreviewCredit->setText(
"");
2396 ui->ImagePreviewCreditLink->setText(
"");
2401 Q_UNUSED(deselected);
2402 if (selected.
indexes().size() == 0)
2410 auto selection = selected.
indexes()[0];
2413 if (
object ==
nullptr)
2420 ui->ImagePreviewCredit->setText(
"");
2421 ui->ImagePreviewCreditLink->setText(
"");
2424 CatalogImageInfo catalogImageInfo;
2425 if (findCatalogImageInfo(name, &catalogImageInfo))
2427 QString filename = catalogImageInfo.m_Filename;
2428 if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
2430 QString imageFullPath = filename;
2434 imageFullPath =
QString(
"%1%2%3").
arg(catDir)
2437 if (!
QFile(imageFullPath).exists())
2438 DPRINTF(stderr,
"Image for \"%s\" -- \"%s\" doesn't exist\n",
2442 if (!catalogImageInfo.m_Link.
isEmpty())
2444 ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
2445 ui->ImagePreview->
setToolTip(
"Click to see original");
2446 ui->ImagePreviewCreditLink->
setToolTip(
"Click to see original");
2450 ui->ImagePreviewCreditLink->setText(
"");
2455 if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
2457 ui->ImagePreviewCredit->setText(
2458 QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
2459 .
arg(creativeCommonsString(catalogImageInfo.m_License)));
2461 QString(
"Original image license: %1")
2462 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2464 else if (!catalogImageInfo.m_Author.
isEmpty())
2466 ui->ImagePreviewCredit->setText(
2467 QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
2470 else if (!catalogImageInfo.m_License.
isEmpty())
2472 ui->ImagePreviewCredit->setText(
2473 QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
2475 QString(
"Original image license: %1")
2476 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2480 ui->ImagePreviewCredit->setText(
"");
2487 object->load_image();
2488 auto image =
object->image();
2494 const QString foundFilename = findObjectImage(name);
2497 constexpr int thumbHeight = 300, thumbWidth = 400;
2499 const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
2501 ui->ImagePreview->setPixmap(
2515void ImagingPlanner::updateDisplays()
2520 if (!currentCatalogObject())
2522 if (ui->CatalogView->model()->rowCount() > 0)
2524 auto index = ui->CatalogView->model()->index(0, 0);
2525 ui->CatalogView->selectionModel()->select(index,
2530 auto object = currentCatalogObject();
2533 updateDetails(*
object, currentObjectFlags());
2534 updateNotes(currentObjectNotes());
2535 plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
2542void ImagingPlanner::updateDetails(
const CatalogObject &
object,
int flags)
2544 ui->infoObjectName->setText(
object.
name());
2545 ui->infoSize->setText(
QString(
"%1' x %2'").arg(
object.a(), 0,
'f', 1).arg(
object.b(), 0,
'f', 1));
2551 if (
object.longname().isEmpty() || (
object.longname() ==
object.
name()))
2552 ui->infoObjectLongName->clear();
2554 ui->infoObjectLongName->setText(
QString(
"(%1)").arg(
object.longname()));
2559 QTime riseTime =
object.riseSetTime(noon, getGeo(),
true);
2560 QTime setTime =
object.riseSetTime(noon, getGeo(),
false);
2561 QTime transitTime =
object.transitTime(noon, getGeo());
2562 dms transitAltitude =
object.transitAltitude(noon, getGeo());
2565 KSMoon *moon = getMoon();
2568 const double separation = ui->CatalogView->selectionModel()->currentIndex()
2569 .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
2571 if (separation >= 0)
2572 moonString =
QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0,
'f', 1);
2577 riseSetString =
QString(
"%1 %2 @ %3º")
2582 riseSetString =
QString(
"%1 %2")
2586 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2593 riseSetString =
QString(
"%1 %2")
2597 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2604 riseSetString =
QString(
"%1 %2 %3 %4")
2610 riseSetString =
QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
2618 if (moonString.
size() > 0)
2620 ui->infoRiseSet->setText(riseSetString);
2625 ui->infoObjectFlags->setText(flagString(flags));
2634void ImagingPlanner::plotAltitudeGraph(
const QDate &date,
const dms &ra,
const dms &dec)
2636 auto altitudeGraph = ui->altitudeGraph;
2637 altitudeGraph->setAltitudeAxis(-20.0, 90.0);
2641 getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked(),
2642 &jobStartTimes, &jobEndTimes);
2644 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
2650 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
2652 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
2655 Ekos::SchedulerJob job;
2656 setupJob(job,
"temp", ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked());
2664 plotStart = plotStart.
addSecs(-1 * 3600);
2667 auto plotEnd = dawn.
addSecs(1 * 3600);
2670 while (t.secsTo(plotEnd) > 0)
2672 SkyPoint coords = job.getTargetCoords();
2673 double alt = getAltitude(getGeo(), coords, t);
2675 double hour = midnight.
secsTo(t) / 3600.0;
2677 t = t.addSecs(60 * 10);
2680 altitudeGraph->plot(getGeo(), &ksal, times, alts,
false);
2682 for (
int i = 0; i < jobStartTimes.
size(); ++i)
2684 auto startTime = jobStartTimes[i];
2685 auto stopTime = jobEndTimes[i];
2686 if (startTime < plotStart) startTime = plotStart;
2687 if (stopTime > plotEnd) stopTime = plotEnd;
2690 stopTime.setTimeZone(tz);
2697 while (t.secsTo(stopTime) > 0)
2699 SkyPoint coords = job.getTargetCoords();
2700 double alt = getAltitude(getGeo(), coords, t);
2702 double hour = midnight.
secsTo(t) / 3600.0;
2704 t = t.addSecs(60 * 10);
2706 altitudeGraph->plot(getGeo(), &ksal, runTimes, runAlts,
true);
2710void ImagingPlanner::updateCounts()
2712 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2713 const int totalCatalogObjects = m_CatalogModel->rowCount();
2714 if (numDisplayedObjects == 1)
2715 ui->tableCount->setText(
QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
2717 ui->tableCount->setText(
QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
2720void ImagingPlanner::moveBackOneDay()
2723 QString selection = currentObjectName();
2724 ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
2728 scrollToName(selection);
2731void ImagingPlanner::moveForwardOneDay()
2733 QString selection = currentObjectName();
2734 ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
2738 scrollToName(selection);
2741QString ImagingPlanner::currentObjectName()
const
2743 QString name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).data(
2751 return getObject(name);
2756void ImagingPlanner::objectDetails()
2759 if (current ==
nullptr)
2761 auto ut = KStarsData::Instance()->
ut();
2769void ImagingPlanner::centerOnSkymap()
2771 if (!Options::imagingPlannerCenterOnSkyMap())
2773 reallyCenterOnSkymap();
2776void ImagingPlanner::reallyCenterOnSkymap()
2779 if (current ==
nullptr)
2783 if (current->
ra().Degrees() == 0 && current->
dec().Degrees() == 0)
2785 DPRINTF(stderr,
"found a 0,0 object\n");
2791 dms lst = getGeo()->GSTtoLST(time.
gst());
2796 bool keepGround = Options::showGround();
2797 bool keepAnimatedSlew = Options::useAnimatedSlewing();
2798 Options::setShowGround(
false);
2799 Options::setUseAnimatedSlewing(
false);
2805 Options::setShowGround(keepGround);
2806 Options::setUseAnimatedSlewing(keepAnimatedSlew);
2809void ImagingPlanner::setSelection(
int flag,
bool enabled)
2811 auto rows = ui->CatalogView->selectionModel()->selectedRows();
2821 for (
int i = 0; i < rows.size(); ++i)
2823 auto proxyIndex = rows[i].siblingAtColumn(FLAGS_COLUMN);
2824 auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
2825 sourceIndeces.
append(sourceIndex);
2828 for (
int i = 0; i < sourceIndeces.
size(); ++i)
2830 auto &sourceIndex = sourceIndeces[i];
2834 setFlag(sourceIndex, flag, m_CatalogModel.
data());
2836 clearFlag(sourceIndex, flag, m_CatalogModel.
data());
2838 QString name = m_CatalogModel->data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
2839 int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
2840 QString notes = m_CatalogModel->data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
2841 saveToDB(name, flags, notes);
2843 if (flag == IMAGED_BIT)
2844 highlightImagedObject(sourceIndex,
enabled);
2845 if (flag == PICKED_BIT)
2846 highlightPickedObject(sourceIndex,
enabled);
2851void ImagingPlanner::highlightImagedObject(
const QModelIndex &index,
bool imaged)
2854 QColor m_DefaultCellBackground(36, 35, 35);
2855 QColor m_ImagedObjectBackground(10, 65, 10);
2857 if (themeName ==
"High Key" || themeName ==
"Default" || themeName ==
"White Balance")
2859 m_DefaultCellBackground =
QColor(240, 240, 240);
2860 m_ImagedObjectBackground =
QColor(180, 240, 180);
2862 for (
int col = 0; col < LAST_COLUMN; ++col)
2865 m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground,
Qt::BackgroundRole);
2869void ImagingPlanner::highlightPickedObject(
const QModelIndex &index,
bool picked)
2871 for (
int col = 0; col < LAST_COLUMN; ++col)
2875 auto ff = qvariant_cast<QFont>(
font);
2877 ff.setItalic(picked);
2878 ff.setUnderline(picked);
2884void ImagingPlanner::setSelectionPicked()
2886 setSelection(PICKED_BIT,
true);
2889void ImagingPlanner::setSelectionNotPicked()
2891 setSelection(PICKED_BIT,
false);
2894void ImagingPlanner::setSelectionImaged()
2896 setSelection(IMAGED_BIT,
true);
2899void ImagingPlanner::setSelectionNotImaged()
2901 setSelection(IMAGED_BIT,
false);
2904void ImagingPlanner::setSelectionIgnored()
2906 setSelection(IGNORED_BIT,
true);
2909void ImagingPlanner::setSelectionNotIgnored()
2911 setSelection(IGNORED_BIT,
false);
2914int ImagingPlanner::currentObjectFlags()
2916 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(FLAGS_COLUMN);
2917 const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
2920 return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
2923QString ImagingPlanner::currentObjectNotes()
2925 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NOTES_COLUMN);
2926 const bool hasNotes = ui->CatalogView->model()->data(index, NOTES_ROLE).canConvert<
QString>();
2929 return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
2932void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
2934 auto index = ui->CatalogView->selectionModel()->currentIndex();
2939 auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
2941 m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
2944ImagingPlannerPopup::ImagingPlannerPopup() :
QMenu(nullptr)
2953void ImagingPlannerPopup::init(ImagingPlanner * planner,
const QStringList &names,
2954 const bool * imaged,
const bool * picked,
const bool * ignored)
2957 if (names.
size() == 0)
return;
2960 if (names.
size() == 1)
2962 else if (names.
size() <= 3)
2965 for (
int i = 1; i < names.
size(); i++)
2969 title =
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
2975 if (imaged ==
nullptr)
2977 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
2978 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
2981 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
2983 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
2985 if (picked ==
nullptr)
2987 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
2988 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
2991 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
2993 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
2996 if (ignored ==
nullptr)
2998 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
2999 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3003 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3005 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3008 addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
3012ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
bool picked,
bool imaged,
3013 bool ignored,
const QString ¬es) : m_Name(
name), m_Notes(notes)
3018ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
int flags,
const QString ¬es)
3019 : m_Name(
name), m_Flags(flags), m_Notes(notes)
3023void ImagingPlannerDBEntry::getFlags(
bool * picked,
bool * imaged,
bool * ignored)
3025 *picked = m_Flags & PickedBit;
3026 *imaged = m_Flags & ImagedBit;
3027 *ignored = m_Flags & IgnoredBit;
3031void ImagingPlannerDBEntry::setFlags(
bool picked,
bool imaged,
bool ignored)
3034 if (picked) m_Flags |= PickedBit;
3035 if (imaged) m_Flags |= ImagedBit;
3036 if (ignored) m_Flags |= IgnoredBit;
3039void ImagingPlanner::saveToDB(
const QString &name,
bool picked,
bool imaged,
3040 bool ignored,
const QString ¬es)
3042 ImagingPlannerDBEntry e(name, 0, notes);
3043 e.setFlags(picked, imaged, ignored);
3047void ImagingPlanner::saveToDB(
const QString &name,
int flags,
const QString ¬es)
3049 ImagingPlannerDBEntry e(name, flags, notes);
3054void ImagingPlanner::loadFromDB()
3059 m_CatalogSortModel->setSourceModel(
nullptr);
3061 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3070 for (
const auto &entry : list)
3072 dbData[entry.m_Name] = entry;
3075 int rows = m_CatalogModel->rowCount();
3076 for (
int i = 0; i < rows; ++i)
3078 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
3079 auto entry = dbData.
find(name);
3080 if (entry != dbData.
end())
3083 m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
3084 if (entry->m_Flags & IMAGED_BIT)
3085 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3086 if (entry->m_Flags & PICKED_BIT)
3087 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3089 m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
3093 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
3096void ImagingPlanner::loadImagedFile()
3103 QFile inputFile(fileName);
3114 name = tweakNames(name);
3115 if (getObject(name))
3118 auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
3121 if (matches.size() > 0)
3123 setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
3124 highlightImagedObject(matches[0],
true);
3127 QString name = m_CatalogModel->data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
3128 int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3129 QString notes = m_CatalogModel->data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
3130 saveToDB(name, flags, notes);
3134 DPRINTF(stderr,
"ooops! internal inconsitency--got an object but match didn't work");
3138 failedNames.
append(name);
3141 if (failedNames.
size() == 0)
3144 KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
3146 KSNotification::sorry(
i18n(
"Empty file"));
3150 int num = std::min((
int)failedNames.
size(), 10);
3152 for (
int i = 1; i < num; ++i)
3154 if (numSuccess == 0 && failedNames.
size() <= 10)
3155 KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
3156 else if (numSuccess == 0)
3157 KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
3158 else if (numSuccess > 0 && failedNames.
size() <= 10)
3159 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
3160 numSuccess, failedNames.
size() == 1 ?
"this" :
"these", sample));
3162 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
3163 numSuccess, failedNames.
size(), sample));
3168 KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
3172void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
3174 m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
3177bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo *info)
3180 if (
result == m_CatalogImageInfoMap.
end())
3182 if (
result->m_Filename.isEmpty())
3188void ImagingPlanner::loadCatalogViaMenu()
3190 QString startDir = Options::imagingPlannerCatalogPath();
3192 startDir = defaultDirectory();
3201void ImagingPlanner::loadCatalog(
const QString &path)
3203#ifdef THREADED_LOAD_CATALOG
3207 loadCatalogFromFile(path);
3210 m_LoadCatalogsWatcher->setFuture(m_LoadCatalogs);
3218 loadCatalogFromFile(path);
3223CatalogImageInfo::CatalogImageInfo(
const QString &csv)
3229 if (columns.
size() < 1 || columns[0].isEmpty())
3232 m_Name = columns[column++];
3233 if (columns.
size() <= column)
return;
3234 m_Filename = columns[column++];
3235 if (columns.
size() <= column)
return;
3236 m_Author = columns[column++];
3237 if (columns.
size() <= column)
return;
3238 m_Link = columns[column++];
3239 if (columns.
size() <= column)
return;
3240 m_License = columns[column++];
3259void ImagingPlanner::loadCatalogFromFile(
QString path,
bool reset)
3261 QFile inputFile(path);
3265 m_numMissingImage = 0;
3267 int numMissingImage = 0, numWithImage = 0;
3268 if (!inputFile.exists())
3270 emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
3276 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3283 Options::setImagingPlannerCatalogPath(path);
3284 Options::self()->save();
3285 if (m_CatalogModel->rowCount() > 0)
3286 m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
3292 CatalogImageInfo info(in.readLine().trimmed());
3293 if (info.m_Name.isEmpty())
3295 if (info.m_Name.startsWith(
"LoadCatalog"))
3300 auto match = re.match(info.m_Name);
3301 if (
match.hasMatch())
3304 if (catFilename.
isEmpty())
continue;
3307 QString catFullPath = catFilename;
3308 if (!info.isAbsolute())
3314 if (catFullPath != path)
3315 loadCatalogFromFile(catFullPath,
false);
3319 objectNames.
append(info.m_Name);
3320 if (!info.m_Filename.isEmpty())
3324 if (fInfo.isRelative())
3327 addCatalogImageInfo(info);
3332 DPRINTF(stderr,
"No catalog image for %s\n", info.m_Name.toLatin1().data());
3334#ifndef THREADED_LOAD_CATALOG
3340 int num = 0, numBad = 0, iteration = 0;
3342 for (
const auto &name : objectNames)
3344 setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
3345 if (addCatalogItem(ksal, name, 0)) num++;
3352 m_numWithImage += numWithImage;
3353 m_numMissingImage += numMissingImage;
3354 DPRINTF(stderr,
"Catalog %s: %d of %d have catalog images\n",
3363 emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
3367void ImagingPlanner::sorry(
const QString &message)
3369 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.
std::pair< bool, QString > add_object(const int catalog_id, const SkyObject::TYPE t, const CachingDms &r, const CachingDms &d, const QString &n, const float m=NaN::f, const QString &lname=QString(), const QString &catalog_identifier=QString(), const float a=0.0, const float b=0.0, const double pa=0.0, const float flux=0)
Add a CatalogObject to a table with `catalog_id`.
CatalogObjectList find_objects_by_name(const QString &name, const int limit=-1, const bool exactMatchOnly=false)
Find an objects by name.
std::pair< bool, CatalogObject > get_object(const CatalogObject::oid &oid)
Get an object by `oid`.
DetailDialog is a window showing detailed information for a selected object.
static QString processSearchText(QString searchText)
Do some post processing on the search text to interpret what the user meant This could include replac...
Represents a flag on the sky map.
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.
There are several time-dependent values used in position calculations, that are not specific to an ob...
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)
Child class of KSPlanetBase; encapsulates information about the Sun.
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 longname(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,...
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.
CompletionCondition
Conditions under which a SchedulerJob may complete.
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
const QList< QKeySequence > & end()
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 bool setData(const QModelIndex &index, const QVariant &value, int role)
qsizetype length() const const
QByteArray & remove(qsizetype pos, qsizetype len)
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)
virtual void resizeEvent(QResizeEvent *) override
QString absolutePath() const const
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
bool exists() const const
bool mkpath(const QString &dirPath) const const
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QString absolutePath() 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 selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
void append(QList< T > &&value)
void push_back(parameter_type value)
qsizetype size() const const
iterator find(const Key &key)
QVariant data(int role) const const
bool isValid() const const
QModelIndex siblingAtColumn(int column) const const
int globalX() const const
int globalY() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
bool disconnect(const QMetaObject::Connection &connection)
void installEventFilter(QObject *filterObj)
QObject * parent() const const
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
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
bool hasMatch() 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
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)
QFuture< T > run(Function function,...)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
bool isValid(int h, int m, int s, int ms)
QString toString(QStringView format) const const
bool isEmpty() const const
bool canConvert() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const