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
74#define TYPE_ROLE (Qt::UserRole + 1)
75#define HOURS_ROLE (Qt::UserRole + 2)
76#define SIZE_ROLE (Qt::UserRole + 3)
77#define ALTITUDE_ROLE (Qt::UserRole + 4)
78#define MOON_ROLE (Qt::UserRole + 5)
79#define FLAGS_ROLE (Qt::UserRole + 6)
80#define NOTES_ROLE (Qt::UserRole + 7)
82#define PICKED_BIT ImagingPlannerDBEntry::PickedBit
83#define IMAGED_BIT ImagingPlannerDBEntry::ImagedBit
84#define IGNORED_BIT ImagingPlannerDBEntry::IgnoredBit
118 case SkyObject::OPEN_CLUSTER:
119 return Options::imagingPlannerAcceptOpenCluster();
120 case SkyObject::GLOBULAR_CLUSTER:
121 return Options::imagingPlannerAcceptGlobularCluster();
122 case SkyObject::GASEOUS_NEBULA:
123 return Options::imagingPlannerAcceptNebula();
124 case SkyObject::PLANETARY_NEBULA:
125 return Options::imagingPlannerAcceptPlanetary();
126 case SkyObject::SUPERNOVA_REMNANT:
127 return Options::imagingPlannerAcceptSupernovaRemnant();
128 case SkyObject::GALAXY:
129 return Options::imagingPlannerAcceptGalaxy();
130 case SkyObject::GALAXY_CLUSTER:
131 return Options::imagingPlannerAcceptGalaxyCluster();
132 case SkyObject::DARK_NEBULA:
133 return Options::imagingPlannerAcceptDarkNebula();
135 return Options::imagingPlannerAcceptOther();
142 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
145 const bool flag = model->
data(idx, FLAGS_ROLE).
toInt() & bit;
152 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
153 int currentFlags = 0;
155 currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
157 model->
setData(idx, val, FLAGS_ROLE);
163 const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
166 const int currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
168 model->
setData(idx, val, FLAGS_ROLE);
174 if (flags & IMAGED_BIT) str.
append(
i18n(
"Imaged"));
175 if (flags & PICKED_BIT)
181 if (flags & IGNORED_BIT)
191void setupShowCallback(
bool checked,
192 void (*showOption)(
bool),
void (*showNotOption)(
bool),
193 void (*dontCareOption)(
bool),
197 Q_UNUSED(showCheckbox);
201 showNotOption(
false);
202 dontCareOption(
false);
205 Options::self()->save();
210 showNotOption(
false);
211 dontCareOption(
true);
214 Options::self()->save();
218void setupShowNotCallback(
bool checked,
219 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
222 Q_UNUSED(showNotCheckbox);
227 dontCareOption(
false);
230 Options::self()->save();
235 showNotOption(
false);
236 dontCareOption(
true);
239 Options::self()->save();
243void setupDontCareCallback(
bool checked,
244 void (*showOption)(
bool),
void (*showNotOption)(
bool),
void (*dontCareOption)(
bool),
250 showNotOption(
false);
251 dontCareOption(
true);
254 Options::self()->save();
261 showNotOption(
false);
262 dontCareOption(
true);
266 Options::self()->save();
275 "\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
280 auto match = re.match(input);
281 if (!
match.hasMatch())
284 return(
match.captured(0));
290 match = re.match(inp);
291 if (!
match.hasMatch())
294 return (
match.captured(0));
320 int column,
int role)
322 const double l =
left.siblingAtColumn(column).data(role).toDouble();
323 const double r =
right.siblingAtColumn(column).data(role).toDouble();
333 const QString l =
left.siblingAtColumn(column).data(role).toString();
334 const QString r =
right.siblingAtColumn(column).data(role).toString();
338 if (lList.
size() == 0 || rList.
size() == 0)
349 if (lList.
size() >= 2 && rList.
size() >= 2)
351 int lInt = lList[1].toInt();
352 int rInt = rList[1].toInt();
355 if (lInt > 0 && rInt > 0)
356 return -(lInt - rInt);
364void SchedulerUtils_setupJob(Ekos::SchedulerJob &job,
const QString &name,
bool isLead,
const QString &group,
365 const QString &train,
const dms &ra,
const dms &dec,
double djd,
double rotation,
const QUrl &sequenceUrl,
367 const QDateTime &completionTime,
int completionRepeats,
double minimumAltitude,
double minimumMoonSeparation,
368 bool enforceWeather,
bool enforceTwilight,
bool enforceArtificialHorizon,
bool track,
bool focus,
bool align,
bool guide)
372 job.setIsLead(isLead);
373 job.setOpticalTrain(train);
374 job.setPositionAngle(rotation);
380 job.setLeadJob(
nullptr);
382 job.setTargetCoords(ra, dec, djd);
383 job.setFITSFile(fitsUrl);
386 job.setStartupCondition(startup);
387 if (startup == Ekos::START_AT)
389 job.setStartupTime(startupTime);
392 job.setFileStartupCondition(job.getStartupCondition());
393 job.setStartAtTime(job.getStartupTime());
397 job.setMinAltitude(minimumAltitude);
398 job.setMinMoonSeparation(minimumMoonSeparation);
401 job.setEnforceWeather(enforceWeather);
403 job.setEnforceTwilight(enforceTwilight);
404 job.setEnforceArtificialHorizon(enforceArtificialHorizon);
407 job.setStepPipeline(Ekos::SchedulerJob::USE_NONE);
409 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_TRACK));
411 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_FOCUS));
413 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_ALIGN));
415 job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_GUIDE));
418 job.setFileStartupCondition(job.getStartupCondition());
419 job.setStartAtTime(job.getStartupTime());
424 job.setSequenceFile(sequenceUrl);
425 job.setCompletionCondition(completion);
426 if (completion == Ekos::FINISH_AT)
427 job.setFinishAtTime(completionTime);
428 else if (completion == Ekos::FINISH_REPEAT)
430 job.setRepeatsRequired(completionRepeats);
431 job.setRepeatsRemaining(completionRepeats);
439void setupJob(Ekos::SchedulerJob &job,
const QString name,
double minAltitude,
double minMoonSeparation,
dms ra,
dms dec,
440 bool useArtificialHorizon)
443 double rotation = 0.0;
449 SchedulerUtils_setupJob(job, name,
true,
"",
451 rotation, sequenceURL,
QUrl(),
454 minAltitude, minMoonSeparation,
455 false,
true, useArtificialHorizon,
456 true,
true,
true,
true);
460void getRunTimes(
const QDate &date,
const GeoLocation &geo,
double minAltitude,
double minMoonSeparation,
464 jobStartTimes->
clear();
465 jobEndTimes->
clear();
466 constexpr int SCHEDULE_RESOLUTION_MINUTES = 10;
467 Ekos::SchedulerJob job;
468 setupJob(job,
"temp", minAltitude, minMoonSeparation, ra, dec, useArtificialHorizon);
475 startTime.setTimeZone(tz);
476 stopTime.setTimeZone(tz);
480 while (--maxIters >= 0)
482 QDateTime s = job.getNextPossibleStartTime(startTime, SCHEDULE_RESOLUTION_MINUTES,
false, stopTime);
487 QDateTime e = job.getNextEndTime(s, SCHEDULE_RESOLUTION_MINUTES, &constraintReason, stopTime);
495 if (e.
secsTo(stopTime) < 600)
505 double minMoonSeparation,
bool useArtificialHorizon)
508 getRunTimes(date, geo, minAltitude, minMoonSeparation,
object.ra0(),
object.dec0(), useArtificialHorizon, &jobStartTimes,
510 if (jobStartTimes.
size() == 0 || jobEndTimes.
size() == 0)
514 double totalHours = 0.0;
515 for (
int i = 0; i < jobStartTimes.
size(); ++i)
516 totalHours += jobStartTimes[i].secsTo(jobEndTimes[i]) * 1.0 / 3600.0;
525int packString(
const QString &input, quint8 *p,
bool reallyPack)
528 quint32 len = str_data.
length();
529 const char *str = str_data.
data();
530 constexpr bool compatibilityMode =
false;
531 const quint8 *origP = p;
534 if (reallyPack) *p = 0xa0 | len;
537 else if (len <= std::numeric_limits<quint8>::max() &&
538 compatibilityMode ==
false)
540 if (reallyPack) *p = 0xd9;
542 if (reallyPack) *p = len;
545 else if (len <= std::numeric_limits<quint16>::max())
547 if (reallyPack) *p = 0xda;
558 if (reallyPack) memcpy(p, str, len);
559 return (p - origP) + len;
566 int size = packString(input,
nullptr,
false);
570 packString(input,
reinterpret_cast<quint8*
>(arr.
data()),
true);
580 newStr = newStr.
replace(0, 4,
"sh2-");
581 newStr = newStr.
replace(
' ',
"");
585bool downsampleImageFiles(
const QString &baseDir,
int maxHeight)
596 const QString subDir =
"REDUCED";
597 QDir directory(baseDir);
598 if (!directory.exists())
600 fprintf(stderr,
"downsampleImageFiles: Base directory doesn't exist\n");
608 fprintf(stderr,
"downsampleImageFiles: Failed making the output directory\n");
615 foreach (
QString filename, files)
620 if (img.height() > maxHeight)
629 if (!scaledImg.
save(jpgFilename,
"JPG"))
630 fprintf(stderr,
"downsampleImageFiles: Failed saving \"%s\"\n", writeFilename.
toLatin1().
data());
634 fprintf(stderr,
"downsampleImageFiles: saved \"%s\"\n", writeFilename.
toLatin1().
data());
637 fprintf(stderr,
"downsampleImageFiles: Wrote %d files\n", numSaved);
648 const int len = bInput.
size();
650 for (
int i = 0; i < len; ++i)
660 bInput.
replace(pos, 1, substitute);
668 QString massagedName = massageObjectName(name);
673 if (files.size() > 0)
674 return files[0].absoluteFilePath();
677 for (
int i = 0; i < subDirs.size(); i++)
679 QDir subDir(subDirs[i].absoluteFilePath());
681 if (files.size() > 0)
682 return files[0].absoluteFilePath();
689 if (astrobinAbbrev ==
"ACC")
691 else if (astrobinAbbrev ==
"ASACC")
693 else if (astrobinAbbrev ==
"ANCCC")
695 else if (astrobinAbbrev ==
"ANCSACC")
696 return "CC-BY-SA-NC";
700QString creativeCommonsTooltipString(
const QString &astrobinAbbrev)
702 if (astrobinAbbrev ==
"ACC")
703 return "Atribution Creative Commons";
704 else if (astrobinAbbrev ==
"ASACC")
705 return "Atribution Share-Alike Creative Commons";
706 else if (astrobinAbbrev ==
"ANCCC")
707 return "Atribution Non-Commercial Creative Commons";
708 else if (astrobinAbbrev ==
"ANCSACC")
709 return "Atribution Non-Commercial Share-Alike Creative Commons";
728 double hoursAfterDusk = 0,
double hoursBeforeDawn = 0)
734 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
736 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
742 auto end = dawn.
addSecs(-hoursBeforeDawn * 3600);
753 while (t.secsTo(end) > 0)
755 double alt = getAltitude(geo, coords, t);
761 t = t.addSecs(60 * 20);
770 m_SortColumn = HOURS_COLUMN;
774bool CatalogFilter::filterAcceptsRow(
int row,
const QModelIndex &parent)
const
778 if (!acceptType(type))
return false;
782 if (!hasEnoughHours)
return false;
786 const bool isImaged =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IMAGED_BIT;
787 const bool passesImagedConstraints = !m_ImagedConstraintsEnabled || (isImaged == m_ImagedRequired);
788 if (!passesImagedConstraints)
return false;
790 const bool isIgnored =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IGNORED_BIT;
791 const bool passesIgnoredConstraints = !m_IgnoredConstraintsEnabled || (isIgnored == m_IgnoredRequired);
792 if (!passesIgnoredConstraints)
return false;
794 const bool isPicked =
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & PICKED_BIT;
795 const bool passesPickedConstraints = !m_PickedConstraintsEnabled || (isPicked == m_PickedRequired);
796 if (!passesPickedConstraints)
return false;
799 if (m_Keyword.isEmpty() || !m_KeywordConstraintsEnabled)
return true;
801 const QString notes =
sourceModel()->data(notesIndex, NOTES_ROLE).toString();
803 const bool REMatches = m_KeywordRE.match(notes).hasMatch();
804 return (m_KeywordRequired == REMatches);
807void CatalogFilter::setMinHours(
double hours)
812void CatalogFilter::setImagedConstraints(
bool enabled,
bool required)
814 m_ImagedConstraintsEnabled = enabled;
815 m_ImagedRequired = required;
818void CatalogFilter::setPickedConstraints(
bool enabled,
bool required)
820 m_PickedConstraintsEnabled = enabled;
821 m_PickedRequired = required;
824void CatalogFilter::setIgnoredConstraints(
bool enabled,
bool required)
826 m_IgnoredConstraintsEnabled = enabled;
827 m_IgnoredRequired = required;
830void CatalogFilter::setKeywordConstraints(
bool enabled,
bool required,
const QString &keyword)
832 m_KeywordConstraintsEnabled = enabled;
833 m_KeywordRequired = required;
835 m_KeywordRE = QRegularExpression(keyword);
838void CatalogFilter::setSortColumn(
int column)
840 if (column == m_SortColumn)
841 m_ReverseSort = !m_ReverseSort;
842 m_SortColumn = column;
851 double compareVal = 0;
856 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
857 if (m_ReverseSort) compareVal = -compareVal;
861 compareVal = stringCompareFcn(left, right, TYPE_COLUMN,
Qt::DisplayRole);
862 if (m_ReverseSort) compareVal = -compareVal;
863 if (compareVal != 0)
break;
864 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
865 if (compareVal != 0)
break;
866 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
870 compareVal = floatCompareFcn(left, right, SIZE_COLUMN, SIZE_ROLE);
871 if (m_ReverseSort) compareVal = -compareVal;
872 if (compareVal != 0)
break;
873 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
874 if (compareVal != 0)
break;
875 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
877 case ALTITUDE_COLUMN:
879 compareVal = floatCompareFcn(left, right, ALTITUDE_COLUMN, ALTITUDE_ROLE);
880 if (m_ReverseSort) compareVal = -compareVal;
881 if (compareVal != 0)
break;
882 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
883 if (compareVal != 0)
break;
884 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
888 compareVal = floatCompareFcn(left, right, MOON_COLUMN, MOON_ROLE);
889 if (m_ReverseSort) compareVal = -compareVal;
890 if (compareVal != 0)
break;
891 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
892 if (compareVal != 0)
break;
893 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
895 case CONSTELLATION_COLUMN:
897 compareVal = stringCompareFcn(left, right, CONSTELLATION_COLUMN,
Qt::DisplayRole);
898 if (m_ReverseSort) compareVal = -compareVal;
899 if (compareVal != 0)
break;
900 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
901 if (compareVal != 0)
break;
902 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
906 compareVal = stringCompareFcn(left, right, COORD_COLUMN,
Qt::DisplayRole);
907 if (m_ReverseSort) compareVal = -compareVal;
908 if (compareVal != 0)
break;
909 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
910 if (compareVal != 0)
break;
911 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
916 compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
917 if (m_ReverseSort) compareVal = -compareVal;
918 if (compareVal != 0)
break;
919 compareVal = stringCompareFcn(left, right, NAME_COLUMN,
Qt::DisplayRole);
922 return compareVal < 0;
932void ImagingPlannerUI::setupIcons()
956 return KStarsData::Instance()->
geo();
959QDate ImagingPlanner::getDate()
const
961 return ui->DateEdit->date();
964ImagingPlanner::ImagingPlanner() :
QDialog(nullptr), m_manager{ CatalogsDB::dso_db_path() }
966 ui =
new ImagingPlannerUI(
this);
972 setLayout(mainLayout);
974 setWindowTitle(
i18nc(
"@title:window",
"Imaging Planner"));
977 if (Options::imagingPlannerIndependentWindow())
993void ImagingPlanner::setupHideButtons(
bool(*option)(),
void(*setOption)(
bool),
1003 Options::self()->save();
1012 Options::self()->save();
1020void ImagingPlanner::focusOnTable()
1022 ui->CatalogView->setFocus();
1025void ImagingPlanner::adjustWindowSize()
1027 const int keepWidth =
width();
1029 const int newHeight =
height();
1030 resize(keepWidth, newHeight);
1034void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox,
bool(*option)(),
void(*setOption)(
bool))
1040 Options::self()->save();
1041 m_CatalogSortModel->invalidate();
1043 ui->CatalogView->resizeColumnsToContents();
1049void ImagingPlanner::setupFilter2Buttons(
1051 bool(*yesOption)(),
bool(*noOption)(),
bool(*dontCareOption)(),
1052 void(*setYesOption)(
bool),
void(*setNoOption)(
bool),
void(*setDontCareOption)(
bool))
1058 setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1059 updateSortConstraints();
1060 m_CatalogSortModel->invalidate();
1061 ui->CatalogView->resizeColumnsToContents();
1067 setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1068 updateSortConstraints();
1069 m_CatalogSortModel->invalidate();
1070 ui->CatalogView->resizeColumnsToContents();
1074 connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
1076 setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
1077 updateSortConstraints();
1078 m_CatalogSortModel->invalidate();
1079 ui->CatalogView->resizeColumnsToContents();
1090void ImagingPlanner::updateSortConstraints()
1092 m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
1093 ui->pickedCB->isChecked());
1094 m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
1095 ui->imagedCB->isChecked());
1096 m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
1097 ui->ignoredCB->isChecked());
1098 m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
1099 ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
1103void ImagingPlanner::initialize()
1105 if (KStarsData::Instance() ==
nullptr)
1112 connect(
this, &ImagingPlanner::popupSorry,
this, &ImagingPlanner::sorry);
1115 m_CatalogModel =
new QStandardItemModel(0, LAST_COLUMN);
1118 m_CatalogModel->setHorizontalHeaderLabels(
1121 m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
1122 i18n(
"Object Name--click header to sort ascending/descending."));
1123 m_CatalogModel->horizontalHeaderItem(
1124 HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
1125 m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
1126 i18n(
"Object Type--click header to sort ascending/descending."));
1127 m_CatalogModel->horizontalHeaderItem(
1128 SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
1129 m_CatalogModel->horizontalHeaderItem(
1130 ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
1131 m_CatalogModel->horizontalHeaderItem(
1132 MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
1133 m_CatalogModel->horizontalHeaderItem(
1134 CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
1135 m_CatalogModel->horizontalHeaderItem(
1136 COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
1138 m_CatalogSortModel =
new CatalogFilter(
this);
1140 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
1141 m_CatalogSortModel->setDynamicSortFilter(
true);
1143 ui->CatalogView->setModel(m_CatalogSortModel.data());
1144 ui->CatalogView->setSortingEnabled(
false);
1145 ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
1146 ui->CatalogView->resizeColumnsToContents();
1147 ui->CatalogView->verticalHeader()->setVisible(
false);
1148 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
1151 this, &ImagingPlanner::selectionChanged);
1156 auto utc = KStarsData::Instance()->
clock()->
utc();
1157 auto localTime = getGeo()->UTtoLT(utc);
1158 ui->DateEdit->
setDate(localTime.date());
1164 setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
1165 ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
1166 ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
1173 QString selection = currentObjectName();
1177 scrollToName(selection);
1193 Options::setImagingPlannerHideAstrobinDetails(
true);
1194 setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
1195 ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
1196 ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
1197 ui->AstrobinAward->setChecked(Options::astrobinAward());
1200 Options::setAstrobinAward(checked);
1201 Options::self()->save();
1204 ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
1207 Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
1208 Options::self()->save();
1211 ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
1214 Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
1215 Options::self()->save();
1221 QPixmap(
":/images/noimage.png").scaled(ui->ImagePreview->width(), ui->ImagePreview->height(),
Qt::KeepAspectRatio,
1226 setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
1227 ui->hideImageButton, ui->showImageButton,
1228 ui->ImageFrame, ui->HiddenImageFrame);
1231 Options::setImagingPlannerHideFilters(
true);
1232 setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
1233 ui->hideFilterTypesButton, ui->showFilterTypesButton,
1234 ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
1235 setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
1236 &Options::setImagingPlannerAcceptOpenCluster);
1237 setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
1238 setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
1239 &Options::setImagingPlannerAcceptGlobularCluster);
1240 setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
1241 setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
1242 &Options::setImagingPlannerAcceptSupernovaRemnant);
1243 setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
1244 setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
1245 &Options::setImagingPlannerAcceptGalaxyCluster);
1246 setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
1247 setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
1249 setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
1250 &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
1251 &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
1253 setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
1254 &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
1255 &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
1257 setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
1258 &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
1259 &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
1260 &Options::setImagingPlannerDontCareIgnored);
1262 ui->keywordEdit->setText(Options::imagingPlannerKeyword());
1263 ui->keywordEdit->setAcceptRichText(
false);
1264 m_Keyword = Options::imagingPlannerKeyword();
1265 setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
1266 &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
1267 &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
1268 &Options::setImagingPlannerDontCareKeyword);
1273 ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
1274 m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
1275 ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
1276 m_MinMoon = Options::imagingPlannerMinMoonSeparation();
1277 ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
1278 m_MinAltitude = Options::imagingPlannerMinAltitude();
1279 ui->minHours->setValue(Options::imagingPlannerMinHours());
1280 m_MinHours = Options::imagingPlannerMinHours();
1281 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1284 if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
1286 m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
1287 Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
1288 Options::self()->save();
1294 if (m_MinMoon == ui->minMoon->value())
1296 m_MinMoon = ui->minMoon->value();
1297 Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
1298 Options::self()->save();
1304 if (m_MinAltitude == ui->minAltitude->value())
1306 m_MinAltitude = ui->minAltitude->value();
1307 Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
1308 Options::self()->save();
1314 if (m_MinHours == ui->minHours->value())
1316 m_MinHours = ui->minHours->value();
1317 Options::setImagingPlannerMinHours(ui->minHours->value());
1318 Options::self()->save();
1319 m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
1320 m_CatalogSortModel->invalidate();
1321 ui->CatalogView->resizeColumnsToContents();
1325 updateSortConstraints();
1327 m_CatalogSortModel->setMinHours(ui->minHours->value());
1329 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
1338 ui->userNotesLabel->setVisible(true);
1339 ui->userNotesEdit->setText(ui->userNotes->text());
1340 ui->userNotesEdit->setVisible(true);
1341 ui->userNotesEditButton->setVisible(false);
1342 ui->userNotesDoneButton->setVisible(true);
1343 ui->userNotes->setVisible(false);
1344 ui->userNotesLabel->setVisible(true);
1345 ui->userNotesOpenLink->setVisible(false);
1346 ui->userNotesOpenLink2->setVisible(false);
1347 ui->userNotesOpenLink3->setVisible(false);
1353 QString urlString = findUrl(ui->userNotes->text());
1354 if (urlString.isEmpty())
1356 QDesktopServices::openUrl(QUrl(urlString));
1361 QString urlString = findUrl(ui->userNotes->text(), 2);
1362 if (urlString.isEmpty())
1364 QDesktopServices::openUrl(QUrl(urlString));
1369 QString urlString = findUrl(ui->userNotes->text(), 3);
1370 if (urlString.isEmpty())
1372 QDesktopServices::openUrl(QUrl(urlString));
1381 m_CatalogSortModel->setSortColumn(column);
1382 m_CatalogSortModel->invalidate();
1383 ui->CatalogView->resizeColumnsToContents();
1392 qRegisterMetaType<QList<QStandardItem *>>(
"QList<QStandardItem *>");
1393 connect(
this, &ImagingPlanner::addRow,
this, &ImagingPlanner::addRowSlot);
1403 installEventFilters();
1406void ImagingPlanner::installEventFilters()
1410 ui->SearchText->installEventFilter(
this);
1411 ui->userNotesEdit->installEventFilter(
this);
1412 ui->keywordEdit->installEventFilter(
this);
1413 ui->ImagePreviewCreditLink->installEventFilter(
this);
1414 ui->ImagePreviewCredit->installEventFilter(
this);
1415 ui->ImagePreview->installEventFilter(
this);
1416 ui->CatalogView->viewport()->installEventFilter(
this);
1417 ui->CatalogView->installEventFilter(
this);
1420void ImagingPlanner::removeEventFilters()
1422 ui->SearchText->removeEventFilter(
this);
1423 ui->userNotesEdit->removeEventFilter(
this);
1424 ui->keywordEdit->removeEventFilter(
this);
1425 ui->ImagePreviewCreditLink->removeEventFilter(
this);
1426 ui->ImagePreviewCredit->removeEventFilter(
this);
1427 ui->ImagePreview->removeEventFilter(
this);
1428 ui->CatalogView->viewport()->removeEventFilter(
this);
1429 ui->CatalogView->removeEventFilter(
this);
1432void ImagingPlanner::openOptionsMenu()
1434 QSharedPointer<ImagingPlannerOptions> options(
new ImagingPlannerOptions(
this));
1440void ImagingPlanner::getHelp()
1450 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/MESSIER", 300))
1451 fprintf(stderr,
"downsampling succeeded\n");
1453 fprintf(stderr,
"downsampling failed\n");
1455 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/OTHER", 300))
1456 fprintf(stderr,
"downsampling succeeded\n");
1458 fprintf(stderr,
"downsampling failed\n");
1460 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/CALDWELL", 300))
1461 fprintf(stderr,
"downsampling succeeded\n");
1463 fprintf(stderr,
"downsampling failed\n");
1465 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/AWARDS", 300))
1466 fprintf(stderr,
"downsampling succeeded\n");
1468 fprintf(stderr,
"downsampling failed\n");
1470 if (downsampleImageFiles(
"/home/hy/Desktop/SharedFolder/PLANNER_IMAGES/HERSCHEL12", 300))
1471 fprintf(stderr,
"downsampling succeeded\n");
1473 fprintf(stderr,
"downsampling failed\n");
1476 const QUrl url(
"https://docs.kde.org/trunk5/en/kstars/kstars/kstars.pdf#tool-imaging-planner");
1481KSMoon *ImagingPlanner::getMoon()
1483 if (KStarsData::Instance() ==
nullptr)
1489 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1490 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1492 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1493 KSNumbers numbers(midnight.
djd());
1494 moon->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1500void ImagingPlanner::updateMoon()
1502 KSMoon *moon = getMoon();
1507 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1508 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1509 CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
1510 KSNumbers numbers(midnight.
djd());
1512 sun->
updateCoords(&numbers,
true, getGeo()->lat(), &LST,
true);
1516 ui->moonPercentLabel->setText(QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0,
'f', 0));
1519bool ImagingPlanner::scrollToName(
const QString &name)
1523 QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0),
Qt::EditRole,
1525 if(matchList.count() >= 1)
1528 for (
int i = 0; i < matchList.count(); i++)
1530 QString nn = ui->CatalogView->model()->data(matchList[i],
Qt::DisplayRole).toString();
1537 ui->CatalogView->scrollTo(matchList[bestIndex]);
1538 ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
1544void ImagingPlanner::searchSlot()
1546 if (m_loadingCatalog)
1548 QString origName = ui->SearchText->toPlainText().trimmed();
1549 QString
name = tweakNames(origName);
1550 ui->SearchText->setPlainText(name);
1554 if (!scrollToName(name))
1555 KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
1558 ui->SearchText->clear();
1559 ui->SearchText->setPlainText(
"");
1562void ImagingPlanner::initUserNotes()
1564 ui->userNotesLabel->setVisible(
true);
1565 ui->userNotesEdit->setVisible(
false);
1566 ui->userNotesEditButton->setVisible(
true);
1567 ui->userNotesDoneButton->setVisible(
false);
1568 ui->userNotes->setVisible(
true);
1569 ui->userNotesLabel->setVisible(
true);
1570 ui->userNotesOpenLink->setVisible(
false);
1571 ui->userNotesOpenLink2->setVisible(
false);
1572 ui->userNotesOpenLink3->setVisible(
false);
1575void ImagingPlanner::disableUserNotes()
1577 ui->userNotesEdit->setVisible(
false);
1578 ui->userNotesEditButton->setVisible(
false);
1579 ui->userNotesDoneButton->setVisible(
false);
1580 ui->userNotes->setVisible(
false);
1581 ui->userNotesLabel->setVisible(
false);
1582 ui->userNotesOpenLink->setVisible(
false);
1583 ui->userNotesOpenLink2->setVisible(
false);
1584 ui->userNotesOpenLink3->setVisible(
false);
1587void ImagingPlanner::userNotesEditFinished()
1589 const QString ¬es = ui->userNotesEdit->toPlainText().
trimmed();
1590 ui->userNotes->setText(notes);
1591 ui->userNotesLabel->setVisible(notes.
isEmpty());
1592 ui->userNotesEdit->setVisible(
false);
1593 ui->userNotesEditButton->setVisible(
true);
1594 ui->userNotesDoneButton->setVisible(
false);
1595 ui->userNotes->setVisible(
true);
1596 ui->userNotesLabel->setVisible(
true);
1597 setCurrentObjectNotes(notes);
1598 setupNotesLinks(notes);
1600 auto o = currentCatalogObject();
1602 saveToDB(currentObjectName(), currentObjectFlags(), notes);
1605void ImagingPlanner::updateNotes(
const QString ¬es)
1607 ui->userNotes->setMaximumWidth(ui->RightPanel->width() - 125);
1609 ui->userNotes->setText(notes);
1610 ui->userNotesLabel->setVisible(notes.
isEmpty());
1611 setupNotesLinks(notes);
1614void ImagingPlanner::setupNotesLinks(
const QString ¬es)
1616 QString
link = findUrl(notes);
1617 ui->userNotesOpenLink->setVisible(!
link.isEmpty());
1618 if (!
link.isEmpty())
1619 ui->userNotesOpenLink->setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
1621 link = findUrl(notes, 2);
1622 ui->userNotesOpenLink2->setVisible(!
link.isEmpty());
1623 if (!
link.isEmpty())
1624 ui->userNotesOpenLink2->setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
1626 link = findUrl(notes, 3);
1627 ui->userNotesOpenLink3->setVisible(!
link.isEmpty());
1628 if (!
link.isEmpty())
1629 ui->userNotesOpenLink3->setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
1639 std::list<CatalogObject> objs =
1640 m_manager.find_objects_by_name(filteredName, 1,
true);
1644 int abellNumber = -1;
1645 bool abellPlanetary =
false;
1649 auto match = abellRE.match(filteredName);
1650 if (
match.hasMatch())
1652 abellNumber =
match.captured(1).toInt();
1653 if (abellNumber <= 86)
1654 abellPlanetary =
true;
1657 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1660 if (objs.size() == 0 && filteredName.
size() > 0)
1663 const QString capitalized = capitalize(filteredName);
1664 objs = m_manager.find_objects_by_name(capitalized, 1,
true);
1665 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1668 if (objs.size() == 0)
1671 const QString lowerCase = filteredName.
toLower();
1672 objs = m_manager.find_objects_by_name(lowerCase, 1,
true);
1673 if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
1682 QString name2 = filteredName;
1684 objs = m_manager.find_objects_by_name(name2, 1,
true);
1688 QString name2 = filteredName;
1690 objs = m_manager.find_objects_by_name(name2, 1,
true);
1693 if (objs.size() == 0 && !abellPlanetary)
1694 objs = m_manager.find_objects_by_name(filteredName.
toLower(), 20,
false);
1695 if (objs.size() == 0)
1697 QElapsedTimer timer;
1702 QString resolverName = filteredName;
1706 resolverName = QString(
"PN A66 %1").
arg(abellNumber);
1713 CatalogObject
object = cedata.second;
1716 if (
object.
name() ==
object.name2())
1717 object.setName2(filteredName);
1718 object.setName(filteredName);
1721 m_manager.add_object(CatalogsDB::user_catalog_id,
object);
1722 const auto &added_object =
1723 m_manager.get_object(
object.getId(), CatalogsDB::user_catalog_id);
1725 if (added_object.first)
1727 *catObject = KStarsData::Instance()
1729 ->catalogsComponent()
1733 DPRINTF(stderr,
"***** Found %s using name resolver (%.1fs)\n",
name.
toLatin1().
data(),
1738 if (objs.size() == 0)
1742 *catObject = objs.front();
1743 if (objs.size() > 1)
1745 QString addSpace = filteredName;
1747 for (
const auto &obj : objs)
1767 auto o = m_CatalogHash.find(lName);
1768 if (o == m_CatalogHash.end())
1773void ImagingPlanner::clearObjects()
1779 m_CatalogHash.clear();
1787 if (getObject(lName) !=
nullptr)
1789 DPRINTF(stderr,
"Didn't add \"%s\" because it's already there\n",
name.
toLatin1().
data());
1794 if (!getKStarsCatalogObject(lName, &o))
1796 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
1799 m_CatalogHash[lName] = o;
1800 return &(m_CatalogHash[lName]);
1805bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal,
const QString &name,
int flags)
1807 CatalogObject *
object = addObject(name);
1808 if (
object ==
nullptr)
1811 auto getItemWithUserRole = [](
const QString & itemText) -> QStandardItem *
1813 QStandardItem *ret =
new QStandardItem(itemText);
1820 QList<QStandardItem *> itemList;
1821 for (
int i = 0; i < LAST_COLUMN; ++i)
1823 if (i == NAME_COLUMN)
1825 itemList.
append(getItemWithUserRole(name));
1827 else if (i == HOURS_COLUMN)
1829 double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
1830 ui->useArtificialHorizon->isChecked());
1831 auto hoursItem = getItemWithUserRole(QString(
"%1").arg(runHours, 0,
'f', 1));
1832 hoursItem->setData(runHours, HOURS_ROLE);
1833 itemList.
append(hoursItem);
1835 else if (i == TYPE_COLUMN)
1837 auto typeItem = getItemWithUserRole(QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
1838 typeItem->setData(object->
type(), TYPE_ROLE);
1839 itemList.
append(typeItem);
1841 else if (i == SIZE_COLUMN)
1843 double size = std::max(object->
a(), object->
b());
1844 auto sizeItem = getItemWithUserRole(QString(
"%1'").arg(
size, 0,
'f', 1));
1845 sizeItem->setData(
size, SIZE_ROLE);
1846 itemList.
append(sizeItem);
1848 else if (i == ALTITUDE_COLUMN)
1850 const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
1851 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
1852 auto altItem = getItemWithUserRole(QString(
"%1º").arg(altitude, 0,
'f', 0));
1853 altItem->setData(altitude, ALTITUDE_ROLE);
1854 itemList.
append(altItem);
1856 else if (i == MOON_COLUMN)
1858 KSMoon *moon = getMoon();
1864 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1865 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1867 KSNumbers numbers(midnight.
djd());
1871 auto moonItem = getItemWithUserRole(QString(
"%1º").arg(separation, 0,
'f', 0));
1872 moonItem->setData(separation, MOON_ROLE);
1873 itemList.
append(moonItem);
1877 auto moonItem = getItemWithUserRole(QString(
""));
1878 moonItem->setData(-1, MOON_ROLE);
1881 else if (i == CONSTELLATION_COLUMN)
1883 QString cname = KStarsData::Instance()
1885 ->constellationBoundary()
1886 ->constellationName(
object);
1888 auto constellationItem = getItemWithUserRole(cname);
1889 itemList.
append(constellationItem);
1891 else if (i == COORD_COLUMN)
1893 itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
1895 else if (i == FLAGS_COLUMN)
1897 QStandardItem *flag = getItemWithUserRole(
"flag");
1898 flag->
setData(flags, FLAGS_ROLE);
1901 else if (i == NOTES_COLUMN)
1903 QStandardItem *notes = getItemWithUserRole(
"notes");
1904 notes->
setData(QString(), NOTES_ROLE);
1909 DPRINTF(stderr,
"Bug in addCatalogItem() !\n");
1914 emit addRow(itemList);
1920 m_CatalogModel->appendRow(itemList);
1924void ImagingPlanner::recompute()
1926 setStatus(
i18n(
"Updating tables..."));
1929 m_CatalogSortModel->setSourceModel(
nullptr);
1931 QElapsedTimer timer;
1934 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1935 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1936 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
1937 KSAlmanac ksal(ut, getGeo());
1939 for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
1941 const QString &
name = m_CatalogModel->item(i, 0)->text();
1942 const CatalogObject *catalogEntry = getObject(name);
1943 if (catalogEntry ==
nullptr)
1945 DPRINTF(stderr,
"************* Couldn't find \"%s\"\n",
name.
toLatin1().
data());
1948 double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
1949 ui->minMoon->value(), ui->useArtificialHorizon->isChecked());
1950 QString hoursText = QString(
"%1").arg(runHours, 0,
'f', 1);
1951 QStandardItem *hItem =
new QStandardItem(hoursText);
1954 hItem->
setData(runHours, HOURS_ROLE);
1955 m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
1958 const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
1959 const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
1960 QString altText = QString(
"%1º").arg(altitude, 0,
'f', 0);
1961 auto altItem =
new QStandardItem(altText);
1963 altItem->setData(altitude, ALTITUDE_ROLE);
1964 m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
1966 KSMoon *moon = getMoon();
1972 auto tz = QTimeZone(getGeo()->TZ() * 3600);
1973 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
1975 KSNumbers numbers(midnight.
djd());
1979 QString moonText = QString(
"%1º").arg(separation, 0,
'f', 0);
1980 auto moonItem =
new QStandardItem(moonText);
1982 moonItem->setData(separation, MOON_ROLE);
1983 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1987 auto moonItem =
new QStandardItem(
"");
1989 moonItem->setData(-1, MOON_ROLE);
1990 m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
1994 const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
1996 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
1997 const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
1999 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
2002 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
2004 DPRINTF(stderr,
"Recompute took %.1fs\n", timer.
elapsed() / 1000.0);
2011void ImagingPlanner::checkTargets()
2013 FlagComponent *flags = KStarsData::Instance()->
skyComposite()->flags();
2015 fprintf(stderr,
"****************** check objects (%d)***************\n", flags->
size());
2016 for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
2017 fprintf(stderr,
"Removed, now %d\n", flags->
size());
2018 QList<QString> targets;
2019 int rows = m_CatalogModel->rowCount();
2023 for (
int i = 0; i < rows; ++i)
2025 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
2027 accepted[i] = getObject(name) !=
nullptr;
2029 auto object = getObject(name);
2032 flags->
add(SkyPoint(object->
ra(), object->
dec()),
"J2000.0",
"", name,
Qt::red);
2033 fprintf(stderr,
"%d ", i);
2037 for (
int i = 0; i < targets.
size(); ++i)
2043 object->setRA(object->
ra0());
2044 object->setDec(object->
dec0());
2045 for (
int j = 0; j < targets.
size(); ++j)
2047 if (i == j)
continue;
2049 auto name2 = targets[j];
2050 auto object2 = getObject(name2);
2051 object2->setRA(object2->ra0());
2052 object2->setDec(object2->dec0());
2053 const dms dist =
object->angularDistanceTo(object2);
2054 const double arcsecDist = dist.
Degrees() * 3600.0;
2055 if (arcsecDist < 120)
2057 fprintf(stderr,
"dist %10s (%s %s) to %10s (%s %s) = %.0f\" %s\n",
2062 object2->ra().toHMSString().toLatin1().data(),
2063 object2->dec().toDMSString().toLatin1().data(),
2070 fprintf(stderr,
"Done\n");
2077QString ImagingPlanner::defaultDirectory()
const
2085QString ImagingPlanner::findDefaultCatalog()
const
2087 const QFileInfoList subDirs = QDir(defaultDirectory()).entryInfoList(
2089 for (
int i = 0; i < subDirs.size(); i++)
2092 const QDir subDir(subDirs[i].absoluteFilePath());
2093 const QStringList csvFilter({
"*.csv"});
2095 if (files.size() > 0)
2100 for (
const auto &file : files)
2103 firstFile = file.absoluteFilePath();
2105 return file.absoluteFilePath();
2114void ImagingPlanner::loadInitialCatalog()
2116 QString catalog = Options::imagingPlannerCatalogPath();
2118 catalog = findDefaultCatalog();
2121 KSNotification::sorry(
i18n(
"You need to load a catalog to start using this tool.\nSee Data -> Download New Data..."));
2122 setStatus(
i18n(
"No Catalog!"));
2125 loadCatalog(catalog);
2128void ImagingPlanner::setStatus(
const QString &message)
2130 ui->statusLabel->setText(message);
2133void ImagingPlanner::catalogLoaded()
2135 DPRINTF(stderr,
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
2141 ui->CatalogView->setColumnHidden(FLAGS_COLUMN,
true);
2142 ui->CatalogView->setColumnHidden(NOTES_COLUMN,
true);
2144 m_CatalogSortModel->invalidate();
2146 ui->CatalogView->resizeColumnsToContents();
2149 auto index = ui->CatalogView->
model()->
index(0, 0);
2151 ui->CatalogView->selectionModel()->select(index,
2153 ui->CatalogView->setFocus();
2160void ImagingPlanner::updateStatus()
2162 if (currentObjectName().isEmpty())
2164 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2165 const int totalCatalogObjects = m_CatalogModel->rowCount();
2167 if (numDisplayedObjects > 0)
2168 setStatus(
i18n(
"Select an object."));
2169 else if (totalCatalogObjects > 0)
2170 setStatus(
i18n(
"Check Filters to unhide objects."));
2172 setStatus(
i18n(
"Load a Catalog."));
2182 if (m_initialShow ==
false)
2184 m_initialShow =
true;
2192void ImagingPlanner::slotClose()
2198QUrl ImagingPlanner::getAstrobinUrl(
const QString &target,
bool requireAwards,
bool requireSomeFilters,
double minRadius,
2201 QString myQuery = QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").arg(target);
2204 auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
2205 QDate today = localTime.date();
2206 myQuery.
append(QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
2209 myQuery.
append(QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
2211 if (requireSomeFilters)
2212 myQuery.
append(QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
2214 if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
2215 myQuery.
append(QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
2220 QByteArray packed = pack(b);
2222 QByteArray compressed = qCompress(packed).remove(0, 4);
2224 QByteArray b64 = compressed.
toBase64();
2226 replaceByteArrayChars(b64,
'+', QByteArray(
"%2B"));
2227 replaceByteArrayChars(b64,
'=', QByteArray(
"%3D"));
2228 replaceByteArrayChars(b,
'"', QByteArray(
"%22"));
2229 replaceByteArrayChars(b,
':', QByteArray(
"%3A"));
2230 replaceByteArrayChars(b,
'[', QByteArray(
"%5B"));
2231 replaceByteArrayChars(b,
']', QByteArray(
"%5D"));
2232 replaceByteArrayChars(b,
',', QByteArray(
"%2C"));
2233 replaceByteArrayChars(b,
'\'', QByteArray(
"%27"));
2234 replaceByteArrayChars(b,
'{', QByteArray(
"%7B"));
2235 replaceByteArrayChars(b,
'}', QByteArray(
"%7D"));
2237 QString url = QString(
"https://app.astrobin.com/search?p=%1").arg(b64.
toStdString().c_str());
2241void ImagingPlanner::popupAstrobin(
const QString &target)
2243 QString newStr = massageObjectName(target);
2246 const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(),
false, Options::astrobinMinRadius(),
2247 Options::astrobinMaxRadius());
2253void ImagingPlanner::searchNGCICImages()
2256 auto o = currentCatalogObject();
2259 fprintf(stderr,
"NULL object sent to searchNGCICImages.\n");
2265 num = o->name().mid(3).toInt();
2266 QString urlString = QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3").arg(num / 100).arg(
2267 num % 100 < 50 ?
"" :
"a").arg(num);
2273 num = o->name().mid(2).toInt();
2274 QString urlString = QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3").
arg(num / 100).
arg(
2275 num % 100 < 50 ?
"" :
"a").
arg(num);
2281void ImagingPlanner::searchSimbad()
2284 QString
name = currentObjectName();
2287 name.
replace(QRegularExpression(
"sh2\\s*"),
"sh2-");
2289 name.
replace(QRegularExpression(
"hickson\\s*"),
"HCG");
2293 QString urlStr = QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1"
2294 "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
2300void ImagingPlanner::searchWikipedia()
2303 QString wikipediaAddress =
"https://en.wikipedia.org";
2304 QString
name = currentObjectName();
2307 fprintf(stderr,
"NULL object sent to Wikipedia.\n");
2311 QString massagedName =
name;
2313 massagedName = QString(
"Messier_%1").
arg(
name.
mid(2, -1));
2315 massagedName = QString(
"NGC_%1").
arg(
name.
mid(4, -1));
2317 massagedName = QString(
"IC_%1").
arg(
name.
mid(3, -1));
2319 massagedName = QString(
"sh2-%1").
arg(
name.
mid(4, -1));
2321 massagedName = QString(
"Abell_%1").
arg(
name.
mid(6, -1));
2324 QString backupSearch = QString(
"%1/w/index.php?search=%2")
2325 .arg(wikipediaAddress).arg(massageObjectName(name));
2329 QUrl(QString(
"%1/wiki/%2").arg(wikipediaAddress).arg(massagedName)));
2332void ImagingPlanner::searchAstrobin()
2335 QString
name = currentObjectName();
2338 popupAstrobin(name);
2341bool ImagingPlanner::eventFilter(
QObject * obj,
QEvent * event)
2343 if (m_loadingCatalog)
2348 m_InitialLoad =
false;
2349 setStatus(
i18n(
"Loading Catalogs..."));
2355 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>(
event);
2356 if ((obj == ui->CatalogView->viewport()) &&
2361 int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
2362 QStringList selectedNames;
2363 for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
2365 selectedNames.
append(r.siblingAtColumn(0).
data().toString());
2366 bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
2367 if (isPicked) numPicked++;
2368 else numNotPicked++;
2369 bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
2370 if (isImaged) numImaged++;
2371 else numNotImaged++;
2372 bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
2373 if (isIgnored) numIgnored++;
2374 else numNotIgnored++;
2377 if (selectedNames.
size() == 0)
2381 m_PopupMenu =
new ImagingPlannerPopup;
2383 const bool imaged = numImaged > 0;
2384 const bool picked = numPicked > 0;
2385 const bool ignored = numIgnored > 0;
2386 m_PopupMenu->init(
this, selectedNames,
2387 (numImaged > 0 && numNotImaged > 0) ?
nullptr : &imaged,
2388 (numPicked > 0 && numNotPicked > 0) ?
nullptr : &picked,
2389 (numIgnored > 0 && numNotIgnored > 0) ?
nullptr : &ignored);
2391 m_PopupMenu->popup(
pos);
2395 userNotesEditFinished();
2398 keywordEditFinished();
2409 keywordEditFinished();
2410 ui->keywordEdit->clearFocus();
2433 else if ((obj == ui->ImagePreview ||
2434 obj == ui->ImagePreviewCredit ||
2435 obj == ui->ImagePreviewCreditLink) &&
2438 if (!ui->ImagePreviewCreditLink->text().isEmpty())
2440 QUrl url(ui->ImagePreviewCreditLink->text());
2448void ImagingPlanner::keywordEditFinished()
2450 QString kwd = ui->keywordEdit->toPlainText().trimmed();
2451 ui->keywordEdit->clear();
2452 ui->keywordEdit->setText(kwd);
2453 if (m_Keyword != kwd)
2456 Options::setImagingPlannerKeyword(kwd);
2457 Options::self()->save();
2458 updateSortConstraints();
2459 m_CatalogSortModel->invalidate();
2460 ui->CatalogView->resizeColumnsToContents();
2465void ImagingPlanner::setDefaultImage()
2467 ui->ImagePreview->setPixmap(m_NoImagePixmap);
2468 ui->ImagePreview->update();
2469 ui->ImagePreviewCredit->setText(
"");
2470 ui->ImagePreviewCreditLink->setText(
"");
2475 if (m_loadingCatalog)
2478 Q_UNUSED(deselected);
2479 if (selected.
indexes().size() == 0)
2487 auto selection = selected.
indexes()[0];
2488 QString
name = selection.
data().toString();
2489 CatalogObject *
object = getObject(name);
2490 if (
object ==
nullptr)
2497 ui->ImagePreviewCredit->setText(
"");
2498 ui->ImagePreviewCreditLink->setText(
"");
2501 CatalogImageInfo catalogImageInfo;
2502 if (findCatalogImageInfo(name, &catalogImageInfo))
2504 QString filename = catalogImageInfo.m_Filename;
2505 if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
2507 QString imageFullPath = filename;
2508 if (QFileInfo(filename).isRelative())
2510 QString catDir = QFileInfo(Options::imagingPlannerCatalogPath()).absolutePath();
2511 imageFullPath = QString(
"%1%2%3").
arg(catDir)
2514 if (!QFile(imageFullPath).exists())
2515 DPRINTF(stderr,
"Image for \"%s\" -- \"%s\" doesn't exist\n",
2519 if (!catalogImageInfo.m_Link.
isEmpty())
2521 ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
2522 ui->ImagePreview->setToolTip(
"Click to see original");
2523 ui->ImagePreviewCreditLink->setToolTip(
"Click to see original");
2527 ui->ImagePreviewCreditLink->setText(
"");
2528 ui->ImagePreview->setToolTip(
"");
2529 ui->ImagePreviewCreditLink->setToolTip(
"");
2532 if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
2534 ui->ImagePreviewCredit->setText(
2535 QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
2536 .arg(creativeCommonsString(catalogImageInfo.m_License)));
2537 ui->ImagePreviewCredit->setToolTip(
2538 QString(
"Original image license: %1")
2539 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2541 else if (!catalogImageInfo.m_Author.
isEmpty())
2543 ui->ImagePreviewCredit->setText(
2544 QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
2545 ui->ImagePreviewCredit->setToolTip(
"");
2547 else if (!catalogImageInfo.m_License.
isEmpty())
2549 ui->ImagePreviewCredit->setText(
2550 QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
2551 ui->ImagePreviewCredit->setToolTip(
2552 QString(
"Original image license: %1")
2553 .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
2557 ui->ImagePreviewCredit->setText(
"");
2558 ui->ImagePreviewCredit->setToolTip(
"");
2564 object->load_image();
2565 auto image =
object->image();
2571 const QString foundFilename = findObjectImage(name);
2574 constexpr int thumbHeight = 300, thumbWidth = 400;
2575 const QImage img = QImage(foundFilename);
2576 const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
2578 ui->ImagePreview->setPixmap(
2592void ImagingPlanner::updateDisplays()
2597 if (!currentCatalogObject())
2599 if (ui->CatalogView->model()->rowCount() > 0)
2601 auto index = ui->CatalogView->
model()->
index(0, 0);
2602 ui->CatalogView->selectionModel()->select(index,
2607 auto object = currentCatalogObject();
2610 updateDetails(*
object, currentObjectFlags());
2611 updateNotes(currentObjectNotes());
2612 plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
2619void ImagingPlanner::updateDetails(
const CatalogObject &
object,
int flags)
2621 ui->infoObjectName->setText(
object.
name());
2622 ui->infoSize->setText(QString(
"%1' x %2'").arg(
object.a(), 0,
'f', 1).arg(
object.b(), 0,
'f', 1));
2624 QPalette
palette = ui->infoObjectLongName->palette();
2627 ui->infoObjectLongName->setPalette(
palette);
2628 if (
object.longname().isEmpty() || (
object.longname() ==
object.
name()))
2629 ui->infoObjectLongName->clear();
2631 ui->infoObjectLongName->setText(QString(
"(%1)").arg(
object.longname()));
2635 auto noon = KStarsDateTime(getDate(), QTime(12, 0, 0));
2636 QTime riseTime =
object.riseSetTime(noon, getGeo(),
true);
2637 QTime setTime =
object.riseSetTime(noon, getGeo(),
false);
2638 QTime transitTime =
object.transitTime(noon, getGeo());
2639 dms transitAltitude =
object.transitAltitude(noon, getGeo());
2642 KSMoon *moon = getMoon();
2645 const double separation = ui->CatalogView->selectionModel()->currentIndex()
2646 .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
2648 if (separation >= 0)
2649 moonString = QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0,
'f', 1);
2652 QString riseSetString;
2654 riseSetString = QString(
"%1 %2 @ %3º")
2659 riseSetString = QString(
"%1 %2")
2663 riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
2670 riseSetString = QString(
"%1 %2")
2674 riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
2681 riseSetString = QString(
"%1 %2 %3 %4")
2687 riseSetString = QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
2695 if (moonString.
size() > 0)
2696 riseSetString.
append(QString(
", %1").arg(moonString));
2697 ui->infoRiseSet->setText(riseSetString);
2699 palette = ui->infoObjectFlags->palette();
2701 ui->infoObjectFlags->setPalette(
palette);
2702 ui->infoObjectFlags->setText(flagString(flags));
2711void ImagingPlanner::plotAltitudeGraph(
const QDate &date,
const dms &ra,
const dms &dec)
2713 auto altitudeGraph = ui->altitudeGraph;
2714 altitudeGraph->setAltitudeAxis(-20.0, 90.0);
2717 QVector<QDateTime> jobStartTimes, jobEndTimes;
2718 getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked(),
2719 &jobStartTimes, &jobEndTimes);
2721 auto tz = QTimeZone(getGeo()->TZ() * 3600);
2722 KStarsDateTime midnight = KStarsDateTime(date.
addDays(1), QTime(0, 1));
2725 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
2726 KSAlmanac ksal(ut, getGeo());
2727 QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
2729 QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
2732 Ekos::SchedulerJob job;
2733 setupJob(job,
"temp", ui->minAltitude->value(), ui->minMoon->value(), ra, dec, ui->useArtificialHorizon->isChecked());
2735 QVector<double> times, alts;
2736 QDateTime plotStart = dusk;
2741 plotStart = plotStart.
addSecs(-1 * 3600);
2744 auto plotEnd = dawn.
addSecs(1 * 3600);
2747 while (t.secsTo(plotEnd) > 0)
2749 SkyPoint coords = job.getTargetCoords();
2750 double alt = getAltitude(getGeo(), coords, t);
2752 double hour = midnight.
secsTo(t) / 3600.0;
2754 t = t.addSecs(60 * 10);
2757 altitudeGraph->plot(getGeo(), &ksal, times, alts,
false);
2759 for (
int i = 0; i < jobStartTimes.
size(); ++i)
2761 auto startTime = jobStartTimes[i];
2762 auto stopTime = jobEndTimes[i];
2763 if (startTime < plotStart) startTime = plotStart;
2764 if (stopTime > plotEnd) stopTime = plotEnd;
2767 stopTime.setTimeZone(tz);
2769 QVector<double> runTimes, runAlts;
2774 while (t.secsTo(stopTime) > 0)
2776 SkyPoint coords = job.getTargetCoords();
2777 double alt = getAltitude(getGeo(), coords, t);
2779 double hour = midnight.
secsTo(t) / 3600.0;
2781 t = t.addSecs(60 * 10);
2783 altitudeGraph->plot(getGeo(), &ksal, runTimes, runAlts,
true);
2787void ImagingPlanner::updateCounts()
2789 const int numDisplayedObjects = m_CatalogSortModel->rowCount();
2790 const int totalCatalogObjects = m_CatalogModel->rowCount();
2791 if (numDisplayedObjects == 1)
2792 ui->tableCount->setText(QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
2794 ui->tableCount->setText(QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
2797void ImagingPlanner::moveBackOneDay()
2800 QString selection = currentObjectName();
2801 ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
2805 scrollToName(selection);
2808void ImagingPlanner::moveForwardOneDay()
2810 QString selection = currentObjectName();
2811 ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
2815 scrollToName(selection);
2818QString ImagingPlanner::currentObjectName()
const
2820 QString
name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).
data(
2827 QString
name = currentObjectName();
2828 return getObject(name);
2833void ImagingPlanner::objectDetails()
2835 CatalogObject *current = currentCatalogObject();
2836 if (current ==
nullptr)
2838 auto ut = KStarsData::Instance()->
ut();
2840 QPointer<DetailDialog> dd =
2846void ImagingPlanner::centerOnSkymap()
2848 if (!Options::imagingPlannerCenterOnSkyMap())
2850 reallyCenterOnSkymap();
2853void ImagingPlanner::reallyCenterOnSkymap()
2855 CatalogObject *current = currentCatalogObject();
2856 if (current ==
nullptr)
2862 DPRINTF(stderr,
"found a 0,0 object\n");
2867 KStarsDateTime time = KStarsData::Instance()->
clock()->
utc();
2868 dms lst = getGeo()->GSTtoLST(time.
gst());
2873 bool keepGround = Options::showGround();
2874 bool keepAnimatedSlew = Options::useAnimatedSlewing();
2875 Options::setShowGround(
false);
2876 Options::setUseAnimatedSlewing(
false);
2882 Options::setShowGround(keepGround);
2883 Options::setUseAnimatedSlewing(keepAnimatedSlew);
2886void ImagingPlanner::setSelection(
int flag,
bool enabled)
2888 auto rows = ui->CatalogView->selectionModel()->selectedRows();
2897 QList<QModelIndex> sourceIndeces;
2898 for (
int i = 0; i < rows.size(); ++i)
2900 auto proxyIndex = rows[i].siblingAtColumn(FLAGS_COLUMN);
2901 auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
2902 sourceIndeces.
append(sourceIndex);
2905 for (
int i = 0; i < sourceIndeces.
size(); ++i)
2907 auto &sourceIndex = sourceIndeces[i];
2911 setFlag(sourceIndex, flag, m_CatalogModel.data());
2913 clearFlag(sourceIndex, flag, m_CatalogModel.data());
2915 QString
name = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
2916 int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
2917 QString notes = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).
toString();
2918 saveToDB(name, flags, notes);
2920 if (flag == IMAGED_BIT)
2921 highlightImagedObject(sourceIndex,
enabled);
2922 if (flag == PICKED_BIT)
2923 highlightPickedObject(sourceIndex,
enabled);
2928void ImagingPlanner::highlightImagedObject(
const QModelIndex &index,
bool imaged)
2931 QColor m_DefaultCellBackground(36, 35, 35);
2932 QColor m_ImagedObjectBackground(10, 65, 10);
2933 QString themeName = KSTheme::Manager::instance()->currentThemeName().
toLatin1().
data();
2934 if (themeName ==
"High Key" || themeName ==
"Default" || themeName ==
"White Balance")
2936 m_DefaultCellBackground = QColor(240, 240, 240);
2937 m_ImagedObjectBackground = QColor(180, 240, 180);
2939 for (
int col = 0; col < LAST_COLUMN; ++col)
2942 m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground,
Qt::BackgroundRole);
2946void ImagingPlanner::highlightPickedObject(
const QModelIndex &index,
bool picked)
2948 for (
int col = 0; col < LAST_COLUMN; ++col)
2952 auto ff = qvariant_cast<QFont>(
font);
2954 ff.setItalic(picked);
2955 ff.setUnderline(picked);
2961void ImagingPlanner::setSelectionPicked()
2963 setSelection(PICKED_BIT,
true);
2966void ImagingPlanner::setSelectionNotPicked()
2968 setSelection(PICKED_BIT,
false);
2971void ImagingPlanner::setSelectionImaged()
2973 setSelection(IMAGED_BIT,
true);
2976void ImagingPlanner::setSelectionNotImaged()
2978 setSelection(IMAGED_BIT,
false);
2981void ImagingPlanner::setSelectionIgnored()
2983 setSelection(IGNORED_BIT,
true);
2986void ImagingPlanner::setSelectionNotIgnored()
2988 setSelection(IGNORED_BIT,
false);
2991int ImagingPlanner::currentObjectFlags()
2993 auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(FLAGS_COLUMN);
2994 const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
2997 return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
3000QString ImagingPlanner::currentObjectNotes()
3002 auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(NOTES_COLUMN);
3003 const bool hasNotes = ui->CatalogView->
model()->
data(index, NOTES_ROLE).
canConvert<QString>();
3006 return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
3009void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
3011 auto index = ui->CatalogView->selectionModel()->currentIndex();
3016 auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
3018 m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
3021ImagingPlannerPopup::ImagingPlannerPopup() :
QMenu(nullptr)
3030void ImagingPlannerPopup::init(ImagingPlanner * planner,
const QStringList &names,
3031 const bool * imaged,
const bool * picked,
const bool * ignored)
3034 if (names.
size() == 0)
return;
3037 if (names.
size() == 1)
3039 else if (names.
size() <= 3)
3042 for (
int i = 1; i < names.
size(); i++)
3043 title.append(QString(
", %1").arg(names[i]));
3046 title =
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
3050 QString word = names.
size() == 1 ? names[0] :
i18n(
"objects");
3052 if (imaged ==
nullptr)
3054 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3055 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3058 addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
3060 addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
3062 if (picked ==
nullptr)
3064 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3065 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3068 addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
3070 addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
3073 if (ignored ==
nullptr)
3075 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3076 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3080 addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
3082 addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
3085 addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
3089ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
bool picked,
bool imaged,
3090 bool ignored,
const QString ¬es) : m_Name(
name), m_Notes(notes)
3095ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name,
int flags,
const QString ¬es)
3096 : m_Name(
name), m_Flags(flags), m_Notes(notes)
3100void ImagingPlannerDBEntry::getFlags(
bool * picked,
bool * imaged,
bool * ignored)
3102 *picked = m_Flags & PickedBit;
3103 *imaged = m_Flags & ImagedBit;
3104 *ignored = m_Flags & IgnoredBit;
3108void ImagingPlannerDBEntry::setFlags(
bool picked,
bool imaged,
bool ignored)
3111 if (picked) m_Flags |= PickedBit;
3112 if (imaged) m_Flags |= ImagedBit;
3113 if (ignored) m_Flags |= IgnoredBit;
3116void ImagingPlanner::saveToDB(
const QString &name,
bool picked,
bool imaged,
3117 bool ignored,
const QString ¬es)
3119 ImagingPlannerDBEntry e(name, 0, notes);
3120 e.setFlags(picked, imaged, ignored);
3124void ImagingPlanner::saveToDB(
const QString &name,
int flags,
const QString ¬es)
3126 ImagingPlannerDBEntry e(name, flags, notes);
3131void ImagingPlanner::loadFromDB()
3136 m_CatalogSortModel->setSourceModel(
nullptr);
3138 auto tz = QTimeZone(getGeo()->TZ() * 3600);
3139 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
3140 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
3141 KSAlmanac ksal(ut, getGeo());
3143 QList<ImagingPlannerDBEntry>
list;
3145 QHash<QString, ImagingPlannerDBEntry> dbData;
3146 QHash<QString, int> dbNotes;
3147 for (
const auto &entry : list)
3149 dbData[entry.m_Name] = entry;
3152 int rows = m_CatalogModel->rowCount();
3153 for (
int i = 0; i < rows; ++i)
3155 const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
3156 auto entry = dbData.
find(name);
3157 if (entry != dbData.
end())
3159 QVariant f = entry->m_Flags;
3160 m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
3161 if (entry->m_Flags & IMAGED_BIT)
3162 highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3163 if (entry->m_Flags & PICKED_BIT)
3164 highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN),
true);
3165 QVariant n = entry->m_Notes;
3166 m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
3170 m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
3173void ImagingPlanner::loadImagedFile()
3175 if (m_loadingCatalog)
3183 QFile inputFile(fileName);
3187 QStringList failedNames;
3188 QTextStream in(&inputFile);
3194 name = tweakNames(name);
3195 if (getObject(name))
3198 auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
3199 QVariant value(name);
3201 if (matches.size() > 0)
3203 setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
3204 highlightImagedObject(matches[0],
true);
3207 QString
name = m_CatalogModel->
data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
3208 int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
3209 QString notes = m_CatalogModel->
data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
3210 saveToDB(name, flags, notes);
3214 DPRINTF(stderr,
"ooops! internal inconsitency--got an object but match didn't work");
3218 failedNames.
append(name);
3221 if (failedNames.
size() == 0)
3224 KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
3226 KSNotification::sorry(
i18n(
"Empty file"));
3230 int num = std::min((
int)failedNames.
size(), 10);
3231 QString sample = QString(
"\"%1\"").arg(failedNames[0]);
3232 for (
int i = 1; i < num; ++i)
3233 sample.
append(QString(
" \"%1\"").arg(failedNames[i]));
3234 if (numSuccess == 0 && failedNames.
size() <= 10)
3235 KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
3236 else if (numSuccess == 0)
3237 KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
3238 else if (numSuccess > 0 && failedNames.
size() <= 10)
3239 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
3240 numSuccess, failedNames.
size() == 1 ?
"this" :
"these", sample));
3242 KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
3243 numSuccess, failedNames.
size(), sample));
3248 KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
3252void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
3254 m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
3257bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo *info)
3260 if (
result == m_CatalogImageInfoMap.end())
3262 if (
result->m_Filename.isEmpty())
3268void ImagingPlanner::loadCatalogViaMenu()
3270 QString startDir = Options::imagingPlannerCatalogPath();
3272 startDir = defaultDirectory();
3281void ImagingPlanner::loadCatalog(
const QString &path)
3283 removeEventFilters();
3290 m_loadingCatalog =
true;
3291 loadCatalogFromFile(path);
3299 m_loadingCatalog =
false;
3300 installEventFilters();
3303CatalogImageInfo::CatalogImageInfo(
const QString &csv)
3308 QStringList columns = line.
split(
",");
3309 if (columns.
size() < 1 || columns[0].isEmpty())
3312 m_Name = columns[column++];
3313 if (columns.
size() <= column)
return;
3314 m_Filename = columns[column++];
3315 if (columns.
size() <= column)
return;
3316 m_Author = columns[column++];
3317 if (columns.
size() <= column)
return;
3318 m_Link = columns[column++];
3319 if (columns.
size() <= column)
return;
3320 m_License = columns[column++];
3339void ImagingPlanner::loadCatalogFromFile(
QString path,
bool reset)
3341 QFile inputFile(path);
3345 m_numMissingImage = 0;
3347 int numMissingImage = 0, numWithImage = 0;
3348 if (!inputFile.exists())
3350 emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
3353 QStringList objectNames;
3356 auto tz = QTimeZone(getGeo()->TZ() * 3600);
3357 KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
3358 KStarsDateTime ut = getGeo()->LTtoUT(KStarsDateTime(midnight));
3359 KSAlmanac ksal(ut, getGeo());
3363 Options::setImagingPlannerCatalogPath(path);
3364 Options::self()->save();
3365 if (m_CatalogModel->rowCount() > 0)
3366 m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
3369 QTextStream in(&inputFile);
3372 CatalogImageInfo info(in.readLine().trimmed());
3373 if (info.m_Name.isEmpty())
3375 if (info.m_Name.startsWith(
"LoadCatalog"))
3380 auto match = re.match(info.m_Name);
3381 if (
match.hasMatch())
3383 QString catFilename =
match.captured(1);
3384 if (catFilename.
isEmpty())
continue;
3385 QFileInfo info(catFilename);
3387 QString catFullPath = catFilename;
3388 if (!info.isAbsolute())
3390 QString catDir = QFileInfo(path).absolutePath();
3391 catFullPath = QString(
"%1%2%3").
arg(catDir)
3394 if (catFullPath != path)
3395 loadCatalogFromFile(catFullPath,
false);
3399 objectNames.
append(info.m_Name);
3400 if (!info.m_Filename.isEmpty())
3403 QFileInfo fInfo(info.m_Filename);
3404 if (fInfo.isRelative())
3405 info.m_Filename = QString(
"%1%2%3").arg(QFileInfo(path).absolutePath())
3407 addCatalogImageInfo(info);
3412 DPRINTF(stderr,
"No catalog image for %s\n", info.m_Name.toLatin1().data());
3418 int num = 0, numBad = 0, iteration = 0;
3420 for (
const auto &name : objectNames)
3422 setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
3423 if (addCatalogItem(ksal, name, 0)) num++;
3430 m_numWithImage += numWithImage;
3431 m_numMissingImage += numMissingImage;
3432 DPRINTF(stderr,
"Catalog %s: %d of %d have catalog images\n",
3441 emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
3445void ImagingPlanner::sorry(
const QString &message)
3447 KSNotification::sorry(message);
a dms subclass that caches its sine and cosine values every time the angle is changed.
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
CatalogObject & insertStaticObject(const CatalogObject &obj)
Insert an object obj into m_static_objects and return a reference to the newly inserted object.
static QString processSearchText(QString searchText)
Do some post processing on the search text to interpret what the user meant This could include replac...
int size()
Return the numbers of flags.
void remove(int index)
Remove a flag.
void add(const SkyPoint &flagPoint, QString epoch, QString image, QString label, QColor labelColor)
Add a flag.
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
A class that implements methods to find sun rise, sun set, twilight begin / end times,...
Provides necessary information about the Moon.
void findPhase(const KSSun *Sun=nullptr)
Determine the phase angle of the moon, and assign the appropriate moon image.
const QImage & image() const
void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false) override
Update position of the planet (reimplemented from SkyPoint)
bool AddImagingPlannerEntry(const ImagingPlannerDBEntry &entry)
Adds a new Imaging Planner row into the database.
bool GetAllImagingPlannerEntries(QList< ImagingPlannerDBEntry > *entryList)
Gets all the Imaging Planner rows from the database.
const KStarsDateTime & ut() const
Q_INVOKABLE SimClock * clock()
SkyMapComposite * skyComposite()
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addSecs(double s) const
void setDate(const QDate &d)
Assign the Date according to a QDate object.
static KStars * Instance()
KStarsData * data() const
const KStarsDateTime & utc() const
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
void setClickedPoint(const SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
void setClickedObject(SkyObject *o)
Set the ClickedObject pointer to the argument.
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
void slotCenter()
Center the display at the point ClickedPoint.
Provides all necessary information about an object in the sky: its coordinates, name(s),...
virtual QString 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...)
StartupCondition
Conditions under which a SchedulerJob may start.
QMap< QString, uint16_t > CapturedFramesMap
mapping signature --> frames count
CompletionCondition
Conditions under which a SchedulerJob may complete.
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
KCRASH_EXPORT void initialize()
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
QString name(GameStandardAction id)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
GeoCoordinates geo(const QVariant &location)
QString path(const QString &relativePath)
VehicleSection::Type type(QStringView coachNumber, QStringView coachClassification)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
std::pair< bool, CatalogObject > resolveName(const QString &name)
Resolve the name of the given DSO and extract data from various sources.
virtual QVariant data(const QModelIndex &index, int role) const const=0
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
virtual QModelIndex parent(const QModelIndex &index) const const=0
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
qsizetype length() const const
QByteArray & replace(QByteArrayView before, QByteArrayView after)
void resize(qsizetype newSize, char c)
qsizetype size() const const
QByteArray toBase64(Base64Options options) const const
std::string toStdString() const const
void processEvents(QEventLoop::ProcessEventsFlags flags)
QDate addDays(qint64 ndays) const const
QString toString(QStringView format, QCalendar cal) const const
QDateTime addSecs(qint64 s) const const
bool isValid() const const
qint64 secsTo(const QDateTime &other) const const
void setTimeZone(const QTimeZone &toZone)
void dateChanged(QDate date)
bool openUrl(const QUrl &url)
QString absolutePath() const const
bool exists() const const
bool mkpath(const QString &dirPath) const const
qint64 elapsed() const const
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
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
bool isValid() const const
const QAbstractItemModel * model() 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)
QString tr(const char *sourceText, const char *disambiguation, int n)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
virtual QVariant data(int role) const const
virtual void setData(const QVariant &value, int role)
void setTextAlignment(Qt::Alignment alignment)
QString & append(QChar ch)
QString arg(Args &&... args) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool isEmpty() const const
QString mid(qsizetype position, qsizetype n) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
qsizetype size() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLatin1() const const
QString toLower() const const
QString toUpper() const const
QByteArray toUtf8() const const
QString trimmed() const const
QTextStream & dec(QTextStream &stream)
QTextStream & endl(QTextStream &stream)
QTextStream & fixed(QTextStream &stream)
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
bool isValid(int h, int m, int s, int ms)
QString toString(QStringView format) const const
bool isEmpty() const const
bool canConvert() const const
int toInt(bool *ok) const const
QString toString() const const