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
121 case SkyObject::OPEN_CLUSTER:
122 return Options::imagingPlannerAcceptOpenCluster();
123 case SkyObject::GLOBULAR_CLUSTER:
124 return Options::imagingPlannerAcceptGlobularCluster();
125 case SkyObject::GASEOUS_NEBULA:
126 return Options::imagingPlannerAcceptNebula();
127 case SkyObject::PLANETARY_NEBULA:
128 return Options::imagingPlannerAcceptPlanetary();
129 case SkyObject::SUPERNOVA_REMNANT:
130 return Options::imagingPlannerAcceptSupernovaRemnant();
131 case SkyObject::GALAXY:
132 return Options::imagingPlannerAcceptGalaxy();
133 case SkyObject::GALAXY_CLUSTER:
134 return Options::imagingPlannerAcceptGalaxyCluster();
135 case SkyObject::DARK_NEBULA:
136 return Options::imagingPlannerAcceptDarkNebula();
138 return Options::imagingPlannerAcceptOther();
145 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
148 const bool flag = model->
data(idx, FLAGS_ROLE).
toInt() & bit;
155 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
156 int currentFlags = 0;
158 currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
160 model->
setData(idx, val, FLAGS_ROLE);
166 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
169 const int currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
171 model->
setData(idx, val, FLAGS_ROLE);
177 if (flags & IMAGED_BIT) str.
append(
i18n(
"Imaged"));
178 if (flags & PICKED_BIT)
184 if (flags & IGNORED_BIT)
194void setupShowCallback(
bool checked,
195 void (*showOption)(
bool),
void (*showNotOption)(
bool),
196 void (*dontCareOption)(
bool),
200 Q_UNUSED(showCheckbox);
204 showNotOption(
false);
205 dontCareOption(
false);
208 Options::self()->save();
213 showNotOption(
false);
214 dontCareOption(
true);
217 Options::self()->save();
221void setupShowNotCallback(
bool checked,
222 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
225 Q_UNUSED(showNotCheckbox);
230 dontCareOption(
false);
233 Options::self()->save();
238 showNotOption(
false);
239 dontCareOption(
true);
242 Options::self()->save();
246void setupDontCareCallback(
bool checked,
247 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
253 showNotOption(
false);
254 dontCareOption(
true);
257 Options::self()->save();
264 showNotOption(
false);
265 dontCareOption(
true);
269 Options::self()->save();
278 "\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
283 auto match = re.match(input);
284 if (!
match.hasMatch())
287 return(
match.captured(0));
293 match = re.match(inp);
294 if (!
match.hasMatch())
297 return (
match.captured(0));
323 int column,
int role)
325 const double l =
left.siblingAtColumn(column).data(role).toDouble();
326 const double r =
right.siblingAtColumn(column).data(role).toDouble();
336 const QString l =
left.siblingAtColumn(column).data(role).toString();
337 const QString r =
right.siblingAtColumn(column).data(role).toString();
341 if (lList.
size() == 0 || rList.
size() == 0)
352 if (lList.
size() >= 2 && rList.
size() >= 2)
354 int lInt = lList[1].toInt();
355 int rInt = rList[1].toInt();
358 if (lInt > 0 && rInt > 0)
359 return -(lInt - rInt);
367void SchedulerUtils_setupJob(Ekos::SchedulerJob &job,
const QString &name,
bool isLead,
const QString &group,
368 const QString &train,
const dms &ra,
const dms &dec,
double djd,
double rotation,
const QUrl &sequenceUrl,
370 const QDateTime &completionTime,
int completionRepeats,
double minimumAltitude,
double minimumMoonSeparation,
371 bool enforceWeather,
bool enforceTwilight,
bool enforceArtificialHorizon,
bool track,
bool focus,
bool align,
bool guide)
375 job.setIsLead(isLead);
376 job.setOpticalTrain(train);
377 job.setPositionAngle(rotation);
383 job.setLeadJob(
nullptr);
385 job.setTargetCoords(ra, dec, djd);
386 job.setFITSFile(fitsUrl);
389 job.setStartupCondition(startup);
390 if (startup == Ekos::START_AT)
392 job.setStartupTime(startupTime);
395 job.setFileStartupCondition(job.getStartupCondition());
396 job.setStartAtTime(job.getStartupTime());
400 job.setMinAltitude(minimumAltitude);
401 job.setMinMoonSeparation(minimumMoonSeparation);
404 job.setEnforceWeather(enforceWeather);
406 job.setEnforceTwilight(enforceTwilight);
407 job.setEnforceArtificialHorizon(enforceArtificialHorizon);
410 job.setStepPipeline(Ekos::SchedulerJob::USE_NONE);
412 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_TRACK));
414 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_FOCUS));
416 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_ALIGN));
418 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_GUIDE));
421 job.setFileStartupCondition(job.getStartupCondition());
422 job.setStartAtTime(job.getStartupTime());
427 job.setSequenceFile(sequenceUrl);
428 job.setCompletionCondition(completion);
429 if (completion == Ekos::FINISH_AT)
430 job.setFinishAtTime(completionTime);
431 else if (completion == Ekos::FINISH_REPEAT)
433 job.setRepeatsRequired(completionRepeats);
434 job.setRepeatsRemaining(completionRepeats);
442void setupJob(Ekos::SchedulerJob &job,
const QString name,
double minAltitude,
double minMoonSeparation,
dms ra,
dms dec,
443 bool useArtificialHorizon)
446 double rotation = 0.0;
452 SchedulerUtils_setupJob(job, name,
true,
"",
454 rotation, sequenceURL,
QUrl(),
457 minAltitude, minMoonSeparation,
458 false,
true, useArtificialHorizon,
459 true,
true,
true,
true);
463void getRunTimes(
const QDate &date,
const GeoLocation &geo,
double minAltitude,
double minMoonSeparation,
467 jobStartTimes->
clear();
468 jobEndTimes->
clear();
469 constexpr int SCHEDULE_RESOLUTION_MINUTES = 10;
470 Ekos::SchedulerJob job;
471 setupJob(job,
"temp", minAltitude, minMoonSeparation, ra, dec, useArtificialHorizon);
478 startTime.setTimeZone(tz);
479 stopTime.setTimeZone(tz);
483 while (--maxIters >= 0)
485 QDateTime s = job.getNextPossibleStartTime(startTime, SCHEDULE_RESOLUTION_MINUTES,
false, stopTime);
490 QDateTime e = job.getNextEndTime(s, SCHEDULE_RESOLUTION_MINUTES, &constraintReason, stopTime);
498 if (e.
secsTo(stopTime) < 600)
508 double minMoonSeparation,
bool useArtificialHorizon)
511 getRunTimes(date, geo, minAltitude, minMoonSeparation,
object.ra0(),
object.dec0(), useArtificialHorizon, &jobStartTimes,
513 if (jobStartTimes.
size() == 0 || jobEndTimes.
size() == 0)
517 double totalHours = 0.0;
518 for (
int i = 0; i < jobStartTimes.
size(); ++i)
519 totalHours += jobStartTimes[i].secsTo(jobEndTimes[i]) * 1.0 / 3600.0;
528int packString(
const QString &input, quint8 *p,
bool reallyPack)
531 quint32 len = str_data.
length();
532 const char *str = str_data.
data();
533 constexpr bool compatibilityMode =
false;
534 const quint8 *origP = p;
537 if (reallyPack) *p = 0xa0 | len;
540 else if (len <= std::numeric_limits<quint8>::max() &&
541 compatibilityMode ==
false)
543 if (reallyPack) *p = 0xd9;
545 if (reallyPack) *p = len;
548 else if (len <= std::numeric_limits<quint16>::max())
550 if (reallyPack) *p = 0xda;
561 if (reallyPack) memcpy(p, str, len);
562 return (p - origP) + len;
569 int size = packString(input,
nullptr,
false);
573 packString(input,
reinterpret_cast<quint8*
>(arr.
data()),
true);
583 newStr = newStr.
replace(0, 4,
"sh2-");
584 newStr = newStr.
replace(
' ',
"");
588bool downsampleImageFiles(
const QString &baseDir,
int maxHeight)
599 const QString subDir =
"REDUCED";
600 QDir directory(baseDir);
601 if (!directory.exists())
603 fprintf(stderr,
"downsampleImageFiles: Base directory doesn't exist\n");
611 fprintf(stderr,
"downsampleImageFiles: Failed making the output directory\n");
618 foreach (
QString filename, files)
623 if (img.height() > maxHeight)
632 if (!scaledImg.
save(jpgFilename,
"JPG"))
633 fprintf(stderr,
"downsampleImageFiles: Failed saving \"%s\"\n", writeFilename.
toLatin1().
data());
637 fprintf(stderr,
"downsampleImageFiles: saved \"%s\"\n", writeFilename.
toLatin1().
data());
640 fprintf(stderr,
"downsampleImageFiles: Wrote %d files\n", numSaved);
651 const int len = bInput.
size();
653 for (
int i = 0; i < len; ++i)
663 bInput.
replace(pos, 1, substitute);
671 QString massagedName = massageObjectName(name);
676 if (files.size() > 0)
677 return files[0].absoluteFilePath();
680 for (
int i = 0; i < subDirs.size(); i++)
682 QDir subDir(subDirs[i].absoluteFilePath());
684 if (files.size() > 0)
685 return files[0].absoluteFilePath();
692 if (astrobinAbbrev ==
"ACC")
694 else if (astrobinAbbrev ==
"ASACC")
696 else if (astrobinAbbrev ==
"ANCCC")
698 else if (astrobinAbbrev ==
"ANCSACC")
699 return "CC-BY-SA-NC";
703QString creativeCommonsTooltipString(
const QString &astrobinAbbrev)
705 if (astrobinAbbrev ==
"ACC")
706 return "Atribution Creative Commons";
707 else if (astrobinAbbrev ==
"ASACC")
708 return "Atribution Share-Alike Creative Commons";
709 else if (astrobinAbbrev ==
"ANCCC")
710 return "Atribution Non-Commercial Creative Commons";
711 else if (astrobinAbbrev ==
"ANCSACC")
712 return "Atribution Non-Commercial Share-Alike Creative Commons";
731 double hoursAfterDusk = 0,
double hoursBeforeDawn = 0)
737 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
739 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
745 auto end = dawn.
addSecs(-hoursBeforeDawn * 3600);
756 while (t.secsTo(end) > 0)
758 double alt = getAltitude(geo, coords, t);
764 t = t.addSecs(60 * 20);
773 m_SortColumn = HOURS_COLUMN;
777bool CatalogFilter::filterAcceptsRow(
int row,
const QModelIndex &parent)
const
781 if (!acceptType(type))
return false;
785 if (!hasEnoughHours)
return false;
790 const bool passesImagedConstraints = !m_ImagedConstraintsEnabled || (isImaged == m_ImagedRequired);
791 if (!passesImagedConstraints)
return false;
793 const bool isIgnored =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IGNORED_BIT;
794 const bool passesIgnoredConstraints = !m_IgnoredConstraintsEnabled || (isIgnored == m_IgnoredRequired);
795 if (!passesIgnoredConstraints)
return false;
797 const bool isPicked =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & PICKED_BIT;
798 const bool passesPickedConstraints = !m_PickedConstraintsEnabled || (isPicked == m_PickedRequired);
799 if (!passesPickedConstraints)
return false;
802 if (m_Keyword.
isEmpty() || !m_KeywordConstraintsEnabled)
return true;
807 return (m_KeywordRequired == REMatches);
810void CatalogFilter::setMinHours(
double hours)
815void CatalogFilter::setImagedConstraints(
bool enabled,
bool required)
817 m_ImagedConstraintsEnabled = enabled;
818 m_ImagedRequired = required;
821void CatalogFilter::setPickedConstraints(
bool enabled,
bool required)
823 m_PickedConstraintsEnabled = enabled;
824 m_PickedRequired = required;
827void CatalogFilter::setIgnoredConstraints(
bool enabled,
bool required)
829 m_IgnoredConstraintsEnabled = enabled;
830 m_IgnoredRequired = required;
833void CatalogFilter::setKeywordConstraints(
bool enabled,
bool required,
const QString &keyword)
835 m_KeywordConstraintsEnabled = enabled;
836 m_KeywordRequired = required;
841void CatalogFilter::setSortColumn(
int column)
843 if (column == m_SortColumn)
844 m_ReverseSort = !m_ReverseSort;
845 m_SortColumn = column;
854 double compareVal = 0;
859 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
860 if (m_ReverseSort) compareVal = -compareVal;
864 compareVal = stringCompareFcn(left, right, TYPE_COLUMN,
Qt::DisplayRole);
865 if (m_ReverseSort) compareVal = -compareVal;
866 if (compareVal != 0)
break;
867 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
868 if (compareVal != 0)
break;
869 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
873 compareVal = floatCompareFcn(left, right, SIZE_COLUMN, SIZE_ROLE);
874 if (m_ReverseSort) compareVal = -compareVal;
875 if (compareVal != 0)
break;
876 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
877 if (compareVal != 0)
break;
878 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
880 case ALTITUDE_COLUMN:
882 compareVal = floatCompareFcn(left, right, ALTITUDE_COLUMN, ALTITUDE_ROLE);
883 if (m_ReverseSort) compareVal = -compareVal;
884 if (compareVal != 0)
break;
885 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
886 if (compareVal != 0)
break;
887 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
891 compareVal = floatCompareFcn(left, right, MOON_COLUMN, MOON_ROLE);
892 if (m_ReverseSort) compareVal = -compareVal;
893 if (compareVal != 0)
break;
894 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
895 if (compareVal != 0)
break;
896 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
898 case CONSTELLATION_COLUMN:
900 compareVal = stringCompareFcn(left, right, CONSTELLATION_COLUMN,
Qt::DisplayRole);
901 if (m_ReverseSort) compareVal = -compareVal;
902 if (compareVal != 0)
break;
903 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
904 if (compareVal != 0)
break;
905 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
909 compareVal = stringCompareFcn(left, right, COORD_COLUMN,
Qt::DisplayRole);
910 if (m_ReverseSort) compareVal = -compareVal;
911 if (compareVal != 0)
break;
912 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
913 if (compareVal != 0)
break;
914 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
919 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
920 if (m_ReverseSort) compareVal = -compareVal;
921 if (compareVal != 0)
break;
922 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
925 return compareVal < 0;
935void ImagingPlannerUI::setupIcons()
959 return KStarsData::Instance()->
geo();
962QDate ImagingPlanner::getDate()
const
964 return ui->DateEdit->date();
967ImagingPlanner::ImagingPlanner() :
QDialog(nullptr), m_manager{ CatalogsDB::dso_db_path() }
969 ui =
new ImagingPlannerUI(
this);
975 setLayout(mainLayout);
977 setWindowTitle(
i18nc(
"@title:window",
"Imaging Planner"));
980 if (Options::imagingPlannerIndependentWindow())
996void ImagingPlanner::setupHideButtons(
bool(*option)(),
void(*setOption)(
bool),
1006 Options::self()->save();
1015 Options::self()->save();
1023void ImagingPlanner::focusOnTable()
1028void ImagingPlanner::adjustWindowSize()
1030 const int keepWidth =
width();
1032 const int newHeight =
height();
1033 resize(keepWidth, newHeight);
1037void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox,
bool(*option)(),
void(*setOption)(
bool))
1043 Options::self()->save();
1044 m_CatalogSortModel->invalidate();
1046 ui->CatalogView->resizeColumnsToContents();
1052void ImagingPlanner::setupFilter2Buttons(
1054 bool(*yesOption)(),
bool(*noOption)(),
bool(*dontCareOption)(),
1055 void(*setYesOption)(
bool),
void(*setNoOption)(
bool),
void(*setDontCareOption)(
bool))
1061 setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1062 updateSortConstraints();
1063 m_CatalogSortModel->invalidate();
1064 ui->CatalogView->resizeColumnsToContents();
1070 setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1071 updateSortConstraints();
1072 m_CatalogSortModel->invalidate();
1073 ui->CatalogView->resizeColumnsToContents();
1077 connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
1079 setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1080 updateSortConstraints();
1081 m_CatalogSortModel->invalidate();
1082 ui->CatalogView->resizeColumnsToContents();
1093void ImagingPlanner::updateSortConstraints()
1095 m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
1096 ui->pickedCB->isChecked());
1097 m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
1098 ui->imagedCB->isChecked());
1099 m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
1100 ui->ignoredCB->isChecked());
1101 m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
1102 ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
1106void ImagingPlanner::initialize()
1108 if (KStarsData::Instance() ==
nullptr)
1115 connect(
this, &ImagingPlanner::popupSorry,
this, &ImagingPlanner::sorry);
1121 m_CatalogModel->setHorizontalHeaderLabels(
1124 m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
1125 i18n(
"Object Name--click header to sort ascending/descending."));
1126 m_CatalogModel->horizontalHeaderItem(
1127 HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
1128 m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
1129 i18n(
"Object Type--click header to sort ascending/descending."));
1130 m_CatalogModel->horizontalHeaderItem(
1131 SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
1132 m_CatalogModel->horizontalHeaderItem(
1133 ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
1134 m_CatalogModel->horizontalHeaderItem(
1135 MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
1136 m_CatalogModel->horizontalHeaderItem(
1137 CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
1138 m_CatalogModel->horizontalHeaderItem(
1139 COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
1141 m_CatalogSortModel =
new CatalogFilter(
this);
1143 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
1144 m_CatalogSortModel->setDynamicSortFilter(
true);
1146 ui->CatalogView->setModel(m_CatalogSortModel.
data());
1147 ui->CatalogView->setSortingEnabled(
false);
1148 ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
1149 ui->CatalogView->resizeColumnsToContents();
1150 ui->CatalogView->verticalHeader()->
setVisible(
false);
1151 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
1154 this, &ImagingPlanner::selectionChanged);
1159 auto utc = KStarsData::Instance()->
clock()->
utc();
1160 auto localTime = getGeo()->UTtoLT(utc);
1161 ui->DateEdit->setDate(localTime.date());
1167 setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
1168 ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
1169 ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
1176 QString selection = currentObjectName();
1180 scrollToName(selection);
1196 Options::setImagingPlannerHideAstrobinDetails(
true);
1197 setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
1198 ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
1199 ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
1200 ui->AstrobinAward->setChecked(Options::astrobinAward());
1203 Options::setAstrobinAward(checked);
1204 Options::self()->save();
1207 ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
1210 Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
1211 Options::self()->save();
1214 ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
1217 Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
1218 Options::self()->save();
1229 setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
1230 ui->hideImageButton, ui->showImageButton,
1231 ui->ImageFrame, ui->HiddenImageFrame);
1234 Options::setImagingPlannerHideFilters(
true);
1235 setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
1236 ui->hideFilterTypesButton, ui->showFilterTypesButton,
1237 ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
1238 setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
1239 &Options::setImagingPlannerAcceptOpenCluster);
1240 setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
1241 setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
1242 &Options::setImagingPlannerAcceptGlobularCluster);
1243 setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
1244 setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
1245 &Options::setImagingPlannerAcceptSupernovaRemnant);
1246 setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
1247 setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
1248 &Options::setImagingPlannerAcceptGalaxyCluster);
1249 setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
1250 setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
1252 setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
1253 &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
1254 &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
1256 setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
1257 &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
1258 &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
1260 setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
1261 &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
1262 &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
1263 &Options::setImagingPlannerDontCareIgnored);
1265 ui->keywordEdit->setText(Options::imagingPlannerKeyword());
1266 ui->keywordEdit->setAcceptRichText(
false);
1267 m_Keyword = Options::imagingPlannerKeyword();
1268 setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
1269 &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
1270 &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
1271 &Options::setImagingPlannerDontCareKeyword);
1276 ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
1277 m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
1278 ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
1279 m_MinMoon = Options::imagingPlannerMinMoonSeparation();
1280 ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
1281 m_MinAltitude = Options::imagingPlannerMinAltitude();
1282 ui->minHours->setValue(Options::imagingPlannerMinHours());
1283 m_MinHours = Options::imagingPlannerMinHours();
1284 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1287 if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
1289 m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
1290 Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
1291 Options::self()->save();
1297 if (m_MinMoon == ui->minMoon->value())
1299 m_MinMoon = ui->minMoon->value();
1300 Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
1301 Options::self()->save();
1307 if (m_MinAltitude == ui->minAltitude->value())
1309 m_MinAltitude = ui->minAltitude->value();
1310 Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
1311 Options::self()->save();
1317 if (m_MinHours == ui->minHours->value())
1319 m_MinHours = ui->minHours->value();
1320 Options::setImagingPlannerMinHours(ui->minHours->value());
1321 Options::self()->save();
1322 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1323 m_CatalogSortModel->invalidate();
1324 ui->CatalogView->resizeColumnsToContents();
1328 updateSortConstraints();
1330 m_CatalogSortModel->setMinHours(ui->minHours->value());
1332 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
1341 ui->userNotesLabel->setVisible(true);
1342 ui->userNotesEdit->setText(ui->userNotes->text());
1343 ui->userNotesEdit->setVisible(true);
1344 ui->userNotesEditButton->setVisible(false);
1345 ui->userNotesDoneButton->setVisible(true);
1346 ui->userNotes->setVisible(false);
1347 ui->userNotesLabel->setVisible(true);
1348 ui->userNotesOpenLink->setVisible(false);
1349 ui->userNotesOpenLink2->setVisible(false);
1350 ui->userNotesOpenLink3->setVisible(false);
1356 QString urlString = findUrl(ui->userNotes->text());
1357 if (urlString.isEmpty())
1359 QDesktopServices::openUrl(QUrl(urlString));
1364 QString urlString = findUrl(ui->userNotes->text(), 2);
1365 if (urlString.isEmpty())
1367 QDesktopServices::openUrl(QUrl(urlString));
1372 QString urlString = findUrl(ui->userNotes->text(), 3);
1373 if (urlString.isEmpty())
1375 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);
1406 installEventFilters();
1409void ImagingPlanner::installEventFilters()
1423void ImagingPlanner::removeEventFilters()
1435void ImagingPlanner::openOptionsMenu()
1443void ImagingPlanner::getHelp()
1453 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/MESSIER", 300))
1454 fprintf(stderr,
"downsampling succeeded\n");
1456 fprintf(stderr,
"downsampling failed\n");
1458 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/OTHER", 300))
1459 fprintf(stderr,
"downsampling succeeded\n");
1461 fprintf(stderr,
"downsampling failed\n");
1463 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/CALDWELL", 300))
1464 fprintf(stderr,
"downsampling succeeded\n");
1466 fprintf(stderr,
"downsampling failed\n");
1468 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/AWARDS", 300))
1469 fprintf(stderr,
"downsampling succeeded\n");
1471 fprintf(stderr,
"downsampling failed\n");
1473 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/HERSCHEL12", 300))
1474 fprintf(stderr,
"downsampling succeeded\n");
1476 fprintf(stderr,
"downsampling failed\n");
1479 const QUrl url(
"https://docs.kde.org/trunk5/en/kstars/kstars/kstars.pdf#tool-imaging-planner");
1484KSMoon *ImagingPlanner::getMoon()
1486 if (KStarsData::Instance() ==
nullptr)
1492 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1495 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1497 moon->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1503void ImagingPlanner::updateMoon()
1505 KSMoon *moon = getMoon();
1510 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1512 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1515 sun->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1519 ui->moonPercentLabel->setText(
QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0,
'f', 0));
1522bool ImagingPlanner::scrollToName(
const QString &name)
1526 QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0),
Qt::EditRole,
1528 if(matchList.count() >= 1)
1531 for (
int i = 0; i < matchList.count(); i++)
1540 ui->CatalogView->scrollTo(matchList[bestIndex]);
1541 ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
1547void ImagingPlanner::searchSlot()
1549 if (m_loadingCatalog)
1551 QString origName = ui->SearchText->toPlainText().trimmed();
1553 ui->SearchText->setPlainText(name);
1557 if (!scrollToName(name))
1558 KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
1561 ui->SearchText->clear();
1562 ui->SearchText->setPlainText(
"");
1565void ImagingPlanner::initUserNotes()
1578void ImagingPlanner::disableUserNotes()
1590void ImagingPlanner::userNotesEditFinished()
1592 const QString ¬es = ui->userNotesEdit->toPlainText().trimmed();
1593 ui->userNotes->setText(notes);
1600 setCurrentObjectNotes(notes);
1601 setupNotesLinks(notes);
1603 auto o = currentCatalogObject();
1605 saveToDB(currentObjectName(), currentObjectFlags(), notes);
1608void ImagingPlanner::updateNotes(
const QString ¬es)
1612 ui->userNotes->setText(notes);
1614 setupNotesLinks(notes);
1617void ImagingPlanner::setupNotesLinks(
const QString ¬es)
1621 if (!
link.isEmpty())
1622 ui->userNotesOpenLink->
setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
1624 link = findUrl(notes, 2);
1626 if (!
link.isEmpty())
1627 ui->userNotesOpenLink2->
setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
1629 link = findUrl(notes, 3);
1631 if (!
link.isEmpty())
1632 ui->userNotesOpenLink3->
setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
1642 std::list<CatalogObject> objs =
1647 int abellNumber = -1;
1648 bool abellPlanetary =
false;
1652 auto match = abellRE.match(filteredName);
1653 if (
match.hasMatch())
1655 abellNumber =
match.captured(1).toInt();
1656 if (abellNumber <= 86)
1657 abellPlanetary =
true;
1660 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1663 if (objs.size() == 0 && filteredName.
size() > 0)
1666 const QString capitalized = capitalize(filteredName);
1668 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1671 if (objs.size() == 0)
1676 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1696 if (objs.size() == 0 && !abellPlanetary)
1698 if (objs.size() == 0)
1705 QString resolverName = filteredName;
1709 resolverName =
QString(
"PN A66 %1").
arg(abellNumber);
1719 if (
object.
name() ==
object.name2())
1720 object.setName2(filteredName);
1721 object.setName(filteredName);
1724 m_manager.
add_object(CatalogsDB::user_catalog_id,
object);
1725 const auto &added_object =
1726 m_manager.
get_object(
object.getId(), CatalogsDB::user_catalog_id);
1728 if (added_object.first)
1730 *catObject = KStarsData::Instance()
1732 ->catalogsComponent()
1736 DPRINTF(stderr,
"***** Found %s using name resolver (%.1fs)\n",
name.
toLatin1().
data(),
1737 timer.elapsed() / 1000.0);
1741 if (objs.size() == 0)
1745 *catObject = objs.front();
1746 if (objs.size() > 1)
1748 QString addSpace = filteredName;
1750 for (
const auto &obj : objs)
1770 auto o = m_CatalogHash.
find(lName);
1771 if (o == m_CatalogHash.
end())
1776void ImagingPlanner::clearObjects()
1782 m_CatalogHash.
clear();
1790 if (getObject(lName) !=
nullptr)
1792 DPRINTF(stderr,
"Didn't add \"%s\" because it's already there\n",
name.
toLatin1().
data());
1797 if (!getKStarsCatalogObject(lName, &o))
1799 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
1802 m_CatalogHash[lName] = o;
1803 return &(m_CatalogHash[lName]);
1808bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal,
const QString &name,
int flags)
1811 if (
object ==
nullptr)
1824 for (
int i = 0; i < LAST_COLUMN; ++i)
1826 if (i == NAME_COLUMN)
1828 itemList.
append(getItemWithUserRole(name));
1830 else if (i == HOURS_COLUMN)
1832 double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
1833 ui->useArtificialHorizon->isChecked());
1834 auto hoursItem = getItemWithUserRole(
QString(
"%1").arg(runHours, 0,
'f', 1));
1835 hoursItem->setData(runHours, HOURS_ROLE);
1836 itemList.
append(hoursItem);
1838 else if (i == TYPE_COLUMN)
1840 auto typeItem = getItemWithUserRole(
QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
1841 typeItem->setData(object->
type(), TYPE_ROLE);
1842 itemList.
append(typeItem);
1844 else if (i == SIZE_COLUMN)
1846 double size = std::max(object->
a(), object->
b());
1847 auto sizeItem = getItemWithUserRole(
QString(
"%1'").arg(
size, 0,
'f', 1));
1848 sizeItem->setData(
size, SIZE_ROLE);
1849 itemList.
append(sizeItem);
1851 else if (i == ALTITUDE_COLUMN)
1854 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
1855 auto altItem = getItemWithUserRole(
QString(
"%1º").arg(altitude, 0,
'f', 0));
1856 altItem->setData(altitude, ALTITUDE_ROLE);
1857 itemList.
append(altItem);
1859 else if (i == MOON_COLUMN)
1861 KSMoon *moon = getMoon();
1867 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1874 auto moonItem = getItemWithUserRole(
QString(
"%1º").arg(separation, 0,
'f', 0));
1875 moonItem->setData(separation, MOON_ROLE);
1876 itemList.
append(moonItem);
1880 auto moonItem = getItemWithUserRole(
QString(
""));
1881 moonItem->setData(-1, MOON_ROLE);
1884 else if (i == CONSTELLATION_COLUMN)
1886 QString cname = KStarsData::Instance()
1888 ->constellationBoundary()
1889 ->constellationName(
object);
1891 auto constellationItem = getItemWithUserRole(cname);
1892 itemList.
append(constellationItem);
1894 else if (i == COORD_COLUMN)
1896 itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
1898 else if (i == FLAGS_COLUMN)
1901 flag->
setData(flags, FLAGS_ROLE);
1904 else if (i == NOTES_COLUMN)
1912 DPRINTF(stderr,
"Bug in addCatalogItem() !\n");
1917 emit addRow(itemList);
1923 m_CatalogModel->appendRow(itemList);
1927void ImagingPlanner::recompute()
1929 setStatus(
i18n(
"Updating tables..."));
1932 m_CatalogSortModel->setSourceModel(
nullptr);
1937 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1942 for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
1944 const QString &
name = m_CatalogModel->item(i, 0)->text();
1946 if (catalogEntry ==
nullptr)
1948 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n",
name.
toLatin1().
data());
1951 double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
1952 ui->minMoon->value(), ui->useArtificialHorizon->isChecked());
1957 hItem->
setData(runHours, HOURS_ROLE);
1958 m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
1962 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
1966 altItem->setData(altitude, ALTITUDE_ROLE);
1967 m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
1969 KSMoon *moon = getMoon();
1975 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
1985 moonItem->setData(separation, MOON_ROLE);
1986 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1992 moonItem->setData(-1, MOON_ROLE);
1993 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1997 const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
1999 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
2000 const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
2002 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
2005 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
2007 DPRINTF(stderr,
"Recompute took %.1fs\n", timer.elapsed() / 1000.0);
2014void ImagingPlanner::checkTargets()
2018 fprintf(stderr,
"****************** check objects (%d)***************\n", flags->
size());
2019 for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
2020 fprintf(stderr,
"Removed, now %d\n", flags->
size());
2022 int rows = m_CatalogModel->rowCount();
2026 for (
int i = 0; i < rows; ++i)
2028 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
2030 accepted[i] = getObject(name) !=
nullptr;
2032 auto object = getObject(name);
2036 fprintf(stderr,
"%d ", i);
2040 for (
int i = 0; i < targets.
size(); ++i)
2046 object->setRA(object->
ra0());
2047 object->setDec(object->
dec0());
2048 for (
int j = 0; j < targets.
size(); ++j)
2050 if (i == j)
continue;
2052 auto name2 = targets[j];
2053 auto object2 = getObject(name2);
2054 object2->setRA(object2->ra0());
2055 object2->setDec(object2->dec0());
2056 const dms dist =
object->angularDistanceTo(object2);
2057 const double arcsecDist = dist.
Degrees() * 3600.0;
2058 if (arcsecDist < 120)
2060 fprintf(stderr,
"dist %10s (%s %s) to %10s (%s %s) = %.0f\" %s\n",
2065 object2->ra().toHMSString().toLatin1().data(),
2066 object2->dec().toDMSString().toLatin1().data(),
2073 fprintf(stderr,
"Done\n");
2080QString ImagingPlanner::defaultDirectory()
const
2088QString ImagingPlanner::findDefaultCatalog()
const
2092 for (
int i = 0; i < subDirs.size(); i++)
2095 const QDir subDir(subDirs[i].absoluteFilePath());
2098 if (files.size() > 0)
2103 for (
const auto &file : files)
2106 firstFile = file.absoluteFilePath();
2108 return file.absoluteFilePath();
2117void ImagingPlanner::loadInitialCatalog()
2119 QString catalog = Options::imagingPlannerCatalogPath();
2121 catalog = findDefaultCatalog();
2124 KSNotification::sorry(
i18n(
"You need to load a catalog to start using this tool.\nSee Data -> Download New Data..."));
2125 setStatus(
i18n(
"No Catalog!"));
2128 loadCatalog(catalog);
2131void ImagingPlanner::setStatus(
const QString &message)
2133 ui->statusLabel->setText(message);
2136void ImagingPlanner::catalogLoaded()
2138 DPRINTF(stderr,
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
2144 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
2145 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
2147 m_CatalogSortModel->invalidate();
2149 ui->CatalogView->resizeColumnsToContents();
2152 auto index = ui->CatalogView->model()->index(0, 0);
2154 ui->CatalogView->selectionModel()->select(index,
2163void ImagingPlanner::updateStatus()
2165 if (currentObjectName().isEmpty())
2167 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2168 const int totalCatalogObjects = m_CatalogModel->rowCount();
2170 if (numDisplayedObjects > 0)
2171 setStatus(
i18n(
"Select an object."));
2172 else if (totalCatalogObjects > 0)
2173 setStatus(
i18n(
"Check Filters to unhide objects."));
2175 setStatus(
i18n(
"Load a Catalog."));
2185 if (m_initialShow ==
false)
2187 m_initialShow =
true;
2195void ImagingPlanner::slotClose()
2201QUrl ImagingPlanner::getAstrobinUrl(
const QString &target,
bool requireAwards,
bool requireSomeFilters,
double minRadius,
2204 QString myQuery =
QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").
arg(target);
2207 auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
2208 QDate today = localTime.date();
2209 myQuery.
append(
QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
2212 myQuery.
append(
QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
2214 if (requireSomeFilters)
2215 myQuery.
append(
QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
2217 if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
2218 myQuery.
append(
QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
2229 replaceByteArrayChars(b64,
'+',
QByteArray(
"%2B"));
2230 replaceByteArrayChars(b64,
'=',
QByteArray(
"%3D"));
2231 replaceByteArrayChars(b,
'"',
QByteArray(
"%22"));
2232 replaceByteArrayChars(b,
':',
QByteArray(
"%3A"));
2233 replaceByteArrayChars(b,
'[',
QByteArray(
"%5B"));
2234 replaceByteArrayChars(b,
']',
QByteArray(
"%5D"));
2235 replaceByteArrayChars(b,
',',
QByteArray(
"%2C"));
2236 replaceByteArrayChars(b,
'\'',
QByteArray(
"%27"));
2237 replaceByteArrayChars(b,
'{',
QByteArray(
"%7B"));
2238 replaceByteArrayChars(b,
'}',
QByteArray(
"%7D"));
2244void ImagingPlanner::popupAstrobin(
const QString &target)
2246 QString newStr = massageObjectName(target);
2249 const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(),
false, Options::astrobinMinRadius(),
2250 Options::astrobinMaxRadius());
2256void ImagingPlanner::searchNGCICImages()
2259 auto o = currentCatalogObject();
2262 fprintf(stderr,
"NULL object sent to searchNGCICImages.\n");
2268 num = o->name().mid(3).toInt();
2269 QString urlString =
QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3").
arg(num / 100).
arg(
2270 num % 100 < 50 ?
"" :
"a").
arg(num);
2276 num = o->name().mid(2).toInt();
2277 QString urlString =
QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3").
arg(num / 100).
arg(
2278 num % 100 < 50 ?
"" :
"a").
arg(num);
2284void ImagingPlanner::searchSimbad()
2296 QString urlStr =
QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1"
2297 "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
2303void ImagingPlanner::searchWikipedia()
2306 QString wikipediaAddress =
"https://en.wikipedia.org";
2310 fprintf(stderr,
"NULL object sent to Wikipedia.\n");
2328 .
arg(wikipediaAddress).
arg(massageObjectName(name));
2332 QUrl(
QString(
"%1/wiki/%2").arg(wikipediaAddress).arg(massagedName)));
2335void ImagingPlanner::searchAstrobin()
2341 popupAstrobin(name);
2344bool ImagingPlanner::eventFilter(
QObject * obj,
QEvent * event)
2346 if (m_loadingCatalog)
2351 m_InitialLoad =
false;
2353 setStatus(
i18n(
"Loading Catalogs..."));
2354 loadInitialCatalog();
2360 if ((obj == ui->CatalogView->viewport()) &&
2365 int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
2367 for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
2369 selectedNames.
append(r.siblingAtColumn(0).
data().toString());
2370 bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
2371 if (isPicked) numPicked++;
2372 else numNotPicked++;
2373 bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
2374 if (isImaged) numImaged++;
2375 else numNotImaged++;
2376 bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
2377 if (isIgnored) numIgnored++;
2378 else numNotIgnored++;
2381 if (selectedNames.
size() == 0)
2385 m_PopupMenu =
new ImagingPlannerPopup;
2387 const bool imaged = numImaged > 0;
2388 const bool picked = numPicked > 0;
2389 const bool ignored = numIgnored > 0;
2390 m_PopupMenu->init(
this, selectedNames,
2391 (numImaged > 0 && numNotImaged > 0) ?
nullptr : &imaged,
2392 (numPicked > 0 && numNotPicked > 0) ?
nullptr : &picked,
2393 (numIgnored > 0 && numNotIgnored > 0) ?
nullptr : &ignored);
2395 m_PopupMenu->popup(
pos);
2399 userNotesEditFinished();
2402 keywordEditFinished();
2413 keywordEditFinished();
2437 else if ((obj == ui->ImagePreview ||
2438 obj == ui->ImagePreviewCredit ||
2439 obj == ui->ImagePreviewCreditLink) &&
2442 if (!ui->ImagePreviewCreditLink->text().isEmpty())
2444 QUrl url(ui->ImagePreviewCreditLink->text());
2452void ImagingPlanner::keywordEditFinished()
2454 QString kwd = ui->keywordEdit->toPlainText().trimmed();
2455 ui->keywordEdit->clear();
2456 ui->keywordEdit->setText(kwd);
2457 if (m_Keyword != kwd)
2460 Options::setImagingPlannerKeyword(kwd);
2461 Options::self()->save();
2462 updateSortConstraints();
2463 m_CatalogSortModel->invalidate();
2464 ui->CatalogView->resizeColumnsToContents();
2469void ImagingPlanner::setDefaultImage()
2471 ui->ImagePreview->setPixmap(m_NoImagePixmap);
2472 ui->ImagePreview->
update();
2473 ui->ImagePreviewCredit->setText(
"");
2474 ui->ImagePreviewCreditLink->setText(
"");
2479 if (m_loadingCatalog)
2482 Q_UNUSED(deselected);
2483 if (selected.
indexes().size() == 0)
2491 auto selection = selected.
indexes()[0];
2494 if (
object ==
nullptr)
2501 ui->ImagePreviewCredit->setText(
"");
2502 ui->ImagePreviewCreditLink->setText(
"");
2505 CatalogImageInfo catalogImageInfo;
2506 if (findCatalogImageInfo(name, &catalogImageInfo))
2508 QString filename = catalogImageInfo.m_Filename;
2509 if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
2511 QString imageFullPath = filename;
2515 imageFullPath =
QString(
"%1%2%3").
arg(catDir)
2518 if (!
QFile(imageFullPath).exists())
2519 DPRINTF(stderr,
"Image for \"%s\" -- \"%s\" doesn't exist\n",
2523 if (!catalogImageInfo.m_Link.
isEmpty())
2525 ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
2526 ui->ImagePreview->
setToolTip(
"Click to see original");
2527 ui->ImagePreviewCreditLink->
setToolTip(
"Click to see original");
2531 ui->ImagePreviewCreditLink->setText(
"");
2536 if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
2538 ui->ImagePreviewCredit->setText(
2539 QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
2540 .
arg(creativeCommonsString(catalogImageInfo.m_License)));
2542 QString(
"Original image license: %1")
2543 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2545 else if (!catalogImageInfo.m_Author.
isEmpty())
2547 ui->ImagePreviewCredit->setText(
2548 QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
2551 else if (!catalogImageInfo.m_License.
isEmpty())
2553 ui->ImagePreviewCredit->setText(
2554 QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
2556 QString(
"Original image license: %1")
2557 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2561 ui->ImagePreviewCredit->setText(
"");
2568 object->load_image();
2569 auto image =
object->image();
2575 const QString foundFilename = findObjectImage(name);
2578 constexpr int thumbHeight = 300, thumbWidth = 400;
2580 const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
2582 ui->ImagePreview->setPixmap(
2596void ImagingPlanner::updateDisplays()
2601 if (!currentCatalogObject())
2603 if (ui->CatalogView->model()->rowCount() > 0)
2605 auto index = ui->CatalogView->model()->index(0, 0);
2606 ui->CatalogView->selectionModel()->select(index,
2611 auto object = currentCatalogObject();
2614 updateDetails(*
object, currentObjectFlags());
2615 updateNotes(currentObjectNotes());
2616 plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
2623void ImagingPlanner::updateDetails(
const CatalogObject &
object,
int flags)
2625 ui->infoObjectName->setText(
object.
name());
2626 ui->infoSize->setText(
QString(
"%1' x %2'").arg(
object.a(), 0,
'f', 1).arg(
object.b(), 0,
'f', 1));
2632 if (
object.longname().isEmpty() || (
object.longname() ==
object.
name()))
2633 ui->infoObjectLongName->clear();
2635 ui->infoObjectLongName->setText(
QString(
"(%1)").arg(
object.longname()));
2640 QTime riseTime =
object.riseSetTime(noon, getGeo(),
true);
2641 QTime setTime =
object.riseSetTime(noon, getGeo(),
false);
2642 QTime transitTime =
object.transitTime(noon, getGeo());
2643 dms transitAltitude =
object.transitAltitude(noon, getGeo());
2646 KSMoon *moon = getMoon();
2649 const double separation = ui->CatalogView->selectionModel()->currentIndex()
2650 .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
2652 if (separation >= 0)
2653 moonString =
QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0,
'f', 1);
2658 riseSetString =
QString(
"%1 %2 @ %3º")
2663 riseSetString =
QString(
"%1 %2")
2667 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2674 riseSetString =
QString(
"%1 %2")
2678 riseSetString =
QString(
"%1 %2 %3 %4 @ %5º")
2685 riseSetString =
QString(
"%1 %2 %3 %4")
2691 riseSetString =
QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
2699 if (moonString.
size() > 0)
2701 ui->infoRiseSet->setText(riseSetString);
2706 ui->infoObjectFlags->setText(flagString(flags));
2715void ImagingPlanner::plotAltitudeGraph(
const QDate &date,
const dms &ra,
const dms &dec)
2717 auto altitudeGraph = ui->altitudeGraph;
2718 altitudeGraph->setAltitudeAxis(-20.0, 90.0);
2722 getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked(),
2723 &jobStartTimes, &jobEndTimes);
2725 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
2731 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
2733 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
2736 Ekos::SchedulerJob job;
2737 setupJob(job,
"temp", ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked());
2745 plotStart = plotStart.
addSecs(-1 * 3600);
2748 auto plotEnd = dawn.
addSecs(1 * 3600);
2751 while (t.secsTo(plotEnd) > 0)
2753 SkyPoint coords = job.getTargetCoords();
2754 double alt = getAltitude(getGeo(), coords, t);
2756 double hour = midnight.
secsTo(t) / 3600.0;
2758 t = t.addSecs(60 * 10);
2761 altitudeGraph->plot(getGeo(), &ksal, times, alts,
false);
2763 for (
int i = 0; i < jobStartTimes.
size(); ++i)
2765 auto startTime = jobStartTimes[i];
2766 auto stopTime = jobEndTimes[i];
2767 if (startTime < plotStart) startTime = plotStart;
2768 if (stopTime > plotEnd) stopTime = plotEnd;
2771 stopTime.setTimeZone(tz);
2778 while (t.secsTo(stopTime) > 0)
2780 SkyPoint coords = job.getTargetCoords();
2781 double alt = getAltitude(getGeo(), coords, t);
2783 double hour = midnight.
secsTo(t) / 3600.0;
2785 t = t.addSecs(60 * 10);
2787 altitudeGraph->plot(getGeo(), &ksal, runTimes, runAlts,
true);
2791void ImagingPlanner::updateCounts()
2793 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2794 const int totalCatalogObjects = m_CatalogModel->rowCount();
2795 if (numDisplayedObjects == 1)
2796 ui->tableCount->setText(
QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
2798 ui->tableCount->setText(
QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
2801void ImagingPlanner::moveBackOneDay()
2804 QString selection = currentObjectName();
2805 ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
2809 scrollToName(selection);
2812void ImagingPlanner::moveForwardOneDay()
2814 QString selection = currentObjectName();
2815 ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
2819 scrollToName(selection);
2822QString ImagingPlanner::currentObjectName()
const
2824 QString name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).data(
2832 return getObject(name);
2837void ImagingPlanner::objectDetails()
2840 if (current ==
nullptr)
2842 auto ut = KStarsData::Instance()->
ut();
2850void ImagingPlanner::centerOnSkymap()
2852 if (!Options::imagingPlannerCenterOnSkyMap())
2854 reallyCenterOnSkymap();
2857void ImagingPlanner::reallyCenterOnSkymap()
2860 if (current ==
nullptr)
2866 DPRINTF(stderr,
"found a 0,0 object\n");
2872 dms lst = getGeo()->GSTtoLST(time.
gst());
2877 bool keepGround = Options::showGround();
2878 bool keepAnimatedSlew = Options::useAnimatedSlewing();
2879 Options::setShowGround(
false);
2880 Options::setUseAnimatedSlewing(
false);
2886 Options::setShowGround(keepGround);
2887 Options::setUseAnimatedSlewing(keepAnimatedSlew);
2890void ImagingPlanner::setSelection(
int flag,
bool enabled)
2892 auto rows = ui->CatalogView->selectionModel()->selectedRows();
2902 for (
int i = 0; i < rows.size(); ++i)
2904 auto proxyIndex = rows[i].siblingAtColumn(FLAGS_COLUMN);
2905 auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
2906 sourceIndeces.
append(sourceIndex);
2909 for (
int i = 0; i < sourceIndeces.
size(); ++i)
2911 auto &sourceIndex = sourceIndeces[i];
2915 setFlag(sourceIndex, flag, m_CatalogModel.
data());
2917 clearFlag(sourceIndex, flag, m_CatalogModel.
data());
2919 QString name = m_CatalogModel->data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
2920 int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
2921 QString notes = m_CatalogModel->data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
2922 saveToDB(name, flags, notes);
2924 if (flag == IMAGED_BIT)
2925 highlightImagedObject(sourceIndex,
enabled);
2926 if (flag == PICKED_BIT)
2927 highlightPickedObject(sourceIndex,
enabled);
2932void ImagingPlanner::highlightImagedObject(
const QModelIndex &index,
bool imaged)
2935 QColor m_DefaultCellBackground(36, 35, 35);
2936 QColor m_ImagedObjectBackground(10, 65, 10);
2938 if (themeName ==
"High Key" || themeName ==
"Default" || themeName ==
"White Balance")
2940 m_DefaultCellBackground =
QColor(240, 240, 240);
2941 m_ImagedObjectBackground =
QColor(180, 240, 180);
2943 for (
int col = 0; col < LAST_COLUMN; ++col)
2946 m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground,
Qt::BackgroundRole);
2950void ImagingPlanner::highlightPickedObject(
const QModelIndex &index,
bool picked)
2952 for (
int col = 0; col < LAST_COLUMN; ++col)
2956 auto ff = qvariant_cast<QFont>(
font);
2958 ff.setItalic(picked);
2959 ff.setUnderline(picked);
2965void ImagingPlanner::setSelectionPicked()
2967 setSelection(PICKED_BIT,
true);
2970void ImagingPlanner::setSelectionNotPicked()
2972 setSelection(PICKED_BIT,
false);
2975void ImagingPlanner::setSelectionImaged()
2977 setSelection(IMAGED_BIT,
true);
2980void ImagingPlanner::setSelectionNotImaged()
2982 setSelection(IMAGED_BIT,
false);
2985void ImagingPlanner::setSelectionIgnored()
2987 setSelection(IGNORED_BIT,
true);
2990void ImagingPlanner::setSelectionNotIgnored()
2992 setSelection(IGNORED_BIT,
false);
2995int ImagingPlanner::currentObjectFlags()
2997 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(FLAGS_COLUMN);
2998 const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
3001 return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
3004QString ImagingPlanner::currentObjectNotes()
3006 auto index = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NOTES_COLUMN);
3007 const bool hasNotes = ui->CatalogView->model()->data(index, NOTES_ROLE).canConvert<
QString>();
3010 return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
3013void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
3015 auto index = ui->CatalogView->selectionModel()->currentIndex();
3020 auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
3022 m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
3025ImagingPlannerPopup::ImagingPlannerPopup() :
QMenu(nullptr)
3034void ImagingPlannerPopup::init(ImagingPlanner * planner,
const QStringList &names,
3035 const bool * imaged,
const bool * picked,
const bool * ignored)
3038 if (names.
size() == 0)
return;
3041 if (names.
size() == 1)
3043 else if (names.
size() <= 3)
3046 for (
int i = 1; i < names.
size(); i++)
3050 title =
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
3056 if (imaged ==
nullptr)
3058 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3059 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3062 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3064 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3066 if (picked ==
nullptr)
3068 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3069 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3072 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3074 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3077 if (ignored ==
nullptr)
3079 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3080 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3084 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3086 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3089 addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
3093ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
bool picked,
bool imaged,
3094 bool ignored,
const QString ¬es) : m_Name(
name), m_Notes(notes)
3099ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
int flags,
const QString ¬es)
3100 : m_Name(
name), m_Flags(flags), m_Notes(notes)
3104void ImagingPlannerDBEntry::getFlags(
bool * picked,
bool * imaged,
bool * ignored)
3106 *picked = m_Flags & PickedBit;
3107 *imaged = m_Flags & ImagedBit;
3108 *ignored = m_Flags & IgnoredBit;
3112void ImagingPlannerDBEntry::setFlags(
bool picked,
bool imaged,
bool ignored)
3115 if (picked) m_Flags |= PickedBit;
3116 if (imaged) m_Flags |= ImagedBit;
3117 if (ignored) m_Flags |= IgnoredBit;
3120void ImagingPlanner::saveToDB(
const QString &name,
bool picked,
bool imaged,
3121 bool ignored,
const QString ¬es)
3123 ImagingPlannerDBEntry e(name, 0, notes);
3124 e.setFlags(picked, imaged, ignored);
3128void ImagingPlanner::saveToDB(
const QString &name,
int flags,
const QString ¬es)
3130 ImagingPlannerDBEntry e(name, flags, notes);
3135void ImagingPlanner::loadFromDB()
3140 m_CatalogSortModel->setSourceModel(
nullptr);
3142 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3151 for (
const auto &entry : list)
3153 dbData[entry.m_Name] = entry;
3156 int rows = m_CatalogModel->rowCount();
3157 for (
int i = 0; i < rows; ++i)
3159 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
3160 auto entry = dbData.
find(name);
3161 if (entry != dbData.
end())
3164 m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
3165 if (entry->m_Flags & IMAGED_BIT)
3166 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3167 if (entry->m_Flags & PICKED_BIT)
3168 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3170 m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
3174 m_CatalogSortModel->setSourceModel(m_CatalogModel.
data());
3177void ImagingPlanner::loadImagedFile()
3179 if (m_loadingCatalog)
3187 QFile inputFile(fileName);
3198 name = tweakNames(name);
3199 if (getObject(name))
3202 auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
3205 if (matches.size() > 0)
3207 setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
3208 highlightImagedObject(matches[0],
true);
3211 QString name = m_CatalogModel->data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
3212 int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3213 QString notes = m_CatalogModel->data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
3214 saveToDB(name, flags, notes);
3218 DPRINTF(stderr,
"ooops! internal inconsitency--got an object but match didn't work");
3222 failedNames.
append(name);
3225 if (failedNames.
size() == 0)
3228 KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
3230 KSNotification::sorry(
i18n(
"Empty file"));
3234 int num = std::min((
int)failedNames.
size(), 10);
3236 for (
int i = 1; i < num; ++i)
3238 if (numSuccess == 0 && failedNames.
size() <= 10)
3239 KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
3240 else if (numSuccess == 0)
3241 KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
3242 else if (numSuccess > 0 && failedNames.
size() <= 10)
3243 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
3244 numSuccess, failedNames.
size() == 1 ?
"this" :
"these", sample));
3246 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
3247 numSuccess, failedNames.
size(), sample));
3252 KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
3256void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
3258 m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
3261bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo *info)
3264 if (
result == m_CatalogImageInfoMap.
end())
3266 if (
result->m_Filename.isEmpty())
3272void ImagingPlanner::loadCatalogViaMenu()
3274 QString startDir = Options::imagingPlannerCatalogPath();
3276 startDir = defaultDirectory();
3285void ImagingPlanner::loadCatalog(
const QString &path)
3287#ifdef THREADED_LOAD_CATALOG
3291 loadCatalogFromFile(path);
3294 m_LoadCatalogsWatcher->setFuture(m_LoadCatalogs);
3302 removeEventFilters();
3303 m_loadingCatalog =
true;
3304 loadCatalogFromFile(path);
3306 m_loadingCatalog =
false;
3307 installEventFilters();
3311CatalogImageInfo::CatalogImageInfo(
const QString &csv)
3317 if (columns.
size() < 1 || columns[0].isEmpty())
3320 m_Name = columns[column++];
3321 if (columns.
size() <= column)
return;
3322 m_Filename = columns[column++];
3323 if (columns.
size() <= column)
return;
3324 m_Author = columns[column++];
3325 if (columns.
size() <= column)
return;
3326 m_Link = columns[column++];
3327 if (columns.
size() <= column)
return;
3328 m_License = columns[column++];
3347void ImagingPlanner::loadCatalogFromFile(
QString path,
bool reset)
3349 QFile inputFile(path);
3353 m_numMissingImage = 0;
3355 int numMissingImage = 0, numWithImage = 0;
3356 if (!inputFile.exists())
3358 emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
3364 auto tz =
QTimeZone(getGeo()->TZ() * 3600);
3371 Options::setImagingPlannerCatalogPath(path);
3372 Options::self()->save();
3373 if (m_CatalogModel->rowCount() > 0)
3374 m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
3380 CatalogImageInfo info(in.readLine().trimmed());
3381 if (info.m_Name.isEmpty())
3383 if (info.m_Name.startsWith(
"LoadCatalog"))
3388 auto match = re.match(info.m_Name);
3389 if (
match.hasMatch())
3392 if (catFilename.
isEmpty())
continue;
3395 QString catFullPath = catFilename;
3396 if (!info.isAbsolute())
3402 if (catFullPath != path)
3403 loadCatalogFromFile(catFullPath,
false);
3407 objectNames.
append(info.m_Name);
3408 if (!info.m_Filename.isEmpty())
3412 if (fInfo.isRelative())
3415 addCatalogImageInfo(info);
3420 DPRINTF(stderr,
"No catalog image for %s\n", info.m_Name.toLatin1().data());
3422#ifndef THREADED_LOAD_CATALOG
3428 int num = 0, numBad = 0, iteration = 0;
3430 for (
const auto &name : objectNames)
3432 setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
3433 if (addCatalogItem(ksal, name, 0)) num++;
3440 m_numWithImage += numWithImage;
3441 m_numMissingImage += numMissingImage;
3442 DPRINTF(stderr,
"Catalog %s: %d of %d have catalog images\n",
3451 emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
3455void ImagingPlanner::sorry(
const QString &message)
3457 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 QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
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)
KCRASH_EXPORT void initialize()
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)
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