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())
989void ImagingPlanner::setupHideButtons(
bool(*option)(),
void(*setOption)(
bool),
999 Options::self()->save();
1008 Options::self()->save();
1016void ImagingPlanner::focusOnTable()
1021void ImagingPlanner::adjustWindowSize()
1023 const int keepWidth =
width();
1025 const int newHeight =
height();
1026 resize(keepWidth, newHeight);
1030void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox,
bool(*option)(),
void(*setOption)(
bool))
1036 Options::self()->save();
1037 m_CatalogSortModel->invalidate();
1039 ui->CatalogView->resizeColumnsToContents();
1045void ImagingPlanner::setupFilter2Buttons(
1047 bool(*yesOption)(),
bool(*noOption)(),
bool(*dontCareOption)(),
1048 void(*setYesOption)(
bool),
void(*setNoOption)(
bool),
void(*setDontCareOption)(
bool))
1054 setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1055 updateSortConstraints();
1056 m_CatalogSortModel->invalidate();
1057 ui->CatalogView->resizeColumnsToContents();
1063 setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1064 updateSortConstraints();
1065 m_CatalogSortModel->invalidate();
1066 ui->CatalogView->resizeColumnsToContents();
1070 connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
1072 setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1073 updateSortConstraints();
1074 m_CatalogSortModel->invalidate();
1075 ui->CatalogView->resizeColumnsToContents();
1086void ImagingPlanner::updateSortConstraints()
1088 m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
1089 ui->pickedCB->isChecked());
1090 m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
1091 ui->imagedCB->isChecked());
1092 m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
1093 ui->ignoredCB->isChecked());
1094 m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
1095 ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
1099void ImagingPlanner::initialize()
1101 if (KStarsData::Instance() ==
nullptr)
1108 connect(
this, &ImagingPlanner::popupSorry,
this, &ImagingPlanner::sorry);
1114 m_CatalogModel->setHorizontalHeaderLabels(
1117 m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
1118 i18n(
"Object Name--click header to sort ascending/descending."));
1119 m_CatalogModel->horizontalHeaderItem(
1120 HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
1121 m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
1122 i18n(
"Object Type--click header to sort ascending/descending."));
1123 m_CatalogModel->horizontalHeaderItem(
1124 SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
1125 m_CatalogModel->horizontalHeaderItem(
1126 ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
1127 m_CatalogModel->horizontalHeaderItem(
1128 MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
1129 m_CatalogModel->horizontalHeaderItem(
1130 CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
1131 m_CatalogModel->horizontalHeaderItem(
1132 COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
1134 m_CatalogSortModel =
new CatalogFilter(
this);
1136 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
1137 m_CatalogSortModel->setDynamicSortFilter(
true);
1139 ui->CatalogView->setModel(m_CatalogSortModel.
data());
1140 ui->CatalogView->setSortingEnabled(
false);
1141 ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
1142 ui->CatalogView->resizeColumnsToContents();
1143 ui->CatalogView->verticalHeader()->
setVisible(
false);
1144 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
1147 this, &ImagingPlanner::selectionChanged);
1152 auto utc = KStarsData::Instance()->
clock()->
utc();
1153 auto localTime = getGeo()->UTtoLT(utc);
1154 ui->DateEdit->setDate(localTime.date());
1160 setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
1161 ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
1162 ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
1169 QString selection = currentObjectName();
1173 scrollToName(selection);
1189 Options::setImagingPlannerHideAstrobinDetails(
true);
1190 setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
1191 ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
1192 ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
1193 ui->AstrobinAward->setChecked(Options::astrobinAward());
1196 Options::setAstrobinAward(checked);
1197 Options::self()->save();
1200 ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
1203 Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
1204 Options::self()->save();
1207 ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
1210 Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
1211 Options::self()->save();
1222 setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
1223 ui->hideImageButton, ui->showImageButton,
1224 ui->ImageFrame, ui->HiddenImageFrame);
1227 Options::setImagingPlannerHideFilters(
true);
1228 setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
1229 ui->hideFilterTypesButton, ui->showFilterTypesButton,
1230 ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
1231 setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
1232 &Options::setImagingPlannerAcceptOpenCluster);
1233 setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
1234 setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
1235 &Options::setImagingPlannerAcceptGlobularCluster);
1236 setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
1237 setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
1238 &Options::setImagingPlannerAcceptSupernovaRemnant);
1239 setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
1240 setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
1241 &Options::setImagingPlannerAcceptGalaxyCluster);
1242 setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
1243 setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
1245 setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
1246 &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
1247 &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
1249 setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
1250 &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
1251 &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
1253 setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
1254 &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
1255 &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
1256 &Options::setImagingPlannerDontCareIgnored);
1258 ui->keywordEdit->setText(Options::imagingPlannerKeyword());
1259 ui->keywordEdit->setAcceptRichText(
false);
1260 m_Keyword = Options::imagingPlannerKeyword();
1261 setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
1262 &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
1263 &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
1264 &Options::setImagingPlannerDontCareKeyword);
1269 ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
1270 m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
1271 ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
1272 m_MinMoon = Options::imagingPlannerMinMoonSeparation();
1273 ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
1274 m_MinAltitude = Options::imagingPlannerMinAltitude();
1275 ui->minHours->setValue(Options::imagingPlannerMinHours());
1276 m_MinHours = Options::imagingPlannerMinHours();
1277 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1280 if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
1282 m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
1283 Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
1284 Options::self()->save();
1290 if (m_MinMoon == ui->minMoon->value())
1292 m_MinMoon = ui->minMoon->value();
1293 Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
1294 Options::self()->save();
1300 if (m_MinAltitude == ui->minAltitude->value())
1302 m_MinAltitude = ui->minAltitude->value();
1303 Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
1304 Options::self()->save();
1310 if (m_MinHours == ui->minHours->value())
1312 m_MinHours = ui->minHours->value();
1313 Options::setImagingPlannerMinHours(ui->minHours->value());
1314 Options::self()->save();
1315 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1316 m_CatalogSortModel->invalidate();
1317 ui->CatalogView->resizeColumnsToContents();
1321 updateSortConstraints();
1323 m_CatalogSortModel->setMinHours(ui->minHours->value());
1325 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
1334 ui->userNotesLabel->setVisible(true);
1335 ui->userNotesEdit->setText(ui->userNotes->text());
1336 ui->userNotesEdit->setVisible(true);
1337 ui->userNotesEditButton->setVisible(false);
1338 ui->userNotesDoneButton->setVisible(true);
1339 ui->userNotes->setVisible(false);
1340 ui->userNotesLabel->setVisible(true);
1341 ui->userNotesOpenLink->setVisible(false);
1342 ui->userNotesOpenLink2->setVisible(false);
1343 ui->userNotesOpenLink3->setVisible(false);
1349 QString urlString = findUrl(ui->userNotes->text());
1350 if (urlString.isEmpty())
1352 QDesktopServices::openUrl(QUrl(urlString));
1357 QString urlString = findUrl(ui->userNotes->text(), 2);
1358 if (urlString.isEmpty())
1360 QDesktopServices::openUrl(QUrl(urlString));
1365 QString urlString = findUrl(ui->userNotes->text(), 3);
1366 if (urlString.isEmpty())
1368 QDesktopServices::openUrl(QUrl(urlString));
1377 m_CatalogSortModel->setSortColumn(column);
1378 m_CatalogSortModel->invalidate();
1379 ui->CatalogView->resizeColumnsToContents();
1388 qRegisterMetaType<QList<QStandardItem *>>(
"QList<QStandardItem *>");
1389 connect(
this, &ImagingPlanner::addRow,
this, &ImagingPlanner::addRowSlot);
1399 installEventFilters();
1402void ImagingPlanner::installEventFilters()
1416void ImagingPlanner::removeEventFilters()
1428void ImagingPlanner::openOptionsMenu()
1436void ImagingPlanner::getHelp()
1446 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/MESSIER", 300))
1447 fprintf(stderr,
"downsampling succeeded\n");
1449 fprintf(stderr,
"downsampling failed\n");
1451 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/OTHER", 300))
1452 fprintf(stderr,
"downsampling succeeded\n");
1454 fprintf(stderr,
"downsampling failed\n");
1456 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/CALDWELL", 300))
1457 fprintf(stderr,
"downsampling succeeded\n");
1459 fprintf(stderr,
"downsampling failed\n");
1461 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/AWARDS", 300))
1462 fprintf(stderr,
"downsampling succeeded\n");
1464 fprintf(stderr,
"downsampling failed\n");
1466 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/HERSCHEL12", 300))
1467 fprintf(stderr,
"downsampling succeeded\n");
1469 fprintf(stderr,
"downsampling failed\n");
1472 const QUrl url(
"https://docs.kde.org/trunk5/en/kstars/kstars/kstars.pdf#tool-imaging-planner");
1477KSMoon *ImagingPlanner::getMoon()
1479 if (KStarsData::Instance() ==
nullptr)
1485 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1488 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1490 moon->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1496void ImagingPlanner::updateMoon()
1498 KSMoon *moon = getMoon();
1503 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1505 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1508 sun->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1512 ui->moonPercentLabel->setText(
QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0,
'f', 0));
1515bool ImagingPlanner::scrollToName(
const QString &name)
1519 QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0),
Qt::EditRole,
1521 if(matchList.count() >= 1)
1524 for (
int i = 0; i < matchList.count(); i++)
1533 ui->CatalogView->scrollTo(matchList[bestIndex]);
1534 ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
1540void ImagingPlanner::searchSlot()
1542 if (m_loadingCatalog)
1544 QString origName = ui->SearchText->toPlainText().trimmed();
1546 ui->SearchText->setPlainText(name);
1550 if (!scrollToName(name))
1551 KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
1554 ui->SearchText->clear();
1555 ui->SearchText->setPlainText(
"");
1558void ImagingPlanner::initUserNotes()
1571void ImagingPlanner::disableUserNotes()
1583void ImagingPlanner::userNotesEditFinished()
1585 const QString ¬es = ui->userNotesEdit->toPlainText().trimmed();
1586 ui->userNotes->setText(notes);
1593 setCurrentObjectNotes(notes);
1594 setupNotesLinks(notes);
1596 auto o = currentCatalogObject();
1598 saveToDB(currentObjectName(), currentObjectFlags(), notes);
1601void ImagingPlanner::updateNotes(
const QString ¬es)
1605 ui->userNotes->setText(notes);
1607 setupNotesLinks(notes);
1610void ImagingPlanner::setupNotesLinks(
const QString ¬es)
1614 if (!
link.isEmpty())
1615 ui->userNotesOpenLink->
setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
1617 link = findUrl(notes, 2);
1619 if (!
link.isEmpty())
1620 ui->userNotesOpenLink2->
setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
1622 link = findUrl(notes, 3);
1624 if (!
link.isEmpty())
1625 ui->userNotesOpenLink3->
setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
1635 std::list<CatalogObject> objs =
1653 if (objs.size() == 0)
1655 if (objs.size() == 0)
1669 m_manager.
add_object(CatalogsDB::user_catalog_id, cedata.second);
1670 const auto &added_object =
1671 m_manager.
get_object(cedata.second.getId(), CatalogsDB::user_catalog_id);
1674 if (added_object.first)
1676 *catObject = KStarsData::Instance()
1678 ->catalogsComponent()
1681 DPRINTF(stderr,
"***** Found %s using name resolver (%.1fs)\n",
name.
toLatin1().
data(),
1682 timer.elapsed() / 1000.0);
1687 if (objs.size() == 0)
1691 *catObject = objs.front();
1692 if (objs.size() > 1)
1694 QString addSpace = filteredName;
1696 for (
const auto &obj : objs)
1716 auto o = m_CatalogHash.
find(lName);
1717 if (o == m_CatalogHash.
end())
1722void ImagingPlanner::clearObjects()
1728 m_CatalogHash.
clear();
1736 if (getObject(lName) !=
nullptr)
1738 DPRINTF(stderr,
"Didn't add \"%s\" because it's already there\n",
name.
toLatin1().
data());
1743 if (!getKStarsCatalogObject(lName, &o))
1745 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
1748 m_CatalogHash[lName] = o;
1749 return &(m_CatalogHash[lName]);
1754bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal,
const QString &name,
int flags)
1757 if (
object ==
nullptr)
1770 for (
int i = 0; i < LAST_COLUMN; ++i)
1772 if (i == NAME_COLUMN)
1774 itemList.
append(getItemWithUserRole(name));
1776 else if (i == HOURS_COLUMN)
1778 double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
1779 ui->useArtificialHorizon->isChecked());
1780 auto hoursItem = getItemWithUserRole(
QString(
"%1").arg(runHours, 0,
'f', 1));
1781 hoursItem->setData(runHours, HOURS_ROLE);
1782 itemList.
append(hoursItem);
1784 else if (i == TYPE_COLUMN)
1786 auto typeItem = getItemWithUserRole(
QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
1787 typeItem->setData(object->
type(), TYPE_ROLE);
1788 itemList.
append(typeItem);
1790 else if (i == SIZE_COLUMN)
1792 double size = std::max(object->
a(), object->
b());
1793 auto sizeItem = getItemWithUserRole(
QString(
"%1'").arg(
size, 0,
'f', 1));
1794 sizeItem->setData(
size, SIZE_ROLE);
1795 itemList.
append(sizeItem);
1797 else if (i == ALTITUDE_COLUMN)
1800 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
1801 auto altItem = getItemWithUserRole(
QString(
"%1º").arg(altitude, 0,
'f', 0));
1802 altItem->setData(altitude, ALTITUDE_ROLE);
1803 itemList.
append(altItem);
1805 else if (i == MOON_COLUMN)
1807 KSMoon *moon = getMoon();
1813 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1820 auto moonItem = getItemWithUserRole(
QString(
"%1º").arg(separation, 0,
'f', 0));
1821 moonItem->setData(separation, MOON_ROLE);
1822 itemList.
append(moonItem);
1826 auto moonItem = getItemWithUserRole(
QString(
""));
1827 moonItem->setData(-1, MOON_ROLE);
1830 else if (i == CONSTELLATION_COLUMN)
1832 QString cname = KStarsData::Instance()
1834 ->constellationBoundary()
1835 ->constellationName(
object);
1837 auto constellationItem = getItemWithUserRole(cname);
1838 itemList.
append(constellationItem);
1840 else if (i == COORD_COLUMN)
1842 itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
1844 else if (i == FLAGS_COLUMN)
1847 flag->
setData(flags, FLAGS_ROLE);
1850 else if (i == NOTES_COLUMN)
1858 DPRINTF(stderr,
"Bug in addCatalogItem() !\n");
1863 emit addRow(itemList);
1869 m_CatalogModel->appendRow(itemList);
1873void ImagingPlanner::recompute()
1875 setStatus(
i18n(
"Updating tables..."));
1878 m_CatalogSortModel->setSourceModel(
nullptr);
1883 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1888 for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
1890 const QString &
name = m_CatalogModel->item(i, 0)->text();
1892 if (catalogEntry ==
nullptr)
1894 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n",
name.
toLatin1().
data());
1897 double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
1898 ui->minMoon->value(), ui->useArtificialHorizon->isChecked());
1903 hItem->
setData(runHours, HOURS_ROLE);
1904 m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
1908 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
1912 altItem->setData(altitude, ALTITUDE_ROLE);
1913 m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
1915 KSMoon *moon = getMoon();
1921 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1931 moonItem->setData(separation, MOON_ROLE);
1932 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1938 moonItem->setData(-1, MOON_ROLE);
1939 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1943 const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
1945 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
1946 const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
1948 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
1951 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
1953 DPRINTF(stderr,
"Recompute took %.1fs\n", timer.elapsed() / 1000.0);
1960void ImagingPlanner::checkTargets()
1964 fprintf(stderr,
"****************** check objects (%d)***************\n", flags->
size());
1965 for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
1966 fprintf(stderr,
"Removed, now %d\n", flags->
size());
1968 int rows = m_CatalogModel->rowCount();
1972 for (
int i = 0; i < rows; ++i)
1974 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
1976 accepted[i] = getObject(name) !=
nullptr;
1978 auto object = getObject(name);
1982 fprintf(stderr,
"%d ", i);
1986 for (
int i = 0; i < targets.
size(); ++i)
1992 object->setRA(object->
ra0());
1993 object->setDec(object->
dec0());
1994 for (
int j = 0; j < targets.
size(); ++j)
1996 if (i == j)
continue;
1998 auto name2 = targets[j];
1999 auto object2 = getObject(name2);
2000 object2->setRA(object2->ra0());
2001 object2->setDec(object2->dec0());
2002 const dms dist =
object->angularDistanceTo(object2);
2003 const double arcsecDist = dist.
Degrees() * 3600.0;
2004 if (arcsecDist < 120)
2006 fprintf(stderr,
"dist %10s (%s %s) to %10s (%s %s) = %.0f\" %s\n",
2008 object->
ra().toHMSString().toLatin1().data(),
2009 object->
dec().toDMSString().toLatin1().data(),
2011 object2->ra().toHMSString().toLatin1().data(),
2012 object2->dec().toDMSString().toLatin1().data(),
2019 fprintf(stderr,
"Done\n");
2026QString ImagingPlanner::defaultDirectory()
const
2034QString ImagingPlanner::findDefaultCatalog()
const
2038 for (
int i = 0; i < subDirs.size(); i++)
2041 const QDir subDir(subDirs[i].absoluteFilePath());
2044 if (files.size() > 0)
2049 for (
const auto &file : files)
2052 firstFile = file.absoluteFilePath();
2054 return file.absoluteFilePath();
2063void ImagingPlanner::loadInitialCatalog()
2065 QString catalog = Options::imagingPlannerCatalogPath();
2067 catalog = findDefaultCatalog();
2070 KSNotification::sorry(
i18n(
"You need to load a catalog to start using this tool.\nSee Data -> Download New Data..."));
2071 setStatus(
i18n(
"No Catalog!"));
2074 loadCatalog(catalog);
2077void ImagingPlanner::setStatus(
const QString &message)
2079 ui->statusLabel->setText(message);
2082void ImagingPlanner::catalogLoaded()
2084 DPRINTF(stderr,
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
2090 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
2091 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
2093 m_CatalogSortModel->invalidate();
2095 ui->CatalogView->resizeColumnsToContents();
2098 auto index = ui->CatalogView->model()->index(0, 0);
2100 ui->CatalogView->selectionModel()->select(index,
2109void ImagingPlanner::updateStatus()
2111 if (currentObjectName().isEmpty())
2113 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2114 const int totalCatalogObjects = m_CatalogModel->rowCount();
2116 if (numDisplayedObjects > 0)
2117 setStatus(
i18n(
"Select an object."));
2118 else if (totalCatalogObjects > 0)
2119 setStatus(
i18n(
"Check Filters to unhide objects."));
2121 setStatus(
i18n(
"Load a Catalog."));
2131 if (m_initialShow ==
false)
2133 m_initialShow =
true;
2141void ImagingPlanner::slotClose()
2147QUrl ImagingPlanner::getAstrobinUrl(
const QString &target,
bool requireAwards,
bool requireSomeFilters,
double minRadius,
2150 QString myQuery =
QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").
arg(target);
2153 auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
2154 QDate today = localTime.date();
2155 myQuery.
append(
QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
2158 myQuery.
append(
QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
2160 if (requireSomeFilters)
2161 myQuery.
append(
QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
2163 if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
2164 myQuery.
append(
QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
2175 replaceByteArrayChars(b64,
'+',
QByteArray(
"%2B"));
2176 replaceByteArrayChars(b64,
'=',
QByteArray(
"%3D"));
2177 replaceByteArrayChars(b,
'"',
QByteArray(
"%22"));
2178 replaceByteArrayChars(b,
':',
QByteArray(
"%3A"));
2179 replaceByteArrayChars(b,
'[',
QByteArray(
"%5B"));
2180 replaceByteArrayChars(b,
']',
QByteArray(
"%5D"));
2181 replaceByteArrayChars(b,
',',
QByteArray(
"%2C"));
2182 replaceByteArrayChars(b,
'\'',
QByteArray(
"%27"));
2183 replaceByteArrayChars(b,
'{',
QByteArray(
"%7B"));
2184 replaceByteArrayChars(b,
'}',
QByteArray(
"%7D"));
2190void ImagingPlanner::popupAstrobin(
const QString &target)
2192 QString newStr = massageObjectName(target);
2195 const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(),
false, Options::astrobinMinRadius(),
2196 Options::astrobinMaxRadius());
2202void ImagingPlanner::searchNGCICImages()
2205 auto o = currentCatalogObject();
2208 fprintf(stderr,
"NULL object sent to searchNGCICImages.\n");
2214 num = o->name().mid(3).toInt();
2215 QString urlString =
QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3").
arg(num / 100).
arg(
2216 num % 100 < 50 ?
"" :
"a").
arg(num);
2222 num = o->name().mid(2).toInt();
2223 QString urlString =
QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3").
arg(num / 100).
arg(
2224 num % 100 < 50 ?
"" :
"a").
arg(num);
2230void ImagingPlanner::searchSimbad()
2242 QString urlStr =
QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1"
2243 "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
2249void ImagingPlanner::searchWikipedia()
2252 QString wikipediaAddress =
"https://en.wikipedia.org";
2256 fprintf(stderr,
"NULL object sent to Wikipedia.\n");
2274 .
arg(wikipediaAddress).
arg(massageObjectName(name));
2278 QUrl(
QString(
"%1/wiki/%2").arg(wikipediaAddress).arg(massagedName)));
2281void ImagingPlanner::searchAstrobin()
2287 popupAstrobin(name);
2290bool ImagingPlanner::eventFilter(
QObject * obj,
QEvent * event)
2292 if (m_loadingCatalog)
2297 m_InitialLoad =
false;
2299 setStatus(
i18n(
"Loading Catalogs..."));
2300 loadInitialCatalog();
2306 if ((obj == ui->CatalogView->viewport()) &&
2311 int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
2313 for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
2315 selectedNames.
append(r.siblingAtColumn(0).
data().toString());
2316 bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
2317 if (isPicked) numPicked++;
2318 else numNotPicked++;
2319 bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
2320 if (isImaged) numImaged++;
2321 else numNotImaged++;
2322 bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
2323 if (isIgnored) numIgnored++;
2324 else numNotIgnored++;
2327 if (selectedNames.
size() == 0)
2331 m_PopupMenu =
new ImagingPlannerPopup;
2333 const bool imaged = numImaged > 0;
2334 const bool picked = numPicked > 0;
2335 const bool ignored = numIgnored > 0;
2336 m_PopupMenu->init(
this, selectedNames,
2337 (numImaged > 0 && numNotImaged > 0) ?
nullptr : &imaged,
2338 (numPicked > 0 && numNotPicked > 0) ?
nullptr : &picked,
2339 (numIgnored > 0 && numNotIgnored > 0) ?
nullptr : &ignored);
2341 m_PopupMenu->popup(
pos);
2345 userNotesEditFinished();
2348 keywordEditFinished();
2359 keywordEditFinished();
2383 else if ((obj == ui->ImagePreview ||
2384 obj == ui->ImagePreviewCredit ||
2385 obj == ui->ImagePreviewCreditLink) &&
2388 if (!ui->ImagePreviewCreditLink->text().isEmpty())
2390 QUrl url(ui->ImagePreviewCreditLink->text());
2398void ImagingPlanner::keywordEditFinished()
2400 QString kwd = ui->keywordEdit->toPlainText().trimmed();
2401 ui->keywordEdit->clear();
2402 ui->keywordEdit->setText(kwd);
2403 if (m_Keyword != kwd)
2406 Options::setImagingPlannerKeyword(kwd);
2407 Options::self()->save();
2408 updateSortConstraints();
2409 m_CatalogSortModel->invalidate();
2410 ui->CatalogView->resizeColumnsToContents();
2415void ImagingPlanner::setDefaultImage()
2417 ui->ImagePreview->setPixmap(m_NoImagePixmap);
2418 ui->ImagePreview->
update();
2419 ui->ImagePreviewCredit->setText(
"");
2420 ui->ImagePreviewCreditLink->setText(
"");
2425 if (m_loadingCatalog)
2428 Q_UNUSED(deselected);
2429 if (selected.
indexes().size() == 0)
2437 auto selection = selected.
indexes()[0];
2440 if (
object ==
nullptr)
2447 ui->ImagePreviewCredit->setText(
"");
2448 ui->ImagePreviewCreditLink->setText(
"");
2451 CatalogImageInfo catalogImageInfo;
2452 if (findCatalogImageInfo(name, &catalogImageInfo))
2454 QString filename = catalogImageInfo.m_Filename;
2455 if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
2457 QString imageFullPath = filename;
2461 imageFullPath =
QString(
"%1%2%3").
arg(catDir)
2464 if (!
QFile(imageFullPath).exists())
2465 DPRINTF(stderr,
"Image for \"%s\" -- \"%s\" doesn't exist\n",
2469 if (!catalogImageInfo.m_Link.
isEmpty())
2471 ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
2472 ui->ImagePreview->
setToolTip(
"Click to see original");
2473 ui->ImagePreviewCreditLink->
setToolTip(
"Click to see original");
2477 ui->ImagePreviewCreditLink->setText(
"");
2482 if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
2484 ui->ImagePreviewCredit->setText(
2485 QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
2486 .
arg(creativeCommonsString(catalogImageInfo.m_License)));
2488 QString(
"Original image license: %1")
2489 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2491 else if (!catalogImageInfo.m_Author.
isEmpty())
2493 ui->ImagePreviewCredit->setText(
2494 QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
2497 else if (!catalogImageInfo.m_License.
isEmpty())
2499 ui->ImagePreviewCredit->setText(
2500 QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
2502 QString(
"Original image license: %1")
2503 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2507 ui->ImagePreviewCredit->setText(
"");
2514 object->load_image();
2515 auto image =
object->image();
2521 const QString foundFilename = findObjectImage(name);
2524 constexpr int thumbHeight = 300, thumbWidth = 400;
2526 const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
2528 ui->ImagePreview->setPixmap(
2542void ImagingPlanner::updateDisplays()
2547 if (!currentCatalogObject())
2549 if (ui->CatalogView->model()->rowCount() > 0)
2551 auto index = ui->CatalogView->model()->index(0, 0);
2552 ui->CatalogView->selectionModel()->select(index,
2557 auto object = currentCatalogObject();
2560 updateDetails(*
object, currentObjectFlags());
2561 updateNotes(currentObjectNotes());
2562 plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
2569void ImagingPlanner::updateDetails(
const CatalogObject &
object,
int flags)
2571 ui->infoObjectName->setText(
object.
name());
2572 ui->infoSize->setText(
QString(
"%1' x %2'").arg(
object.a(), 0,
'f', 1).arg(
object.b(), 0,
'f', 1));
2578 if (
object.longname().isEmpty() || (
object.longname() ==
object.
name()))
2579 ui->infoObjectLongName->clear();
2581 ui->infoObjectLongName->setText(
QString(
"(%1)").arg(
object.longname()));
2586 QTime riseTime =
object.riseSetTime(noon, getGeo(),
true);
2587 QTime setTime =
object.riseSetTime(noon, getGeo(),
false);
2588 QTime transitTime =
object.transitTime(noon, getGeo());
2589 dms transitAltitude =
object.transitAltitude(noon, getGeo());
2592 KSMoon *moon = getMoon();
2595 const double separation = ui->CatalogView->selectionModel()->currentIndex()
2596 .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
2598 if (separation >= 0)
2599 moonString =
QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0,
'f', 1);
2604 riseSetString =
QString(
"%1 %2 @ %3º")
2609 riseSetString =
QString(
"%1 %2")
2613 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2620 riseSetString =
QString(
"%1 %2")
2624 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2631 riseSetString =
QString(
"%1 %2 %3 %4")
2637 riseSetString =
QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
2645 if (moonString.
size() > 0)
2647 ui->infoRiseSet->setText(riseSetString);
2652 ui->infoObjectFlags->setText(flagString(flags));
2661void ImagingPlanner::plotAltitudeGraph(
const QDate &date,
const dms &ra,
const dms &dec)
2663 auto altitudeGraph = ui->altitudeGraph;
2664 altitudeGraph->setAltitudeAxis(-20.0, 90.0);
2668 getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked(),
2669 &jobStartTimes, &jobEndTimes);
2671 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
2677 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
2679 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
2682 Ekos::SchedulerJob job;
2683 setupJob(job,
"temp", ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked());
2691 plotStart = plotStart.
addSecs(-1 * 3600);
2694 auto plotEnd = dawn.
addSecs(1 * 3600);
2697 while (t.secsTo(plotEnd) > 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);
2707 altitudeGraph->plot(getGeo(), &ksal, times, alts,
false);
2709 for (
int i = 0; i < jobStartTimes.
size(); ++i)
2711 auto startTime = jobStartTimes[i];
2712 auto stopTime = jobEndTimes[i];
2713 if (startTime < plotStart) startTime = plotStart;
2714 if (stopTime > plotEnd) stopTime = plotEnd;
2717 stopTime.setTimeZone(tz);
2724 while (t.secsTo(stopTime) > 0)
2726 SkyPoint coords = job.getTargetCoords();
2727 double alt = getAltitude(getGeo(), coords, t);
2729 double hour = midnight.
secsTo(t) / 3600.0;
2731 t = t.addSecs(60 * 10);
2733 altitudeGraph->plot(getGeo(), &ksal, runTimes, runAlts,
true);
2737void ImagingPlanner::updateCounts()
2739 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2740 const int totalCatalogObjects = m_CatalogModel->rowCount();
2741 if (numDisplayedObjects == 1)
2742 ui->tableCount->setText(
QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
2744 ui->tableCount->setText(
QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
2747void ImagingPlanner::moveBackOneDay()
2750 QString selection = currentObjectName();
2751 ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
2755 scrollToName(selection);
2758void ImagingPlanner::moveForwardOneDay()
2760 QString selection = currentObjectName();
2761 ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
2765 scrollToName(selection);
2768QString ImagingPlanner::currentObjectName()
const
2770 QString name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).data(
2778 return getObject(name);
2783void ImagingPlanner::objectDetails()
2786 if (current ==
nullptr)
2788 auto ut = KStarsData::Instance()->
ut();
2796void ImagingPlanner::centerOnSkymap()
2798 if (!Options::imagingPlannerCenterOnSkyMap())
2800 reallyCenterOnSkymap();
2803void ImagingPlanner::reallyCenterOnSkymap()
2806 if (current ==
nullptr)
2810 if (current->
ra().Degrees() == 0 && current->
dec().Degrees() == 0)
2812 DPRINTF(stderr,
"found a 0,0 object\n");
2818 dms lst = getGeo()->GSTtoLST(time.
gst());
2823 bool keepGround = Options::showGround();
2824 bool keepAnimatedSlew = Options::useAnimatedSlewing();
2825 Options::setShowGround(
false);
2826 Options::setUseAnimatedSlewing(
false);
2832 Options::setShowGround(keepGround);
2833 Options::setUseAnimatedSlewing(keepAnimatedSlew);
2836void ImagingPlanner::setSelection(
int flag,
bool enabled)
2838 auto rows = ui->CatalogView->selectionModel()->selectedRows();
2848 for (
int i = 0; i < rows.size(); ++i)
2850 auto proxyIndex = rows[i].siblingAtColumn(FLAGS_COLUMN);
2851 auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
2852 sourceIndeces.
append(sourceIndex);
2855 for (
int i = 0; i < sourceIndeces.
size(); ++i)
2857 auto &sourceIndex = sourceIndeces[i];
2861 setFlag(sourceIndex, flag, m_CatalogModel.
data());
2863 clearFlag(sourceIndex, flag, m_CatalogModel.
data());
2865 QString name = m_CatalogModel->data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
2866 int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
2867 QString notes = m_CatalogModel->data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
2868 saveToDB(name, flags, notes);
2870 if (flag == IMAGED_BIT)
2871 highlightImagedObject(sourceIndex,
enabled);
2872 if (flag == PICKED_BIT)
2873 highlightPickedObject(sourceIndex,
enabled);
2878void ImagingPlanner::highlightImagedObject(
const QModelIndex &index,
bool imaged)
2881 QColor m_DefaultCellBackground(36, 35, 35);
2882 QColor m_ImagedObjectBackground(10, 65, 10);
2884 if (themeName ==
"High Key" || themeName ==
"Default" || themeName ==
"White Balance")
2886 m_DefaultCellBackground =
QColor(240, 240, 240);
2887 m_ImagedObjectBackground =
QColor(180, 240, 180);
2889 for (
int col = 0; col < LAST_COLUMN; ++col)
2892 m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground,
Qt::BackgroundRole);
2896void ImagingPlanner::highlightPickedObject(
const QModelIndex &index,
bool picked)
2898 for (
int col = 0; col < LAST_COLUMN; ++col)
2902 auto ff = qvariant_cast<QFont>(
font);
2904 ff.setItalic(picked);
2905 ff.setUnderline(picked);
2911void ImagingPlanner::setSelectionPicked()
2913 setSelection(PICKED_BIT,
true);
2916void ImagingPlanner::setSelectionNotPicked()
2918 setSelection(PICKED_BIT,
false);
2921void ImagingPlanner::setSelectionImaged()
2923 setSelection(IMAGED_BIT,
true);
2926void ImagingPlanner::setSelectionNotImaged()
2928 setSelection(IMAGED_BIT,
false);
2931void ImagingPlanner::setSelectionIgnored()
2933 setSelection(IGNORED_BIT,
true);
2936void ImagingPlanner::setSelectionNotIgnored()
2938 setSelection(IGNORED_BIT,
false);
2941int ImagingPlanner::currentObjectFlags()
2943 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(FLAGS_COLUMN);
2944 const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
2947 return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
2950QString ImagingPlanner::currentObjectNotes()
2952 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NOTES_COLUMN);
2953 const bool hasNotes = ui->CatalogView->model()->data(index, NOTES_ROLE).canConvert<
QString>();
2956 return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
2959void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
2961 auto index = ui->CatalogView->selectionModel()->currentIndex();
2966 auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
2968 m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
2971ImagingPlannerPopup::ImagingPlannerPopup() :
QMenu(nullptr)
2980void ImagingPlannerPopup::init(ImagingPlanner * planner,
const QStringList &names,
2981 const bool * imaged,
const bool * picked,
const bool * ignored)
2984 if (names.
size() == 0)
return;
2987 if (names.
size() == 1)
2989 else if (names.
size() <= 3)
2992 for (
int i = 1; i < names.
size(); i++)
2996 title =
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
3002 if (imaged ==
nullptr)
3004 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3005 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3008 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3010 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3012 if (picked ==
nullptr)
3014 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3015 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3018 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3020 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3023 if (ignored ==
nullptr)
3025 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3026 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3030 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3032 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3035 addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
3039ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
bool picked,
bool imaged,
3040 bool ignored,
const QString ¬es) : m_Name(
name), m_Notes(notes)
3045ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
int flags,
const QString ¬es)
3046 : m_Name(
name), m_Flags(flags), m_Notes(notes)
3050void ImagingPlannerDBEntry::getFlags(
bool * picked,
bool * imaged,
bool * ignored)
3052 *picked = m_Flags & PickedBit;
3053 *imaged = m_Flags & ImagedBit;
3054 *ignored = m_Flags & IgnoredBit;
3058void ImagingPlannerDBEntry::setFlags(
bool picked,
bool imaged,
bool ignored)
3061 if (picked) m_Flags |= PickedBit;
3062 if (imaged) m_Flags |= ImagedBit;
3063 if (ignored) m_Flags |= IgnoredBit;
3066void ImagingPlanner::saveToDB(
const QString &name,
bool picked,
bool imaged,
3067 bool ignored,
const QString ¬es)
3069 ImagingPlannerDBEntry e(name, 0, notes);
3070 e.setFlags(picked, imaged, ignored);
3074void ImagingPlanner::saveToDB(
const QString &name,
int flags,
const QString ¬es)
3076 ImagingPlannerDBEntry e(name, flags, notes);
3081void ImagingPlanner::loadFromDB()
3086 m_CatalogSortModel->setSourceModel(
nullptr);
3088 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3097 for (
const auto &entry : list)
3099 dbData[entry.m_Name] = entry;
3102 int rows = m_CatalogModel->rowCount();
3103 for (
int i = 0; i < rows; ++i)
3105 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
3106 auto entry = dbData.
find(name);
3107 if (entry != dbData.
end())
3110 m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
3111 if (entry->m_Flags & IMAGED_BIT)
3112 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3113 if (entry->m_Flags & PICKED_BIT)
3114 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3116 m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
3120 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
3123void ImagingPlanner::loadImagedFile()
3125 if (m_loadingCatalog)
3133 QFile inputFile(fileName);
3144 name = tweakNames(name);
3145 if (getObject(name))
3148 auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
3151 if (matches.size() > 0)
3153 setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
3154 highlightImagedObject(matches[0],
true);
3157 QString name = m_CatalogModel->data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
3158 int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3159 QString notes = m_CatalogModel->data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
3160 saveToDB(name, flags, notes);
3164 DPRINTF(stderr,
"ooops! internal inconsitency--got an object but match didn't work");
3168 failedNames.
append(name);
3171 if (failedNames.
size() == 0)
3174 KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
3176 KSNotification::sorry(
i18n(
"Empty file"));
3180 int num = std::min((
int)failedNames.
size(), 10);
3182 for (
int i = 1; i < num; ++i)
3184 if (numSuccess == 0 && failedNames.
size() <= 10)
3185 KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
3186 else if (numSuccess == 0)
3187 KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
3188 else if (numSuccess > 0 && failedNames.
size() <= 10)
3189 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
3190 numSuccess, failedNames.
size() == 1 ?
"this" :
"these", sample));
3192 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
3193 numSuccess, failedNames.
size(), sample));
3198 KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
3202void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
3204 m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
3207bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo *info)
3210 if (
result == m_CatalogImageInfoMap.
end())
3212 if (
result->m_Filename.isEmpty())
3218void ImagingPlanner::loadCatalogViaMenu()
3220 QString startDir = Options::imagingPlannerCatalogPath();
3222 startDir = defaultDirectory();
3231void ImagingPlanner::loadCatalog(
const QString &path)
3233#ifdef THREADED_LOAD_CATALOG
3237 loadCatalogFromFile(path);
3240 m_LoadCatalogsWatcher->setFuture(m_LoadCatalogs);
3248 removeEventFilters();
3249 m_loadingCatalog =
true;
3250 loadCatalogFromFile(path);
3252 m_loadingCatalog =
false;
3253 installEventFilters();
3257CatalogImageInfo::CatalogImageInfo(
const QString &csv)
3263 if (columns.
size() < 1 || columns[0].isEmpty())
3266 m_Name = columns[column++];
3267 if (columns.
size() <= column)
return;
3268 m_Filename = columns[column++];
3269 if (columns.
size() <= column)
return;
3270 m_Author = columns[column++];
3271 if (columns.
size() <= column)
return;
3272 m_Link = columns[column++];
3273 if (columns.
size() <= column)
return;
3274 m_License = columns[column++];
3293void ImagingPlanner::loadCatalogFromFile(
QString path,
bool reset)
3295 QFile inputFile(path);
3299 m_numMissingImage = 0;
3301 int numMissingImage = 0, numWithImage = 0;
3302 if (!inputFile.exists())
3304 emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
3310 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3317 Options::setImagingPlannerCatalogPath(path);
3318 Options::self()->save();
3319 if (m_CatalogModel->rowCount() > 0)
3320 m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
3326 CatalogImageInfo info(in.readLine().trimmed());
3327 if (info.m_Name.isEmpty())
3329 if (info.m_Name.startsWith(
"LoadCatalog"))
3334 auto match = re.match(info.m_Name);
3335 if (
match.hasMatch())
3338 if (catFilename.
isEmpty())
continue;
3341 QString catFullPath = catFilename;
3342 if (!info.isAbsolute())
3348 if (catFullPath != path)
3349 loadCatalogFromFile(catFullPath,
false);
3353 objectNames.
append(info.m_Name);
3354 if (!info.m_Filename.isEmpty())
3358 if (fInfo.isRelative())
3361 addCatalogImageInfo(info);
3366 DPRINTF(stderr,
"No catalog image for %s\n", info.m_Name.toLatin1().data());
3368#ifndef THREADED_LOAD_CATALOG
3374 int num = 0, numBad = 0, iteration = 0;
3376 for (
const auto &name : objectNames)
3378 setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
3379 if (addCatalogItem(ksal, name, 0)) num++;
3386 m_numWithImage += numWithImage;
3387 m_numMissingImage += numMissingImage;
3388 DPRINTF(stderr,
"Catalog %s: %d of %d have catalog images\n",
3397 emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
3401void ImagingPlanner::sorry(
const QString &message)
3403 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()
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 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)
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
void removeEventFilter(QObject *obj)
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