7#include "imagingplanner.h" 
    9#include <kio_version.h> 
   11#include "artificialhorizoncomponent.h" 
   12#include "auxiliary/screencapture.h" 
   13#include "auxiliary/thememanager.h" 
   14#include "catalogscomponent.h" 
   15#include "constellationboundarylines.h" 
   16#include "dialogs/detaildialog.h" 
   17#include "dialogs/finddialog.h" 
   20#include "ekos/scheduler/schedulerjob.h" 
   23#include "flagmanager.h" 
   24#include "flagcomponent.h" 
   26#include "nameresolver.h" 
   27#include "imageoverlaycomponent.h" 
   28#include "imagingplanneroptions.h" 
   29#include "kplotwidget.h" 
   30#include "kplotobject.h" 
   34#include "ksnotification.h" 
   38#include "kstarsdata.h" 
   39#include "fitsviewer/platesolve.h" 
   41#include "skymapcomposite.h" 
   43#include <QDesktopServices> 
   48#include <QNetworkReply> 
   50#include <QRegularExpression> 
   51#include <QSortFilterProxyModel> 
   52#include <QStandardItemModel> 
   57#define DPRINTF if (false) fprintf 
   89#define TYPE_ROLE (Qt::UserRole + 1) 
   90#define HOURS_ROLE (Qt::UserRole + 2) 
   91#define SIZE_ROLE (Qt::UserRole + 3) 
   92#define ALTITUDE_ROLE (Qt::UserRole + 4) 
   93#define MOON_ROLE (Qt::UserRole + 5) 
   94#define FLAGS_ROLE (Qt::UserRole + 6) 
   95#define NOTES_ROLE (Qt::UserRole + 7) 
   97#define PICKED_BIT ImagingPlannerDBEntry::PickedBit 
   98#define IMAGED_BIT ImagingPlannerDBEntry::ImagedBit 
   99#define IGNORED_BIT ImagingPlannerDBEntry::IgnoredBit 
  129        case SkyObject::OPEN_CLUSTER:
 
  130            return Options::imagingPlannerAcceptOpenCluster();
 
  131        case SkyObject::GLOBULAR_CLUSTER:
 
  132            return Options::imagingPlannerAcceptGlobularCluster();
 
  133        case SkyObject::GASEOUS_NEBULA:
 
  134            return Options::imagingPlannerAcceptNebula();
 
  135        case SkyObject::PLANETARY_NEBULA:
 
  136            return Options::imagingPlannerAcceptPlanetary();
 
  137        case SkyObject::SUPERNOVA_REMNANT:
 
  138            return Options::imagingPlannerAcceptSupernovaRemnant();
 
  139        case SkyObject::GALAXY:
 
  140            return Options::imagingPlannerAcceptGalaxy();
 
  141        case SkyObject::GALAXY_CLUSTER:
 
  142            return Options::imagingPlannerAcceptGalaxyCluster();
 
  143        case SkyObject::DARK_NEBULA:
 
  144            return Options::imagingPlannerAcceptDarkNebula();
 
  146            return Options::imagingPlannerAcceptOther();
 
  153    const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
 
  156    const bool flag = model->
data(idx, FLAGS_ROLE).
toInt() & bit;
 
  163    const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
 
  164    int currentFlags = 0;
 
  166        currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
 
  168    model->
setData(idx, val, FLAGS_ROLE);
 
  174    const bool hasFlags = model->
data(idx, FLAGS_ROLE).
canConvert<
int>();
 
  177    const int currentFlags = model->
data(idx, FLAGS_ROLE).
toInt();
 
  179    model->
setData(idx, val, FLAGS_ROLE);
 
  185    if (flags & IMAGED_BIT) str.
append(
i18n(
"Imaged"));
 
  186    if (flags & PICKED_BIT)
 
  192    if (flags & IGNORED_BIT)
 
  202void setupShowCallback(
bool checked,
 
  203                       void (*showOption)(
bool), 
void (*showNotOption)(
bool),
 
  204                       void (*dontCareOption)(
bool),
 
  208    Q_UNUSED(showCheckbox);
 
  212        showNotOption(
false);
 
  213        dontCareOption(
false);
 
  216        Options::self()->save();
 
  221        showNotOption(
false);
 
  222        dontCareOption(
true);
 
  225        Options::self()->save();
 
  229void setupShowNotCallback(
bool checked,
 
  230                          void (*showOption)(
bool), 
void (*showNotOption)(
bool), 
void (*dontCareOption)(
bool),
 
  233    Q_UNUSED(showNotCheckbox);
 
  238        dontCareOption(
false);
 
  241        Options::self()->save();
 
  246        showNotOption(
false);
 
  247        dontCareOption(
true);
 
  250        Options::self()->save();
 
  254void setupDontCareCallback(
bool checked,
 
  255                           void (*showOption)(
bool), 
void (*showNotOption)(
bool), 
void (*dontCareOption)(
bool),
 
  261        showNotOption(
false);
 
  262        dontCareOption(
true);
 
  265        Options::self()->save();
 
  272        showNotOption(
false);
 
  273        dontCareOption(
true);
 
  277        Options::self()->save();
 
  286                          "\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&//=]*)");
 
  291    auto match = re.match(input);
 
  292    if (!
match.hasMatch())
 
  295        return(
match.captured(0));
 
  301        match = re.match(inp);
 
  302        if (!
match.hasMatch())
 
  305            return (
match.captured(0));
 
  331                        int column, 
int role)
 
  333    const double l = 
left.siblingAtColumn(column).data(role).toDouble();
 
  334    const double r = 
right.siblingAtColumn(column).data(role).toDouble();
 
  344    const QString l = 
left.siblingAtColumn(column).data(role).toString();
 
  345    const QString r = 
right.siblingAtColumn(column).data(role).toString();
 
  349    if (lList.
size() == 0 || rList.
size() == 0)
 
  360    if (lList.
size() >= 2 && rList.
size() >= 2)
 
  362        int lInt = lList[1].toInt();
 
  363        int rInt = rList[1].toInt();
 
  366        if (lInt > 0 && rInt > 0)
 
  367            return -(lInt - rInt);
 
  375void SchedulerUtils_setupJob(Ekos::SchedulerJob &job, 
const QString &name, 
bool isLead, 
const QString &group,
 
  376                             const QString &train, 
const dms &ra, 
const dms &dec, 
double djd, 
double rotation, 
const QUrl &sequenceUrl,
 
  378                             const QDateTime &completionTime, 
int completionRepeats, 
double minimumAltitude, 
double minimumMoonSeparation,
 
  379                             double maxMoonAltitude,
 
  380                             bool enforceTwilight, 
bool enforceArtificialHorizon, 
bool track, 
bool focus, 
bool align, 
bool guide)
 
  384    job.setIsLead(isLead);
 
  385    job.setOpticalTrain(train);
 
  386    job.setPositionAngle(rotation);
 
  392        job.setLeadJob(
nullptr);
 
  394        job.setTargetCoords(ra, dec, djd);
 
  395        job.setFITSFile(fitsUrl);
 
  398        job.setStartupCondition(startup);
 
  399        if (startup == Ekos::START_AT)
 
  401            job.setStartupTime(startupTime);
 
  404        job.setFileStartupCondition(job.getStartupCondition());
 
  405        job.setStartAtTime(job.getStartupTime());
 
  408        job.setMinAltitude(minimumAltitude);
 
  409        job.setMinMoonSeparation(minimumMoonSeparation);
 
  410        job.setMaxMoonAltitude(maxMoonAltitude);
 
  414        job.setEnforceTwilight(enforceTwilight);
 
  415        job.setEnforceArtificialHorizon(enforceArtificialHorizon);
 
  418        job.setStepPipeline(Ekos::SchedulerJob::USE_NONE);
 
  420            job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_TRACK));
 
  422            job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_FOCUS));
 
  424            job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_ALIGN));
 
  426            job.setStepPipeline(
static_cast<Ekos::SchedulerJob::StepPipeline
>(job.getStepPipeline() | Ekos::SchedulerJob::USE_GUIDE));
 
  429        job.setFileStartupCondition(job.getStartupCondition());
 
  430        job.setStartAtTime(job.getStartupTime());
 
  435    job.setSequenceFile(sequenceUrl);
 
  436    job.setCompletionCondition(completion);
 
  437    if (completion == Ekos::FINISH_AT)
 
  438        job.setFinishAtTime(completionTime);
 
  439    else if (completion == Ekos::FINISH_REPEAT)
 
  441        job.setRepeatsRequired(completionRepeats);
 
  442        job.setRepeatsRemaining(completionRepeats);
 
  450void setupJob(Ekos::SchedulerJob &job, 
const QString name, 
double minAltitude, 
double minMoonSeparation,
 
  451              double maxMoonAltitude, 
dms ra, 
dms dec,
 
  452              bool useArtificialHorizon)
 
  455    double rotation = 0.0;
 
  461    SchedulerUtils_setupJob(job, name, 
true, 
"",
 
  463                            rotation, sequenceURL, 
QUrl(),
 
  466                            minAltitude, minMoonSeparation, maxMoonAltitude,
 
  467                            true, useArtificialHorizon,
 
  468                            true, 
true, 
true, 
true);
 
  472void getRunTimes(
const QDate &date, 
const GeoLocation &geo, 
double minAltitude, 
double minMoonSeparation,
 
  473                 double maxMoonAltitude, 
const dms &ra, 
const dms &dec, 
bool useArtificialHorizon, 
QVector<QDateTime> *jobStartTimes,
 
  476    jobStartTimes->
clear();
 
  477    jobEndTimes->
clear();
 
  478    constexpr int SCHEDULE_RESOLUTION_MINUTES = 10;
 
  479    Ekos::SchedulerJob job;
 
  480    setupJob(job, 
"temp", minAltitude, minMoonSeparation, maxMoonAltitude, ra, dec, useArtificialHorizon);
 
  487    startTime.setTimeZone(tz);
 
  488    stopTime.setTimeZone(tz);
 
  492    while (--maxIters >= 0)
 
  494        QDateTime s = job.getNextPossibleStartTime(startTime, SCHEDULE_RESOLUTION_MINUTES, 
false, stopTime);
 
  499        QDateTime e = job.getNextEndTime(s, SCHEDULE_RESOLUTION_MINUTES, &constraintReason, stopTime);
 
  507        if (e.
secsTo(stopTime) < 600)
 
  517                   double minMoonSeparation, 
double maxMoonAltitude, 
bool useArtificialHorizon)
 
  520    getRunTimes(date, geo, minAltitude, minMoonSeparation, maxMoonAltitude, 
object.ra0(), 
object.dec0(), useArtificialHorizon,
 
  523    if (jobStartTimes.
size() == 0 || jobEndTimes.
size() == 0)
 
  527        double totalHours = 0.0;
 
  528        for (
int i = 0; i < jobStartTimes.
size(); ++i)
 
  529            totalHours += jobStartTimes[i].secsTo(jobEndTimes[i]) * 1.0 / 3600.0;
 
  538int packString(
const QString &input, quint8 *p, 
bool reallyPack)
 
  541    quint32 len = str_data.
length();
 
  542    const char *str = str_data.
data();
 
  543    constexpr bool compatibilityMode = 
false;
 
  544    const quint8 *origP = p;
 
  547        if (reallyPack) *p = 0xa0 | len;
 
  550    else if (len <= std::numeric_limits<quint8>::max() &&
 
  551             compatibilityMode == 
false)
 
  553        if (reallyPack) *p = 0xd9;
 
  555        if (reallyPack) *p = len;
 
  558    else if (len <= std::numeric_limits<quint16>::max())
 
  560        if (reallyPack) *p = 0xda;
 
  571    if (reallyPack) memcpy(p, str, len);
 
  572    return (p - origP) + len;
 
  579    int size = packString(input, 
nullptr, 
false);
 
  583    packString(input, 
reinterpret_cast<quint8*
>(arr.
data()), 
true);
 
  601        result.
replace(remainingSpacesRegex, QStringLiteral(
""));
 
  607bool downsampleImageFiles(
const QString &baseDir, 
int maxHeight)
 
  618    const QString subDir = 
"REDUCED";
 
  619    QDir directory(baseDir);
 
  620    if (!directory.exists())
 
  622        fprintf(stderr, 
"downsampleImageFiles: Base directory doesn't exist\n");
 
  630            fprintf(stderr, 
"downsampleImageFiles: Failed making the output directory\n");
 
  637    foreach (
QString filename, files)
 
  642        if (img.height() > maxHeight)
 
  651        if (!scaledImg.
save(jpgFilename, 
"JPG"))
 
  652            fprintf(stderr, 
"downsampleImageFiles: Failed saving \"%s\"\n", writeFilename.
toLatin1().
data());
 
  656            fprintf(stderr, 
"downsampleImageFiles: saved \"%s\"\n", writeFilename.
toLatin1().
data());
 
  659    fprintf(stderr, 
"downsampleImageFiles: Wrote %d files\n", numSaved);
 
  670        const int len = bInput.
size();
 
  672        for (
int i = 0; i < len; ++i)
 
  682        bInput.
replace(pos, 1, substitute);
 
  691    auto massagedName = 
name;
 
  693        massagedName = massagedName.
replace(0, 4, 
"sh2-");
 
  694    massagedName =  massagedName.
replace(
' ', 
"");
 
  700    if (files.size() > 0)
 
  701        return files[0].absoluteFilePath();
 
  704    for (
int i = 0; i < subDirs.size(); i++)
 
  706        QDir subDir(subDirs[i].absoluteFilePath());
 
  708        if (files.size() > 0)
 
  709            return files[0].absoluteFilePath();
 
  716    if (astrobinAbbrev == 
"ACC")
 
  718    else if (astrobinAbbrev == 
"ASACC")
 
  720    else if (astrobinAbbrev == 
"ANCCC")
 
  722    else if (astrobinAbbrev == 
"ANCSACC")
 
  723        return "CC-BY-SA-NC";
 
  727QString creativeCommonsTooltipString(
const QString &astrobinAbbrev)
 
  729    if (astrobinAbbrev == 
"ACC")
 
  730        return "Atribution Creative Commons";
 
  731    else if (astrobinAbbrev == 
"ASACC")
 
  732        return "Atribution Share-Alike Creative Commons";
 
  733    else if (astrobinAbbrev == 
"ANCCC")
 
  734        return "Atribution Non-Commercial Creative Commons";
 
  735    else if (astrobinAbbrev == 
"ANCSACC")
 
  736        return "Atribution Non-Commercial Share-Alike Creative Commons";
 
  755                      double hoursAfterDusk = 0, 
double hoursBeforeDawn = 0)
 
  761    QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
 
  763    QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
 
  769    auto end = dawn.
addSecs(-hoursBeforeDawn * 3600);
 
  778    while (t.secsTo(end) > 0)
 
  780        double alt = getAltitude(geo, coords, t);
 
  786        t = t.addSecs(60 * 20);
 
  795    m_SortColumn = HOURS_COLUMN;
 
  799bool CatalogFilter::filterAcceptsRow(
int row, 
const QModelIndex &parent)
 const 
  803    if (!acceptType(type)) 
return false;
 
  807    if (!hasEnoughHours) 
return false;
 
  811    const bool isImaged = 
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IMAGED_BIT;
 
  812    const bool passesImagedConstraints = !m_ImagedConstraintsEnabled || (isImaged == m_ImagedRequired);
 
  813    if (!passesImagedConstraints) 
return false;
 
  815    const bool isIgnored = 
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & IGNORED_BIT;
 
  816    const bool passesIgnoredConstraints = !m_IgnoredConstraintsEnabled || (isIgnored == m_IgnoredRequired);
 
  817    if (!passesIgnoredConstraints) 
return false;
 
  819    const bool isPicked = 
sourceModel()->data(flagsIndex, FLAGS_ROLE).toInt() & PICKED_BIT;
 
  820    const bool passesPickedConstraints = !m_PickedConstraintsEnabled || (isPicked == m_PickedRequired);
 
  821    if (!passesPickedConstraints) 
return false;
 
  824    if (m_Keyword.isEmpty() || !m_KeywordConstraintsEnabled) 
return true;
 
  826    const QString notes = 
sourceModel()->data(notesIndex, NOTES_ROLE).toString();
 
  828    const bool REMatches = m_KeywordRE.match(notes).hasMatch();
 
  829    return (m_KeywordRequired == REMatches);
 
  832void CatalogFilter::setMinHours(
double hours)
 
  837void CatalogFilter::setImagedConstraints(
bool enabled, 
bool required)
 
  839    m_ImagedConstraintsEnabled = enabled;
 
  840    m_ImagedRequired = required;
 
  843void CatalogFilter::setPickedConstraints(
bool enabled, 
bool required)
 
  845    m_PickedConstraintsEnabled = enabled;
 
  846    m_PickedRequired = required;
 
  849void CatalogFilter::setIgnoredConstraints(
bool enabled, 
bool required)
 
  851    m_IgnoredConstraintsEnabled = enabled;
 
  852    m_IgnoredRequired = required;
 
  855void CatalogFilter::setKeywordConstraints(
bool enabled, 
bool required, 
const QString &keyword)
 
  857    m_KeywordConstraintsEnabled = enabled;
 
  858    m_KeywordRequired = required;
 
  860    m_KeywordRE = QRegularExpression(keyword);
 
  863void CatalogFilter::setSortColumn(
int column)
 
  868    if (column == m_SortColumn)
 
  869        m_ReverseSort = !m_ReverseSort;
 
  870    m_SortColumn = column;
 
  874    switch (m_SortColumn)
 
  877        case ALTITUDE_COLUMN:
 
  881            arrowChar = m_ReverseSort ? QChar(0x25B2) : QChar(0x25BC);
 
  884            arrowChar = m_ReverseSort ? QChar(0x25BC) : QChar(0x25B2);
 
  888        QString(
"%1%2").arg(arrowChar).arg(COLUMN_HEADERS[m_SortColumn]));
 
  897    double compareVal = 0;
 
  902            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  903            if (m_ReverseSort) compareVal = -compareVal;
 
  907            compareVal = stringCompareFcn(left, right, TYPE_COLUMN, 
Qt::DisplayRole);
 
  908            if (m_ReverseSort) compareVal = -compareVal;
 
  909            if (compareVal != 0) 
break;
 
  910            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  911            if (compareVal != 0) 
break;
 
  912            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  916            compareVal = floatCompareFcn(left, right, SIZE_COLUMN, SIZE_ROLE);
 
  917            if (m_ReverseSort) compareVal = -compareVal;
 
  918            if (compareVal != 0) 
break;
 
  919            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  920            if (compareVal != 0) 
break;
 
  921            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  923        case ALTITUDE_COLUMN:
 
  925            compareVal = floatCompareFcn(left, right, ALTITUDE_COLUMN, ALTITUDE_ROLE);
 
  926            if (m_ReverseSort) compareVal = -compareVal;
 
  927            if (compareVal != 0) 
break;
 
  928            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  929            if (compareVal != 0) 
break;
 
  930            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  934            compareVal = floatCompareFcn(left, right, MOON_COLUMN, MOON_ROLE);
 
  935            if (m_ReverseSort) compareVal = -compareVal;
 
  936            if (compareVal != 0) 
break;
 
  937            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  938            if (compareVal != 0) 
break;
 
  939            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  941        case CONSTELLATION_COLUMN:
 
  943            compareVal = stringCompareFcn(left, right, CONSTELLATION_COLUMN, 
Qt::DisplayRole);
 
  944            if (m_ReverseSort) compareVal = -compareVal;
 
  945            if (compareVal != 0) 
break;
 
  946            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  947            if (compareVal != 0) 
break;
 
  948            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  952            compareVal = stringCompareFcn(left, right, COORD_COLUMN, 
Qt::DisplayRole);
 
  953            if (m_ReverseSort) compareVal = -compareVal;
 
  954            if (compareVal != 0) 
break;
 
  955            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  956            if (compareVal != 0) 
break;
 
  957            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  962            compareVal = floatCompareFcn(left, right, HOURS_COLUMN, HOURS_ROLE);
 
  963            if (m_ReverseSort) compareVal = -compareVal;
 
  964            if (compareVal != 0) 
break;
 
  965            compareVal = stringCompareFcn(left, right, NAME_COLUMN, 
Qt::DisplayRole);
 
  968    return compareVal < 0;
 
  978void ImagingPlannerUI::setupIcons()
 
 1002    return KStarsData::Instance()->
geo();
 
 1005QDate ImagingPlanner::getDate()
 const 
 1007    return ui->DateEdit->date();
 
 1010ImagingPlanner::ImagingPlanner() : 
QDialog(nullptr), m_networkManager(this), m_manager{ CatalogsDB::dso_db_path() }
 
 1012    ui = 
new ImagingPlannerUI(
this);
 
 1018    setLayout(mainLayout);
 
 1020    setWindowTitle(
i18nc(
"@title:window", 
"Imaging Planner"));
 
 1023    if (Options::imagingPlannerIndependentWindow())
 
 1039void ImagingPlanner::setupHideButtons(
bool(*option)(), 
void(*setOption)(
bool),
 
 1049        Options::self()->save();
 
 1058        Options::self()->save();
 
 1066void ImagingPlanner::focusOnTable()
 
 1068    ui->CatalogView->setFocus();
 
 1071void ImagingPlanner::adjustWindowSize()
 
 1073    const int keepWidth = 
width();
 
 1075    const int newHeight = 
height();
 
 1076    resize(keepWidth, newHeight);
 
 1080void ImagingPlanner::setupFilterButton(
QCheckBox * checkbox, 
bool(*option)(), 
void(*setOption)(
bool))
 
 1086        Options::self()->save();
 
 1087        m_CatalogSortModel->invalidate();
 
 1089        ui->CatalogView->resizeColumnsToContents();
 
 1095void ImagingPlanner::setupFilter2Buttons(
 
 1097    bool(*yesOption)(), 
bool(*noOption)(), 
bool(*dontCareOption)(),
 
 1098    void(*setYesOption)(
bool), 
void(*setNoOption)(
bool), 
void(*setDontCareOption)(
bool))
 
 1104        setupShowCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
 
 1105        updateSortConstraints();
 
 1106        m_CatalogSortModel->invalidate();
 
 1107        ui->CatalogView->resizeColumnsToContents();
 
 1113        setupShowNotCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
 
 1114        updateSortConstraints();
 
 1115        m_CatalogSortModel->invalidate();
 
 1116        ui->CatalogView->resizeColumnsToContents();
 
 1120    connect(dontCare, &
QCheckBox::clicked, [
this, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare](
bool checked)
 
 1122        setupDontCareCallback(checked, setYesOption, setNoOption, setDontCareOption, yes, no, dontCare);
 
 1123        updateSortConstraints();
 
 1124        m_CatalogSortModel->invalidate();
 
 1125        ui->CatalogView->resizeColumnsToContents();
 
 1136void ImagingPlanner::updateSortConstraints()
 
 1138    m_CatalogSortModel->setPickedConstraints(!ui->dontCarePickedCB->isChecked(),
 
 1139            ui->pickedCB->isChecked());
 
 1140    m_CatalogSortModel->setImagedConstraints(!ui->dontCareImagedCB->isChecked(),
 
 1141            ui->imagedCB->isChecked());
 
 1142    m_CatalogSortModel->setIgnoredConstraints(!ui->dontCareIgnoredCB->isChecked(),
 
 1143            ui->ignoredCB->isChecked());
 
 1144    m_CatalogSortModel->setKeywordConstraints(!ui->dontCareKeywordCB->isChecked(),
 
 1145            ui->keywordCB->isChecked(), ui->keywordEdit->toPlainText().trimmed());
 
 1149void ImagingPlanner::initialize()
 
 1151    if (KStarsData::Instance() == 
nullptr)
 
 1158    connect(
this, &ImagingPlanner::popupSorry, 
this, &ImagingPlanner::sorry);
 
 1161    m_CatalogModel = 
new QStandardItemModel(0, LAST_COLUMN);
 
 1164    m_CatalogModel->setHorizontalHeaderLabels(COLUMN_HEADERS);
 
 1165    m_CatalogModel->horizontalHeaderItem(NAME_COLUMN)->setToolTip(
 
 1166        i18n(
"Object Name--click header to sort ascending/descending."));
 
 1167    m_CatalogModel->horizontalHeaderItem(
 
 1168        HOURS_COLUMN)->setToolTip(
i18n(
"Number of hours the object can be imaged--click header to sort ascending/descending."));
 
 1169    m_CatalogModel->horizontalHeaderItem(TYPE_COLUMN)->setToolTip(
 
 1170        i18n(
"Object Type--click header to sort ascending/descending."));
 
 1171    m_CatalogModel->horizontalHeaderItem(
 
 1172        SIZE_COLUMN)->setToolTip(
i18n(
"Maximum object dimension (arcmin)--click header to sort ascending/descending."));
 
 1173    m_CatalogModel->horizontalHeaderItem(
 
 1174        ALTITUDE_COLUMN)->setToolTip(
i18n(
"Maximum altitude--click header to sort ascending/descending."));
 
 1175    m_CatalogModel->horizontalHeaderItem(
 
 1176        MOON_COLUMN)->setToolTip(
i18n(
"Moon angular separation at midnight--click header to sort ascending/descending."));
 
 1177    m_CatalogModel->horizontalHeaderItem(
 
 1178        CONSTELLATION_COLUMN)->setToolTip(
i18n(
"Constellation--click header to sort ascending/descending."));
 
 1179    m_CatalogModel->horizontalHeaderItem(
 
 1180        COORD_COLUMN)->setToolTip(
i18n(
"RA/DEC coordinates--click header to sort ascending/descending."));
 
 1182    m_CatalogSortModel = 
new CatalogFilter(
this);
 
 1184    m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
 
 1185    m_CatalogSortModel->setDynamicSortFilter(
true);
 
 1187    ui->CatalogView->setModel(m_CatalogSortModel.data());
 
 1188    ui->CatalogView->setSortingEnabled(
false); 
 
 1189    ui->CatalogView->horizontalHeader()->setStretchLastSection(
false);
 
 1190    ui->CatalogView->resizeColumnsToContents();
 
 1191    ui->CatalogView->verticalHeader()->setVisible(
false); 
 
 1192    ui->CatalogView->setColumnHidden(FLAGS_COLUMN, 
true);
 
 1195    m_CatalogSortModel->setSortColumn(HOURS_COLUMN);
 
 1196    m_CatalogSortModel->setSortColumn(HOURS_COLUMN);
 
 1199            this, &ImagingPlanner::selectionChanged);
 
 1204        auto utc = KStarsData::Instance()->
clock()->
utc();
 
 1205        auto localTime = getGeo()->UTtoLT(utc);
 
 1206        ui->DateEdit->
setDate(localTime.date());
 
 1212    setupHideButtons(&Options::imagingPlannerHideAltitudeGraph, &Options::setImagingPlannerHideAltitudeGraph,
 
 1213                     ui->hideAltitudeGraphB, ui->showAltitudeGraphB,
 
 1214                     ui->AltitudeGraphFrame, ui->HiddenAltitudeGraphFrame);
 
 1221        QString selection = currentObjectName();
 
 1225        scrollToName(selection);
 
 1249        checkTargets2(true);
 
 1253        QString dir = QFileDialog::getExistingDirectory(this, tr(
"Downsample Directory"));
 
 1256            if (downsampleImageFiles(dir, 300))
 
 1257                fprintf(stderr, 
"downsampling succeeded\n");
 
 1259                fprintf(stderr, 
"downsampling failed\n");
 
 1264    Options::setImagingPlannerHideAstrobinDetails(
true);
 
 1265    setupHideButtons(&Options::imagingPlannerHideAstrobinDetails, &Options::setImagingPlannerHideAstrobinDetails,
 
 1266                     ui->hideAstrobinDetailsButton, ui->showAstrobinDetailsButton,
 
 1267                     ui->AstrobinSearchFrame, ui->HiddenAstrobinSearchFrame);
 
 1268    ui->AstrobinAward->setChecked(Options::astrobinAward());
 
 1271        Options::setAstrobinAward(checked);
 
 1272        Options::self()->save();
 
 1275    ui->AstrobinMinRadius->setValue(Options::astrobinMinRadius());
 
 1278        Options::setAstrobinMinRadius(ui->AstrobinMinRadius->value());
 
 1279        Options::self()->save();
 
 1282    ui->AstrobinMaxRadius->setValue(Options::astrobinMaxRadius());
 
 1285        Options::setAstrobinMaxRadius(ui->AstrobinMaxRadius->value());
 
 1286        Options::self()->save();
 
 1297    setupHideButtons(&Options::imagingPlannerHideImage, &Options::setImagingPlannerHideImage,
 
 1298                     ui->hideImageButton, ui->showImageButton,
 
 1299                     ui->ImageFrame, ui->HiddenImageFrame);
 
 1302    Options::setImagingPlannerHideFilters(
true);
 
 1303    setupHideButtons(&Options::imagingPlannerHideFilters, &Options::setImagingPlannerHideFilters,
 
 1304                     ui->hideFilterTypesButton, ui->showFilterTypesButton,
 
 1305                     ui->FilterTypesFrame, ui->HiddenFilterTypesFrame);
 
 1306    setupFilterButton(ui->OpenClusterCB, &Options::imagingPlannerAcceptOpenCluster,
 
 1307                      &Options::setImagingPlannerAcceptOpenCluster);
 
 1308    setupFilterButton(ui->NebulaCB, &Options::imagingPlannerAcceptNebula, &Options::setImagingPlannerAcceptNebula);
 
 1309    setupFilterButton(ui->GlobularClusterCB, &Options::imagingPlannerAcceptGlobularCluster,
 
 1310                      &Options::setImagingPlannerAcceptGlobularCluster);
 
 1311    setupFilterButton(ui->PlanetaryCB, &Options::imagingPlannerAcceptPlanetary, &Options::setImagingPlannerAcceptPlanetary);
 
 1312    setupFilterButton(ui->SupernovaRemnantCB, &Options::imagingPlannerAcceptSupernovaRemnant,
 
 1313                      &Options::setImagingPlannerAcceptSupernovaRemnant);
 
 1314    setupFilterButton(ui->GalaxyCB, &Options::imagingPlannerAcceptGalaxy, &Options::setImagingPlannerAcceptGalaxy);
 
 1315    setupFilterButton(ui->GalaxyClusterCB, &Options::imagingPlannerAcceptGalaxyCluster,
 
 1316                      &Options::setImagingPlannerAcceptGalaxyCluster);
 
 1317    setupFilterButton(ui->DarkNebulaCB, &Options::imagingPlannerAcceptDarkNebula, &Options::setImagingPlannerAcceptDarkNebula);
 
 1318    setupFilterButton(ui->OtherCB, &Options::imagingPlannerAcceptOther, &Options::setImagingPlannerAcceptOther);
 
 1320    setupFilter2Buttons(ui->pickedCB, ui->notPickedCB, ui->dontCarePickedCB,
 
 1321                        &Options::imagingPlannerShowPicked, &Options::imagingPlannerShowNotPicked, &Options::imagingPlannerDontCarePicked,
 
 1322                        &Options::setImagingPlannerShowPicked, &Options::setImagingPlannerShowNotPicked, &Options::setImagingPlannerDontCarePicked);
 
 1324    setupFilter2Buttons(ui->imagedCB, ui->notImagedCB, ui->dontCareImagedCB,
 
 1325                        &Options::imagingPlannerShowImaged, &Options::imagingPlannerShowNotImaged, &Options::imagingPlannerDontCareImaged,
 
 1326                        &Options::setImagingPlannerShowImaged, &Options::setImagingPlannerShowNotImaged, &Options::setImagingPlannerDontCareImaged);
 
 1328    setupFilter2Buttons(ui->ignoredCB, ui->notIgnoredCB, ui->dontCareIgnoredCB,
 
 1329                        &Options::imagingPlannerShowIgnored, &Options::imagingPlannerShowNotIgnored, &Options::imagingPlannerDontCareIgnored,
 
 1330                        &Options::setImagingPlannerShowIgnored, &Options::setImagingPlannerShowNotIgnored,
 
 1331                        &Options::setImagingPlannerDontCareIgnored);
 
 1333    ui->keywordEdit->setText(Options::imagingPlannerKeyword());
 
 1334    ui->keywordEdit->setAcceptRichText(
false);
 
 1335    m_Keyword = Options::imagingPlannerKeyword();
 
 1336    setupFilter2Buttons(ui->keywordCB, ui->notKeywordCB, ui->dontCareKeywordCB,
 
 1337                        &Options::imagingPlannerShowKeyword, &Options::imagingPlannerShowNotKeyword, &Options::imagingPlannerDontCareKeyword,
 
 1338                        &Options::setImagingPlannerShowKeyword, &Options::setImagingPlannerShowNotKeyword,
 
 1339                        &Options::setImagingPlannerDontCareKeyword);
 
 1344    ui->useArtificialHorizon->setChecked(Options::imagingPlannerUseArtificialHorizon());
 
 1345    m_UseArtificialHorizon = Options::imagingPlannerUseArtificialHorizon();
 
 1346    ui->minMoon->setValue(Options::imagingPlannerMinMoonSeparation());
 
 1347    m_MinMoon = Options::imagingPlannerMinMoonSeparation();
 
 1348    ui->maxMoonAltitude->setValue(Options::imagingPlannerMaxMoonAltitude());
 
 1349    m_MaxMoonAltitude = Options::imagingPlannerMaxMoonAltitude();
 
 1350    ui->minAltitude->setValue(Options::imagingPlannerMinAltitude());
 
 1351    m_MinAltitude = Options::imagingPlannerMinAltitude();
 
 1352    ui->minHours->setValue(Options::imagingPlannerMinHours());
 
 1353    m_MinHours = Options::imagingPlannerMinHours();
 
 1354    m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
 
 1357        if (m_UseArtificialHorizon == ui->useArtificialHorizon->isChecked())
 
 1359        m_UseArtificialHorizon = ui->useArtificialHorizon->isChecked();
 
 1360        Options::setImagingPlannerUseArtificialHorizon(ui->useArtificialHorizon->isChecked());
 
 1361        Options::self()->save();
 
 1367        if (m_MinMoon == ui->minMoon->value())
 
 1369        m_MinMoon = ui->minMoon->value();
 
 1370        Options::setImagingPlannerMinMoonSeparation(ui->minMoon->value());
 
 1371        Options::self()->save();
 
 1377        if (m_MaxMoonAltitude == ui->maxMoonAltitude->value())
 
 1379        m_MaxMoonAltitude = ui->maxMoonAltitude->value();
 
 1380        Options::setImagingPlannerMaxMoonAltitude(ui->maxMoonAltitude->value());
 
 1381        Options::self()->save();
 
 1387        if (m_MinAltitude == ui->minAltitude->value())
 
 1389        m_MinAltitude = ui->minAltitude->value();
 
 1390        Options::setImagingPlannerMinAltitude(ui->minAltitude->value());
 
 1391        Options::self()->save();
 
 1397        if (m_MinHours == ui->minHours->value())
 
 1399        m_MinHours = ui->minHours->value();
 
 1400        Options::setImagingPlannerMinHours(ui->minHours->value());
 
 1401        Options::self()->save();
 
 1402        m_CatalogSortModel->setMinHours(Options::imagingPlannerMinHours());
 
 1403        m_CatalogSortModel->invalidate();
 
 1404        ui->CatalogView->resizeColumnsToContents();
 
 1408    updateSortConstraints();
 
 1410    m_CatalogSortModel->setMinHours(ui->minHours->value());
 
 1412    ui->CatalogView->setColumnHidden(NOTES_COLUMN, 
true);
 
 1421        ui->userNotesLabel->setVisible(true);
 
 1422        ui->userNotesEdit->setText(ui->userNotes->text());
 
 1423        ui->userNotesEdit->setVisible(true);
 
 1424        ui->userNotesEditButton->setVisible(false);
 
 1425        ui->userNotesDoneButton->setVisible(true);
 
 1426        ui->userNotes->setVisible(false);
 
 1427        ui->userNotesLabel->setVisible(true);
 
 1428        ui->userNotesOpenLink->setVisible(false);
 
 1429        ui->userNotesOpenLink2->setVisible(false);
 
 1430        ui->userNotesOpenLink3->setVisible(false);
 
 1436        QString urlString = findUrl(ui->userNotes->text());
 
 1437        if (urlString.isEmpty())
 
 1439        QDesktopServices::openUrl(QUrl(urlString));
 
 1444        QString urlString = findUrl(ui->userNotes->text(), 2);
 
 1445        if (urlString.isEmpty())
 
 1447        QDesktopServices::openUrl(QUrl(urlString));
 
 1452        QString urlString = findUrl(ui->userNotes->text(), 3);
 
 1453        if (urlString.isEmpty())
 
 1455        QDesktopServices::openUrl(QUrl(urlString));
 
 1464        m_CatalogSortModel->setSortColumn(column);
 
 1465        m_CatalogSortModel->invalidate();
 
 1466        ui->CatalogView->resizeColumnsToContents();
 
 1474    qRegisterMetaType<QList<QStandardItem * >> (
"QList<QStandardItem *>");
 
 1475    connect(
this, &ImagingPlanner::addRow, 
this, &ImagingPlanner::addRowSlot);
 
 1485    installEventFilters();
 
 1487    m_PlateSolve.reset(
new PlateSolve(
this));
 
 1488    m_PlateSolve->enableAuxButton(
"Retake screenshot",
 
 1489                                  "Retake the screenshot of the object if you're having issues solving.");
 
 1491    connect(m_PlateSolve.get(), &PlateSolve::auxClicked, 
this, [
this]()
 
 1493        m_PlateSolve->abort();
 
 1498void ImagingPlanner::installEventFilters()
 
 1502    ui->SearchText->installEventFilter(
this);
 
 1503    ui->userNotesEdit->installEventFilter(
this);
 
 1504    ui->keywordEdit->installEventFilter(
this);
 
 1505    ui->ImagePreviewCreditLink->installEventFilter(
this);
 
 1506    ui->ImagePreviewCredit->installEventFilter(
this);
 
 1507    ui->ImagePreview->installEventFilter(
this);
 
 1508    ui->CatalogView->viewport()->installEventFilter(
this);
 
 1509    ui->CatalogView->installEventFilter(
this);
 
 1510    ui->helpButton->installEventFilter(
this);
 
 1513void ImagingPlanner::removeEventFilters()
 
 1515    ui->SearchText->removeEventFilter(
this);
 
 1516    ui->userNotesEdit->removeEventFilter(
this);
 
 1517    ui->keywordEdit->removeEventFilter(
this);
 
 1518    ui->ImagePreviewCreditLink->removeEventFilter(
this);
 
 1519    ui->ImagePreviewCredit->removeEventFilter(
this);
 
 1520    ui->ImagePreview->removeEventFilter(
this);
 
 1521    ui->CatalogView->viewport()->removeEventFilter(
this);
 
 1522    ui->helpButton->removeEventFilter(
this);
 
 1525void ImagingPlanner::openOptionsMenu()
 
 1527    QSharedPointer<ImagingPlannerOptions> options(
new ImagingPlannerOptions(
this));
 
 1533void ImagingPlanner::getHelp()
 
 1536    const QUrl url(
"https://kstars-docs.kde.org/en/user_manual/tool-imaging-planner.html");
 
 1541KSMoon *ImagingPlanner::getMoon()
 
 1543    if (KStarsData::Instance() == 
nullptr)
 
 1549        auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 1550        KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 1552        CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
 
 1553        KSNumbers numbers(midnight.
djd());
 
 1554        moon->
updateCoords(&numbers, 
true, getGeo()->lat(), &LST, 
true);
 
 1560void ImagingPlanner::updateMoon()
 
 1562    KSMoon *moon = getMoon();
 
 1567    auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 1568    KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 1569    CachingDms LST = getGeo()->GSTtoLST(getGeo()->LTtoUT(midnight).gst());
 
 1570    KSNumbers numbers(midnight.
djd());
 
 1572    sun->
updateCoords(&numbers, 
true, getGeo()->lat(), &LST, 
true);
 
 1576    ui->moonPercentLabel->setText(QString(
"%1%").arg(moon->
illum() * 100.0 + 0.5, 0, 
'f', 0));
 
 1579bool ImagingPlanner::scrollToName(
const QString &name)
 
 1583    QModelIndexList matchList = ui->CatalogView->model()->match(ui->CatalogView->model()->index(0, 0), 
Qt::EditRole,
 
 1585    if(matchList.count() >= 1)
 
 1588        for (
int i = 0; i < matchList.count(); i++)
 
 1590            QString nn = ui->CatalogView->model()->data(matchList[i], 
Qt::DisplayRole).toString();
 
 1597        ui->CatalogView->scrollTo(matchList[bestIndex]);
 
 1598        ui->CatalogView->setCurrentIndex(matchList[bestIndex]);
 
 1604void ImagingPlanner::searchSlot()
 
 1606    if (m_loadingCatalog)
 
 1608    QString origName = ui->SearchText->toPlainText().trimmed();
 
 1609    QString 
name = tweakNames(origName);
 
 1610    ui->SearchText->setPlainText(name);
 
 1614    if (!scrollToName(name))
 
 1615        KSNotification::sorry(
i18n(
"No match for \"%1\"", origName));
 
 1618    ui->SearchText->clear();
 
 1619    ui->SearchText->setPlainText(
"");
 
 1622void ImagingPlanner::initUserNotes()
 
 1624    ui->userNotesLabel->setVisible(
true);
 
 1625    ui->userNotesEdit->setVisible(
false);
 
 1626    ui->userNotesEditButton->setVisible(
true);
 
 1627    ui->userNotesDoneButton->setVisible(
false);
 
 1628    ui->userNotes->setVisible(
true);
 
 1629    ui->userNotesLabel->setVisible(
true);
 
 1630    ui->userNotesOpenLink->setVisible(
false);
 
 1631    ui->userNotesOpenLink2->setVisible(
false);
 
 1632    ui->userNotesOpenLink3->setVisible(
false);
 
 1635void ImagingPlanner::disableUserNotes()
 
 1637    ui->userNotesEdit->setVisible(
false);
 
 1638    ui->userNotesEditButton->setVisible(
false);
 
 1639    ui->userNotesDoneButton->setVisible(
false);
 
 1640    ui->userNotes->setVisible(
false);
 
 1641    ui->userNotesLabel->setVisible(
false);
 
 1642    ui->userNotesOpenLink->setVisible(
false);
 
 1643    ui->userNotesOpenLink2->setVisible(
false);
 
 1644    ui->userNotesOpenLink3->setVisible(
false);
 
 1647void ImagingPlanner::userNotesEditFinished()
 
 1649    const QString ¬es = ui->userNotesEdit->toPlainText().
trimmed();
 
 1650    ui->userNotes->setText(notes);
 
 1651    ui->userNotesLabel->setVisible(notes.
isEmpty());
 
 1652    ui->userNotesEdit->setVisible(
false);
 
 1653    ui->userNotesEditButton->setVisible(
true);
 
 1654    ui->userNotesDoneButton->setVisible(
false);
 
 1655    ui->userNotes->setVisible(
true);
 
 1656    ui->userNotesLabel->setVisible(
true);
 
 1657    setCurrentObjectNotes(notes);
 
 1658    setupNotesLinks(notes);
 
 1660    auto o = currentCatalogObject();
 
 1662    saveToDB(currentObjectName(), currentObjectFlags(), notes);
 
 1665void ImagingPlanner::updateNotes(
const QString ¬es)
 
 1667    ui->userNotes->setMaximumWidth(ui->RightPanel->width() - 125);
 
 1669    ui->userNotes->setText(notes);
 
 1670    ui->userNotesLabel->setVisible(notes.
isEmpty());
 
 1671    setupNotesLinks(notes);
 
 1674void ImagingPlanner::setupNotesLinks(
const QString ¬es)
 
 1676    QString 
link = findUrl(notes);
 
 1677    ui->userNotesOpenLink->setVisible(!
link.isEmpty());
 
 1678    if (!
link.isEmpty())
 
 1679        ui->userNotesOpenLink->setToolTip(
i18n(
"Open a browser with the 1st link in this note: %1", link));
 
 1681    link = findUrl(notes, 2);
 
 1682    ui->userNotesOpenLink2->setVisible(!
link.isEmpty());
 
 1683    if (!
link.isEmpty())
 
 1684        ui->userNotesOpenLink2->setToolTip(
i18n(
"Open a browser with the 2nd link in this note: %1", link));
 
 1686    link = findUrl(notes, 3);
 
 1687    ui->userNotesOpenLink3->setVisible(!
link.isEmpty());
 
 1688    if (!
link.isEmpty())
 
 1689        ui->userNotesOpenLink3->setToolTip(
i18n(
"Open a browser with the 3rd link in this note: %1", link));
 
 1692bool ImagingPlanner::internetNameSearch(
const QString &name, 
bool abellPlanetary, 
int abellNumber,
 
 1696    QElapsedTimer timer;
 
 1698    QString filteredName = 
name;
 
 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(),
 
 1738bool isAbellPlanetary(
const QString &name, 
int *number)
 
 1744        auto match = abellRE.match(name);
 
 1745        if (
match.hasMatch())
 
 1763    std::list<CatalogObject> objs =
 
 1764        m_manager.find_objects_by_name(filteredName, 1, 
true);
 
 1768    int abellNumber = 0;
 
 1769    bool abellPlanetary = isAbellPlanetary(name, &abellNumber);
 
 1770    if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
 
 1773    if (objs.size() == 0 && filteredName.
size() > 0)
 
 1776        const QString capitalized = capitalize(filteredName);
 
 1777        objs = m_manager.find_objects_by_name(capitalized, 1, 
true);
 
 1778        if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
 
 1781        if (objs.size() == 0)
 
 1784            const QString lowerCase = filteredName.
toLower();
 
 1785            objs = m_manager.find_objects_by_name(lowerCase, 1, 
true);
 
 1786            if (objs.size() > 0 && abellPlanetary && objs.front().type() == SkyObject::GALAXY_CLUSTER)
 
 1795        QString name2 = filteredName;
 
 1797        objs = m_manager.find_objects_by_name(name2, 1, 
true);
 
 1801        QString name2 = filteredName;
 
 1803        objs = m_manager.find_objects_by_name(name2, 1, 
true);
 
 1806    if (objs.size() == 0 && !abellPlanetary)
 
 1807        objs = m_manager.find_objects_by_name(filteredName.
toLower(), 20, 
false);
 
 1808    if (objs.size() == 0)
 
 1809        return internetNameSearch(filteredName, abellPlanetary,  abellNumber, catObject);
 
 1811    if (objs.size() == 0)
 
 1815    *catObject = objs.front();
 
 1816    if (objs.size() >= 1)
 
 1818        bool foundIt = 
false;
 
 1819        QString addSpace = filteredName;
 
 1821        QString addComma = filteredName;
 
 1823        QString sh2Fix = filteredName;
 
 1825        for (
const auto &obj : objs)
 
 1843            if (objs.size() == 1)
 
 1844                DPRINTF(stderr, 
" ========> \"%s\" had 1 match \"%s\", but not trusting it!!!!\n", 
name.
toLatin1().
data(),
 
 1845                        objs.front().name().toLatin1().data());
 
 1847            if (internetNameSearch(filteredName, abellPlanetary,  abellNumber, catObject))
 
 1850            DPRINTF(stderr, 
"Didn't find %s (%s) -- Not using name \"%s\" name2 \"%s\" longname \"%s\"\n",
 
 1865    auto o = m_CatalogHash.find(lName);
 
 1866    if (o == m_CatalogHash.end())
 
 1871void ImagingPlanner::clearObjects()
 
 1877    m_CatalogHash.clear();
 
 1885    if (getObject(lName) != 
nullptr)
 
 1887        DPRINTF(stderr, 
"Didn't add \"%s\" because it's already there\n", 
name.
toLatin1().
data());
 
 1892    if (!getKStarsCatalogObject(lName, &o))
 
 1894        DPRINTF(stderr, 
"************* Couldn't find \"%s\"\n", lName.
toLatin1().
data());
 
 1897    m_CatalogHash[lName] = o;
 
 1898    return &(m_CatalogHash[lName]);
 
 1903bool ImagingPlanner::addCatalogItem(
const KSAlmanac &ksal, 
const QString &name, 
int flags)
 
 1905    CatalogObject *
object = addObject(name);
 
 1906    if (
object == 
nullptr)
 
 1909    auto getItemWithUserRole = [](
const QString & itemText) -> QStandardItem *
 
 1911        QStandardItem *ret = 
new QStandardItem(itemText);
 
 1918    QList<QStandardItem *> itemList;
 
 1919    for (
int i = 0; i < LAST_COLUMN; ++i)
 
 1921        if (i == NAME_COLUMN)
 
 1923            itemList.
append(getItemWithUserRole(name));
 
 1925        else if (i == HOURS_COLUMN)
 
 1927            double runHours = getRunHours(*
object, getDate(), *getGeo(), ui->minAltitude->value(), ui->minMoon->value(),
 
 1928                                          ui->maxMoonAltitude->value(), ui->useArtificialHorizon->isChecked());
 
 1929            auto hoursItem = getItemWithUserRole(QString(
"%1").arg(runHours, 0, 
'f', 1));
 
 1930            hoursItem->setData(runHours, HOURS_ROLE);
 
 1931            itemList.
append(hoursItem);
 
 1933        else if (i == TYPE_COLUMN)
 
 1935            auto typeItem = getItemWithUserRole(QString(
"%1").arg(SkyObject::typeShortName(object->
type())));
 
 1936            typeItem->setData(object->
type(), TYPE_ROLE);
 
 1937            itemList.
append(typeItem);
 
 1939        else if (i == SIZE_COLUMN)
 
 1941            double size = std::max(object->
a(), object->
b());
 
 1942            auto sizeItem = getItemWithUserRole(QString(
"%1'").arg(
size, 0, 
'f', 1));
 
 1943            sizeItem->setData(
size, SIZE_ROLE);
 
 1944            itemList.
append(sizeItem);
 
 1946        else if (i == ALTITUDE_COLUMN)
 
 1948            const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
 
 1949            const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *
object, 0, 0);
 
 1950            auto altItem = getItemWithUserRole(QString(
"%1º").arg(altitude, 0, 
'f', 0));
 
 1951            altItem->setData(altitude, ALTITUDE_ROLE);
 
 1952            itemList.
append(altItem);
 
 1954        else if (i == MOON_COLUMN)
 
 1956            KSMoon *moon = getMoon();
 
 1962                auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 1963                KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 1965                KSNumbers numbers(midnight.
djd());
 
 1969                auto moonItem = getItemWithUserRole(QString(
"%1º").arg(separation, 0, 
'f', 0));
 
 1970                moonItem->setData(separation, MOON_ROLE);
 
 1971                itemList.
append(moonItem);
 
 1975                auto moonItem = getItemWithUserRole(QString(
""));
 
 1976                moonItem->setData(-1, MOON_ROLE);
 
 1979        else if (i == CONSTELLATION_COLUMN)
 
 1981            QString cname = KStarsData::Instance()
 
 1983                            ->constellationBoundary()
 
 1984                            ->constellationName(
object);
 
 1986            auto constellationItem = getItemWithUserRole(cname);
 
 1987            itemList.
append(constellationItem);
 
 1989        else if (i == COORD_COLUMN)
 
 1991            itemList.
append(getItemWithUserRole(shortCoordString(object->
ra0(), object->
dec0())));
 
 1993        else if (i == FLAGS_COLUMN)
 
 1995            QStandardItem *flag = getItemWithUserRole(
"flag");
 
 1996            flag->
setData(flags, FLAGS_ROLE);
 
 1999        else if (i == NOTES_COLUMN)
 
 2001            QStandardItem *notes = getItemWithUserRole(
"notes");
 
 2002            notes->
setData(QString(), NOTES_ROLE);
 
 2007            DPRINTF(stderr, 
"Bug in addCatalogItem() !\n");
 
 2012    emit addRow(itemList);
 
 2018    m_CatalogModel->appendRow(itemList);
 
 2022void ImagingPlanner::recompute()
 
 2024    setStatus(
i18n(
"Updating tables..."));
 
 2027    m_CatalogSortModel->setSourceModel(
nullptr);
 
 2029    QElapsedTimer timer;
 
 2032    auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 2033    KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 2034    KStarsDateTime ut  = getGeo()->LTtoUT(KStarsDateTime(midnight));
 
 2035    KSAlmanac ksal(ut, getGeo());
 
 2037    for (
int i = 0; i < m_CatalogModel->rowCount(); ++i)
 
 2039        const QString &
name = m_CatalogModel->item(i, 0)->text();
 
 2040        const CatalogObject *catalogEntry = getObject(name);
 
 2041        if (catalogEntry == 
nullptr)
 
 2043            DPRINTF(stderr, 
"************* Couldn't find \"%s\"\n", 
name.
toLatin1().
data());
 
 2046        double runHours = getRunHours(*catalogEntry, getDate(), *getGeo(), ui->minAltitude->value(),
 
 2047                                      ui->minMoon->value(), ui->maxMoonAltitude->value(), ui->useArtificialHorizon->isChecked());
 
 2048        QString hoursText = QString(
"%1").arg(runHours, 0, 
'f', 1);
 
 2049        QStandardItem *hItem = 
new QStandardItem(hoursText);
 
 2052        hItem->
setData(runHours, HOURS_ROLE);
 
 2053        m_CatalogModel->setItem(i, HOURS_COLUMN, hItem);
 
 2056        const auto time = KStarsDateTime(QDateTime(getDate(), QTime(12, 0)));
 
 2057        const double altitude = getMaxAltitude(ksal, getDate(), getGeo(), *catalogEntry, 0, 0);
 
 2058        QString altText = QString(
"%1º").arg(altitude, 0, 
'f', 0);
 
 2059        auto altItem = 
new QStandardItem(altText);
 
 2061        altItem->setData(altitude, ALTITUDE_ROLE);
 
 2062        m_CatalogModel->setItem(i, ALTITUDE_COLUMN, altItem);
 
 2064        KSMoon *moon = getMoon();
 
 2070            auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 2071            KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 2073            KSNumbers numbers(midnight.
djd());
 
 2077            QString moonText = QString(
"%1º").arg(separation, 0, 
'f', 0);
 
 2078            auto moonItem = 
new QStandardItem(moonText);
 
 2080            moonItem->setData(separation, MOON_ROLE);
 
 2081            m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
 
 2085            auto moonItem = 
new QStandardItem(
"");
 
 2087            moonItem->setData(-1, MOON_ROLE);
 
 2088            m_CatalogModel->setItem(i, MOON_COLUMN, moonItem);
 
 2092        const bool imaged = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & IMAGED_BIT;
 
 2094            highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN), 
true);
 
 2095        const bool picked = m_CatalogModel->item(i, FLAGS_COLUMN)->data(FLAGS_ROLE).toInt() & PICKED_BIT;
 
 2097            highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN), 
true);
 
 2100    m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
 
 2102    DPRINTF(stderr, 
"Recompute took %.1fs\n", timer.
elapsed() / 1000.0);
 
 2113bool ALREADY_CHECKING = 
false;
 
 2114int ALREADY_CHECKING_INDEX = -1;
 
 2116struct ObjectNeighbor
 
 2118    CatalogObject object;
 
 2121    ObjectNeighbor(CatalogObject o, 
double d, QString nei) : object(o), distance(d), neighbor(nei) {}
 
 2127void ImagingPlanner::checkTargets2(
bool backwards)
 
 2129    if (ALREADY_CHECKING)
 
 2132            ALREADY_CHECKING_INDEX--;
 
 2134            ALREADY_CHECKING_INDEX++;
 
 2136        if (sortedAddedObjects.size() == 0)
 
 2138            fprintf(stderr, 
"No TARGETS\n");
 
 2141        if (ALREADY_CHECKING_INDEX >= sortedAddedObjects.size())
 
 2142            ALREADY_CHECKING_INDEX = 0;
 
 2143        else if (ALREADY_CHECKING_INDEX < 0)
 
 2144            ALREADY_CHECKING_INDEX = sortedAddedObjects.size() - 1;
 
 2145        KStarsDateTime time = KStarsData::Instance()->
clock()->
utc();
 
 2146        dms lst = getGeo()->GSTtoLST(time.
gst());
 
 2147        CatalogObject &o = sortedAddedObjects[ALREADY_CHECKING_INDEX].object;
 
 2149        fprintf(stderr, 
"%d: %s\n", ALREADY_CHECKING_INDEX, o.
name().
toLatin1().
data());
 
 2152        bool keepGround = Options::showGround();
 
 2153        bool keepAnimatedSlew = Options::useAnimatedSlewing();
 
 2154        Options::setShowGround(
false);
 
 2155        Options::setUseAnimatedSlewing(
false);
 
 2159        Options::setShowGround(keepGround);
 
 2160        Options::setUseAnimatedSlewing(keepAnimatedSlew);
 
 2166void ImagingPlanner::checkTargets(
bool justCheckCurrentCatalog)
 
 2168    if (ALREADY_CHECKING)
 
 2170        checkTargets2(
false);
 
 2173    ALREADY_CHECKING = 
true;
 
 2176    FlagComponent *flags = KStarsData::Instance()->
skyComposite()->flags();
 
 2177    for (
int i = flags->
size() - 1; i >= 0; --i) flags->
remove(i);
 
 2178    int rows = m_CatalogModel->rowCount();
 
 2181    for (
int i = 0; i < rows; ++i)
 
 2183        const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
 
 2184        auto object = getObject(name);
 
 2188            flags->
add(SkyPoint(object->
ra(), object->
dec()), 
"J2000.0", 
"", name, 
Qt::red);
 
 2191    fprintf(stderr, 
"Added %d flags\n", numFlags);
 
 2195    QList<QString> targets;
 
 2196    QList<QString> newObjects;
 
 2197    if (!justCheckCurrentCatalog)
 
 2203        QFile inputFile(fileName);
 
 2206            QTextStream in(&inputFile);
 
 2209                const QString line = in.readLine().trimmed();
 
 2210                if (line.
size() > 0 && line[0] != 
'#' && newObjects.
indexOf(line) == -1)
 
 2215        if (newObjects.
size() == 0)
 
 2217            fprintf(stderr, 
"No New Targets\n");
 
 2222    QList<CatalogObject> addedObjects;
 
 2223    sortedAddedObjects.clear();
 
 2225    int count = 0, good = 0;
 
 2226    for (
int i = 0; i < rows; ++i)
 
 2228        const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
 
 2230        auto o = getObject(name);
 
 2238    fprintf(stderr, 
"********** %d/%d targets found. %d unique test objects\n", good, count, newObjects.
size());
 
 2242    if (!justCheckCurrentCatalog)
 
 2244        fprintf(stderr, 
"Adding: ");
 
 2245        for (
const auto &name : newObjects)
 
 2247            if (getObject(name) != 
nullptr)
 
 2252            CatalogObject object;
 
 2253            if (!getKStarsCatalogObject(name, &
object))
 
 2258            object.
setRA(
object.ra0());
 
 2259            object.setDec(
object.dec0());
 
 2262                fprintf(stderr, 
"%s had primary name %s -- reverting.\n",
 
 2264                object.setName(name);
 
 2270        fprintf(stderr, 
"\n--------------------------------------------------------\n");
 
 2274    for (
int i = 0; i < addedObjects.
size(); ++i)
 
 2276        auto &
object = addedObjects[i];
 
 2277        double closest = 1e9;
 
 2278        QString closestName;
 
 2279        for (
int j = 0; j < targets.
size(); ++j)
 
 2281            if (justCheckCurrentCatalog && i == j)
 
 2283            auto name2 = targets[j];
 
 2284            auto object2 = getObject(name2);
 
 2285            if (object2 == 
nullptr)
 
 2287                fprintf(stderr, 
"********************************************************* O2 for targets[%d]: %s null!\n", j,
 
 2291            object2->setRA(object2->ra0());
 
 2292            object2->setDec(object2->dec0());
 
 2293            const dms dist = 
object.angularDistanceTo(object2);
 
 2294            const double arcsecDist = dist.
Degrees() * 3600.0;
 
 2295            if (closest > arcsecDist)
 
 2297                closest = arcsecDist;
 
 2298                closestName = name2;
 
 2302        sortedAddedObjects.
push_back(ObjectNeighbor(addedObjects[i], closest, closestName));
 
 2306        if (justCheckCurrentCatalog)
 
 2308            fprintf(stderr, 
"%7.1f %-10s closest %s\n", closest / 60.0, 
object.
name().toLatin1().data(),
 
 2313            double closestNew = 1e9;
 
 2314            QString closestNewName;
 
 2315            for (
int j = 0; j < addedObjects.
size() - 1; ++j)
 
 2317                if (i == j) 
continue;
 
 2318                auto object2 = addedObjects[j];
 
 2319                object2.setRA(object2.ra0());
 
 2320                object2.setDec(object2.dec0());
 
 2321                const dms dist = 
object.angularDistanceTo(&object2);
 
 2322                const double arcsecDist = dist.
Degrees() * 3600.0;
 
 2323                if (closestNew > arcsecDist)
 
 2325                    closestNew = arcsecDist;
 
 2326                    closestNewName = object2.name();
 
 2329            fprintf(stderr, 
"%7.1f %-10s (closest %s) (closestNew %5.0f' %-10s)\n",
 
 2330                    closest / 60.0, 
object.
name().toLatin1().data(), closestName.
toLatin1().
data(),
 
 2332            flags->
add(SkyPoint(
object.ra(), 
object.
dec()), 
"J2000.0", 
"", QString(
"%1").arg(
object.
name()), 
Qt::yellow);
 
 2335    std::sort(sortedAddedObjects.begin(), sortedAddedObjects.end(),
 
 2336              [](
const ObjectNeighbor & a, 
const ObjectNeighbor & b)
 
 2338        return a.distance > b.distance;
 
 2340    if (justCheckCurrentCatalog)
 
 2342        fprintf(stderr, 
"Sorted: ------------------------------------------\n");
 
 2343        for (
const auto &o : sortedAddedObjects)
 
 2344            fprintf(stderr, 
"%7.1f %-10s closest %s\n",
 
 2346                    o.neighbor.toLatin1().data());
 
 2348    fprintf(stderr, 
"DONE. ------------------------------------------\n");
 
 2352QString ImagingPlanner::defaultDirectory()
 const 
 2366QFileInfoList findDefaultDirectories()
 
 2369    QDir kDir(kstarsDir);
 
 2372    nameFilters << 
"ImagingPlanner*";
 
 2373    QFileInfoList dirs1 = kDir.entryInfoList(nameFilters);
 
 2378    dirs1.append(dirs2);
 
 2379    std::sort(dirs1.begin(), dirs1.end(), sortOldest);
 
 2386QString ImagingPlanner::findDefaultCatalog()
 const 
 2388    QFileInfoList subDirs = findDefaultDirectories();
 
 2389    for( 
const auto &dd : subDirs)
 
 2391        QDir subDir(dd.absoluteFilePath());
 
 2392        const QStringList csvFilter({
"*.csv"});
 
 2394        if (files.size() > 0)
 
 2399            for (
const auto &file : files)
 
 2402                    firstFile = file.absoluteFilePath();
 
 2404                    return file.absoluteFilePath();
 
 2413void ImagingPlanner::loadInitialCatalog()
 
 2415    QString catalog = Options::imagingPlannerCatalogPath();
 
 2417        catalog = findDefaultCatalog();
 
 2420        KSNotification::sorry(
 
 2421            i18n(
"You need to load a catalog to start using this tool.\n" 
 2422                 "Use the Load Catalog button if you have one.\n" 
 2423                 "See Data -> Download New Data if not..."));
 
 2424        setStatus(
i18n(
"No Catalog!"));
 
 2427        loadCatalog(catalog);
 
 2430void ImagingPlanner::setStatus(
const QString &message)
 
 2432    ui->statusLabel->setText(message);
 
 2435void ImagingPlanner::catalogLoaded()
 
 2437    DPRINTF(stderr, 
"All catalogs loaded: %d of %d have catalog images\n", m_numWithImage, m_numWithImage + m_numMissingImage);
 
 2443    ui->CatalogView->setColumnHidden(FLAGS_COLUMN, 
true);
 
 2444    ui->CatalogView->setColumnHidden(NOTES_COLUMN, 
true);
 
 2446    m_CatalogSortModel->invalidate();
 
 2448    ui->CatalogView->resizeColumnsToContents();
 
 2451    auto index = ui->CatalogView->
model()->
index(0, 0);
 
 2453    ui->CatalogView->selectionModel()->select(index,
 
 2455    ui->CatalogView->setFocus();
 
 2462void ImagingPlanner::updateStatus()
 
 2464    if (currentObjectName().isEmpty())
 
 2466        const int numDisplayedObjects = m_CatalogSortModel->rowCount();
 
 2467        const int totalCatalogObjects = m_CatalogModel->rowCount();
 
 2469        if (numDisplayedObjects > 0)
 
 2470            setStatus(
i18n(
"Select an object."));
 
 2471        else if (totalCatalogObjects > 0)
 
 2472            setStatus(
i18n(
"Check Filters to unhide objects."));
 
 2474            setStatus(
i18n(
"Load a Catalog."));
 
 2481void ImagingPlanner::showEvent(
QShowEvent * e)
 
 2484    if (m_initialShow == 
false)
 
 2486        m_initialShow = 
true;
 
 2494void ImagingPlanner::slotClose()
 
 2500QUrl ImagingPlanner::getAstrobinUrl(
const QString &target, 
bool requireAwards, 
bool requireSomeFilters, 
double minRadius,
 
 2503    QString myQuery = QString(
"text={\"value\":\"%1\",\"matchType\":\"ALL\"}").arg(target);
 
 2506    auto localTime = getGeo()->UTtoLT(KStarsData::Instance()->clock()->utc());
 
 2507    QDate today = localTime.date();
 
 2508    myQuery.
append(QString(
"&date_acquired={\"min\":\"2018-01-01\",\"max\":\"%1\"}").arg(today.
toString(
"yyyy-MM-dd")));
 
 2511        myQuery.
append(QString(
"&award=[\"iotd\",\"top-pick\",\"top-pick-nomination\"]"));
 
 2513    if (requireSomeFilters)
 
 2514        myQuery.
append(QString(
"&filter_types={\"value\":[\"H_ALPHA\",\"SII\",\"OIII\",\"R\",\"G\",\"B\"],\"matchType\":\"ANY\"}"));
 
 2516    if ((minRadius > 0 || maxRadius > 0) && (maxRadius > minRadius))
 
 2517        myQuery.
append(QString(
"&field_radius={\"min\":%1,\"max\":%2}").arg(minRadius).arg(maxRadius));
 
 2522    QByteArray packed = pack(b);
 
 2524    QByteArray compressed = qCompress(packed).remove(0, 4);
 
 2526    QByteArray b64 = compressed.
toBase64();
 
 2528    replaceByteArrayChars(b64, 
'+', QByteArray(
"%2B"));
 
 2529    replaceByteArrayChars(b64, 
'=', QByteArray(
"%3D"));
 
 2530    replaceByteArrayChars(b, 
'"', QByteArray(
"%22"));
 
 2531    replaceByteArrayChars(b, 
':', QByteArray(
"%3A"));
 
 2532    replaceByteArrayChars(b, 
'[', QByteArray(
"%5B"));
 
 2533    replaceByteArrayChars(b, 
']', QByteArray(
"%5D"));
 
 2534    replaceByteArrayChars(b, 
',', QByteArray(
"%2C"));
 
 2535    replaceByteArrayChars(b, 
'\'', QByteArray(
"%27"));
 
 2536    replaceByteArrayChars(b, 
'{', QByteArray(
"%7B"));
 
 2537    replaceByteArrayChars(b, 
'}', QByteArray(
"%7D"));
 
 2539    QString url = QString(
"https://app.astrobin.com/search?p=%1").arg(b64.
toStdString().c_str());
 
 2543void ImagingPlanner::popupAstrobin(
const QString &target)
 
 2545    QString newStr = replaceSpaceWith(target, 
"-");
 
 2548    const QUrl url = getAstrobinUrl(newStr, Options::astrobinAward(), 
false, Options::astrobinMinRadius(),
 
 2549                                    Options::astrobinMaxRadius());
 
 2558bool ImagingPlanner::checkIfPageExists(
const QString &urlString)
 
 2563    QUrl url(urlString);
 
 2564    QNetworkRequest request(url);
 
 2565    QNetworkReply *reply = m_networkManager.get(request);
 
 2598void ImagingPlanner::adjustSpecialWebPageButton(
const QString &name)
 
 2604        toolTip = 
i18n(
"Search the Professor Seligman online site for NGC images.");
 
 2609        toolTip = 
i18n(
"Search the Professor Seligman online site for information about IC objects..");
 
 2614        label = 
"Sharpless";
 
 2615        toolTip = 
i18n(
"Search the galaxymap.org online site for information about Sharpless2 objects.");
 
 2621        toolTip = 
i18n(
"Search Nasa's online site for information about Messier objects..");
 
 2626        toolTip = 
i18n(
"Search Emil Ivanov's online site for information about VDB objects.");
 
 2633        const int num = numberPart.
toInt(&ok);
 
 2637            ui->searchSpecialWebPageImages->setText(catalog);
 
 2638            ui->searchSpecialWebPageImages2->setText(catalog);
 
 2639            ui->searchSpecialWebPageImages->setEnabled(
true);
 
 2640            ui->searchSpecialWebPageImages2->setEnabled(
true);
 
 2641            ui->searchSpecialWebPageImages->setToolTip(
toolTip);
 
 2642            ui->searchSpecialWebPageImages2->setToolTip(
toolTip);
 
 2646    ui->searchSpecialWebPageImages->setText(
"");
 
 2647    ui->searchSpecialWebPageImages2->setText(
"");
 
 2648    ui->searchSpecialWebPageImages->setEnabled(
false);
 
 2649    ui->searchSpecialWebPageImages2->setEnabled(
false);
 
 2650    ui->searchSpecialWebPageImages->setToolTip(
"");
 
 2651    ui->searchSpecialWebPageImages2->setToolTip(
"");
 
 2655void ImagingPlanner::searchSpecialWebPageImages()
 
 2658    const QString 
objectName = currentObjectName();
 
 2663        const QString numberPart = 
objectName.mid(3).trimmed();
 
 2664        const int num = numberPart.
toInt(&ok);
 
 2666            urlString = QString(
"https://cseligman.com/text/atlas/ngc%1%2.htm#%3")
 
 2667                        .
arg(num / 100).
arg(num % 100 < 50 ? 
"" : 
"a").
arg(num);
 
 2671        const QString numberPart = 
objectName.mid(2).trimmed();
 
 2672        const int num = numberPart.
toInt(&ok);
 
 2674            urlString = QString(
"https://cseligman.com/text/atlas/ic%1%2.htm#ic%3")
 
 2675                        .
arg(num / 100).
arg(num % 100 < 50 ? 
"" : 
"a").
arg(num);
 
 2679        const QString numberPart = 
objectName.mid(3).trimmed();
 
 2680        const int num = numberPart.
toInt(&ok);
 
 2682            urlString = QString(
"http://galaxymap.org/cat/view/sharpless/%1").
arg(num);
 
 2686        const QString numberPart = 
objectName.mid(1).trimmed();
 
 2687        const int num = numberPart.
toInt(&ok);
 
 2689            urlString = QString(
"https://science.nasa.gov/mission/hubble/science/" 
 2690                                "explore-the-night-sky/hubble-messier-catalog/messier-%1").
arg(num);
 
 2694        const QString numberPart = 
objectName.mid(3).trimmed();
 
 2695        const int num = numberPart.
toInt(&ok);
 
 2698            urlString = QString(
"https://www.irida-observatory.org/CCD/VdB%1/VdB%1.html").
arg(num);
 
 2699            if (!checkIfPageExists(urlString))
 
 2700                urlString = 
"https://www.emilivanov.com/CCD%20Images/Catalog_VdB.htm";
 
 2707void ImagingPlanner::searchSimbad()
 
 2710    QString 
name = currentObjectName();
 
 2712    int abellNumber = 0;
 
 2713    bool abellPlanetary = isAbellPlanetary(name, &abellNumber);
 
 2715        name = QString(
"PN A66 %1").
arg(abellNumber);
 
 2717        name.
replace(QRegularExpression(
"sh2\\s*"), 
"sh2-");
 
 2726    QString urlStr = QString(
"https://simbad.cds.unistra.fr/simbad/sim-id?Ident=%1&NbIdent=1" 
 2727                             "&Radius=20&Radius.unit=arcmin&submit=submit+id").
arg(name);
 
 2733void ImagingPlanner::searchWikipedia()
 
 2736    QString wikipediaAddress = 
"https://en.wikipedia.org";
 
 2737    QString 
name = currentObjectName();
 
 2740        DPRINTF(stderr, 
"NULL object sent to Wikipedia.\n");
 
 2746    QString urlStr = QString(
"%1/w/index.php?search=%2").
arg(wikipediaAddress).
arg(replaceSpaceWith(name, 
"_"));
 
 2751void ImagingPlanner::searchAstrobin()
 
 2754    QString 
name = currentObjectName();
 
 2757    popupAstrobin(name);
 
 2760bool ImagingPlanner::eventFilter(
QObject * obj, 
QEvent * event)
 
 2762    if (m_loadingCatalog)
 
 2768        m_InitialLoad = 
false;
 
 2769        setStatus(
i18n(
"Loading Catalogs..."));
 
 2774    QMouseEvent *mouseEvent = 
static_cast<QMouseEvent *
>(
event);
 
 2776    if ((obj == ui->helpButton) &&
 
 2779            (mouseEvent->
modifiers() & Qt::KeyboardModifier::ShiftModifier) &&
 
 2780            (mouseEvent->
modifiers() & Qt::KeyboardModifier::ControlModifier) &&
 
 2781            (mouseEvent->
modifiers() & Qt::KeyboardModifier::AltModifier))
 
 2785        ui->DevelFrame->setVisible(!ui->DevelFrame->isVisible());
 
 2796    else if ((obj == ui->CatalogView->viewport()) &&
 
 2800        int numImaged = 0, numNotImaged = 0, numPicked = 0, numNotPicked = 0, numIgnored = 0, numNotIgnored = 0;
 
 2801        QStringList selectedNames;
 
 2802        for (
const auto &r : ui->CatalogView->selectionModel()->selectedRows())
 
 2804            selectedNames.
append(r.siblingAtColumn(0).
data().toString());
 
 2805            bool isPicked = getFlag(r, PICKED_BIT, ui->CatalogView->model());
 
 2806            if (isPicked) numPicked++;
 
 2807            else numNotPicked++;
 
 2808            bool isImaged = getFlag(r, IMAGED_BIT, ui->CatalogView->model());
 
 2809            if (isImaged) numImaged++;
 
 2810            else numNotImaged++;
 
 2811            bool isIgnored = getFlag(r, IGNORED_BIT, ui->CatalogView->model());
 
 2812            if (isIgnored) numIgnored++;
 
 2813            else numNotIgnored++;
 
 2816        if (selectedNames.
size() == 0)
 
 2820            m_PopupMenu = 
new ImagingPlannerPopup;
 
 2822        const bool imaged = numImaged > 0;
 
 2823        const bool picked = numPicked > 0;
 
 2824        const bool ignored = numIgnored > 0;
 
 2825        m_PopupMenu->init(
this, selectedNames,
 
 2826                          (numImaged > 0 && numNotImaged > 0) ? 
nullptr : &imaged,
 
 2827                          (numPicked > 0 && numNotPicked > 0) ? 
nullptr : &picked,
 
 2828                          (numIgnored > 0 && numNotIgnored > 0) ? 
nullptr : &ignored);
 
 2830        m_PopupMenu->popup(
pos);
 
 2834        userNotesEditFinished();
 
 2837        keywordEditFinished();
 
 2848                keywordEditFinished();
 
 2849                ui->keywordEdit->clearFocus();
 
 2872    else if ((obj == ui->ImagePreview ||
 
 2873              obj == ui->ImagePreviewCredit ||
 
 2874              obj == ui->ImagePreviewCreditLink) &&
 
 2877        if (!ui->ImagePreviewCreditLink->text().isEmpty())
 
 2879            QUrl url(ui->ImagePreviewCreditLink->text());
 
 2887void ImagingPlanner::keywordEditFinished()
 
 2889    QString kwd = ui->keywordEdit->toPlainText().trimmed();
 
 2890    ui->keywordEdit->clear();
 
 2891    ui->keywordEdit->setText(kwd);
 
 2892    if (m_Keyword != kwd)
 
 2895        Options::setImagingPlannerKeyword(kwd);
 
 2896        Options::self()->save();
 
 2897        updateSortConstraints();
 
 2898        m_CatalogSortModel->invalidate();
 
 2899        ui->CatalogView->resizeColumnsToContents();
 
 2904void ImagingPlanner::setDefaultImage()
 
 2906    ui->ImagePreview->setPixmap(m_NoImagePixmap);
 
 2907    ui->ImagePreview->update();
 
 2908    ui->ImagePreviewCredit->setText(
"");
 
 2909    ui->ImagePreviewCreditLink->setText(
"");
 
 2914    if (m_loadingCatalog)
 
 2917    Q_UNUSED(deselected);
 
 2918    if (selected.
indexes().size() == 0)
 
 2926    auto selection = selected.
indexes()[0];
 
 2927    QString 
name = selection.
data().toString();
 
 2928    CatalogObject *
object = getObject(name);
 
 2929    if (
object == 
nullptr)
 
 2936    ui->ImagePreviewCredit->setText(
"");
 
 2937    ui->ImagePreviewCreditLink->setText(
"");
 
 2940    CatalogImageInfo catalogImageInfo;
 
 2941    if (findCatalogImageInfo(name, &catalogImageInfo))
 
 2943        QString filename = catalogImageInfo.m_Filename;
 
 2944        if (!filename.
isEmpty() && !Options::imagingPlannerCatalogPath().isEmpty())
 
 2946            QString imageFullPath = filename;
 
 2947            if (QFileInfo(filename).isRelative())
 
 2949                QString catDir = QFileInfo(Options::imagingPlannerCatalogPath()).absolutePath();
 
 2950                imageFullPath = QString(
"%1%2%3").
arg(catDir)
 
 2953            if (!QFile(imageFullPath).exists())
 
 2954                DPRINTF(stderr, 
"Image for \"%s\" -- \"%s\" doesn't exist\n",
 
 2958            if (!catalogImageInfo.m_Link.
isEmpty())
 
 2960                ui->ImagePreviewCreditLink->setText(catalogImageInfo.m_Link);
 
 2961                ui->ImagePreview->setToolTip(
"Click to see original");
 
 2962                ui->ImagePreviewCreditLink->setToolTip(
"Click to see original");
 
 2966                ui->ImagePreviewCreditLink->setText(
"");
 
 2967                ui->ImagePreview->setToolTip(
"");
 
 2968                ui->ImagePreviewCreditLink->setToolTip(
"");
 
 2971            if (!catalogImageInfo.m_Author.
isEmpty() && !catalogImageInfo.m_License.
isEmpty())
 
 2973                ui->ImagePreviewCredit->setText(
 
 2974                    QString(
"Credit: %1 (with license %2)").arg(catalogImageInfo.m_Author)
 
 2975                    .arg(creativeCommonsString(catalogImageInfo.m_License)));
 
 2976                ui->ImagePreviewCredit->setToolTip(
 
 2977                    QString(
"Original image license: %1")
 
 2978                    .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
 
 2980            else if (!catalogImageInfo.m_Author.
isEmpty())
 
 2982                ui->ImagePreviewCredit->setText(
 
 2983                    QString(
"Credit: %1").arg(catalogImageInfo.m_Author));
 
 2984                ui->ImagePreviewCredit->setToolTip(
"");
 
 2986            else if (!catalogImageInfo.m_License.
isEmpty())
 
 2988                ui->ImagePreviewCredit->setText(
 
 2989                    QString(
"(license %1)").arg(creativeCommonsString(catalogImageInfo.m_License)));
 
 2990                ui->ImagePreviewCredit->setToolTip(
 
 2991                    QString(
"Original image license: %1")
 
 2992                    .arg(creativeCommonsTooltipString(catalogImageInfo.m_License)));
 
 2996                ui->ImagePreviewCredit->setText(
"");
 
 2997                ui->ImagePreviewCredit->setToolTip(
"");
 
 3003        object->load_image();
 
 3004        auto image = 
object->image();
 
 3010            const QString foundFilename = findObjectImage(name);
 
 3013                constexpr int thumbHeight = 300, thumbWidth = 400;
 
 3014                const QImage img = QImage(foundFilename);
 
 3015                const bool scale = img.
width() > thumbWidth || img.
height() > thumbHeight;
 
 3017                    ui->ImagePreview->setPixmap(
 
 3028    adjustSpecialWebPageButton(currentObjectName());
 
 3031void ImagingPlanner::updateDisplays()
 
 3036    if (!currentCatalogObject())
 
 3038        if (ui->CatalogView->model()->rowCount() > 0)
 
 3040            auto index = ui->CatalogView->
model()->
index(0, 0);
 
 3041            ui->CatalogView->selectionModel()->select(index,
 
 3046    auto object = currentCatalogObject();
 
 3049        updateDetails(*
object, currentObjectFlags());
 
 3050        updateNotes(currentObjectNotes());
 
 3051        plotAltitudeGraph(getDate(), object->
ra0(), object->
dec0());
 
 3058void ImagingPlanner::updateDetails(
const CatalogObject &
object, 
int flags)
 
 3060    ui->infoObjectName->setText(
object.
name());
 
 3061    ui->infoSize->setText(QString(
"%1' x %2'").arg(
object.a(), 0, 
'f', 1).arg(
object.b(), 0, 
'f', 1));
 
 3063    QPalette 
palette = ui->infoObjectLongName->palette();
 
 3066    ui->infoObjectLongName->setPalette(
palette);
 
 3067    if (
object.longname().isEmpty() || (
object.longname() == 
object.
name()))
 
 3068        ui->infoObjectLongName->clear();
 
 3070        ui->infoObjectLongName->setText(QString(
"(%1)").arg(
object.longname()));
 
 3074    auto noon = KStarsDateTime(getDate(), QTime(12, 0, 0));
 
 3075    QTime riseTime = 
object.riseSetTime(noon, getGeo(), 
true);
 
 3076    QTime setTime = 
object.riseSetTime(noon, getGeo(), 
false);
 
 3077    QTime transitTime = 
object.transitTime(noon, getGeo());
 
 3078    dms transitAltitude = 
object.transitAltitude(noon, getGeo());
 
 3081    KSMoon *moon = getMoon();
 
 3084        const double separation = ui->CatalogView->selectionModel()->currentIndex()
 
 3085                                  .siblingAtColumn(MOON_COLUMN).data(MOON_ROLE).toDouble();
 
 3087        if (separation >= 0)
 
 3088            moonString = QString(
"%1 \u2220 %3º").
arg(
i18n(
"Moon")).
arg(separation, 0, 
'f', 1);
 
 3091    QString riseSetString;
 
 3093        riseSetString = QString(
"%1 %2 @ %3º")
 
 3098        riseSetString = QString(
"%1 %2")
 
 3102        riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
 
 3109        riseSetString = QString(
"%1 %2")
 
 3113        riseSetString = QString(
"%1 %2 %3 %4 @ %5º")
 
 3120        riseSetString = QString(
"%1 %2 %3 %4")
 
 3126        riseSetString = QString(
"%1 %2 %3 %4 %5 %6 @ %7º")
 
 3134    if (moonString.
size() > 0)
 
 3135        riseSetString.
append(QString(
", %1").arg(moonString));
 
 3136    ui->infoRiseSet->setText(riseSetString);
 
 3138    palette = ui->infoObjectFlags->palette();
 
 3140    ui->infoObjectFlags->setPalette(
palette);
 
 3141    ui->infoObjectFlags->setText(flagString(flags));
 
 3150void ImagingPlanner::plotAltitudeGraph(
const QDate &date, 
const dms &ra, 
const dms &dec)
 
 3152    auto altitudeGraph = ui->altitudeGraph;
 
 3153    altitudeGraph->setAltitudeAxis(-20.0, 90.0);
 
 3156    QVector<QDateTime> jobStartTimes, jobEndTimes;
 
 3157    getRunTimes(date, *getGeo(), ui->minAltitude->value(), ui->minMoon->value(), ui->maxMoonAltitude->value(), ra, dec,
 
 3158                ui->useArtificialHorizon->isChecked(),
 
 3159                &jobStartTimes, &jobEndTimes);
 
 3161    auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 3162    KStarsDateTime midnight = KStarsDateTime(date.
addDays(1), QTime(0, 1));
 
 3165    KStarsDateTime ut  = getGeo()->LTtoUT(KStarsDateTime(midnight));
 
 3166    KSAlmanac ksal(ut, getGeo());
 
 3167    QDateTime dawn = midnight.
addSecs(24 * 3600 * ksal.getDawnAstronomicalTwilight());
 
 3169    QDateTime dusk = midnight.
addSecs(24 * 3600 * ksal.getDuskAstronomicalTwilight());
 
 3172    Ekos::SchedulerJob job;
 
 3173    setupJob(job, 
"temp", ui->minAltitude->value(), ui->minMoon->value(), ui->maxMoonAltitude->value(), ra, dec,
 
 3174             ui->useArtificialHorizon->isChecked());
 
 3176    QVector<double> times, alts;
 
 3177    QDateTime plotStart = dusk;
 
 3182    plotStart = plotStart.
addSecs(-1 * 3600);
 
 3185    auto plotEnd = dawn.
addSecs(1 * 3600);
 
 3188    while (t.secsTo(plotEnd) > 0)
 
 3190        SkyPoint coords = job.getTargetCoords();
 
 3191        double alt = getAltitude(getGeo(), coords, t);
 
 3193        double hour = midnight.
secsTo(t) / 3600.0;
 
 3195        t = t.addSecs(60 * 10);
 
 3198    altitudeGraph->plot(getGeo(), &ksal, times, alts);
 
 3200    for (
int i = 0; i < jobStartTimes.
size(); ++i)
 
 3202        auto startTime = jobStartTimes[i];
 
 3203        auto stopTime = jobEndTimes[i];
 
 3204        if (startTime < plotStart) startTime = plotStart;
 
 3205        if (stopTime > plotEnd) stopTime = plotEnd;
 
 3208        stopTime.setTimeZone(tz);
 
 3210        QVector<double> runTimes, runAlts;
 
 3215        while (t.secsTo(stopTime) > 0)
 
 3217            SkyPoint coords = job.getTargetCoords();
 
 3218            double alt = getAltitude(getGeo(), coords, t);
 
 3220            double hour = midnight.
secsTo(t) / 3600.0;
 
 3222            t = t.addSecs(60 * 10);
 
 3224        altitudeGraph->plotOverlay(runTimes, runAlts);
 
 3228void ImagingPlanner::updateCounts()
 
 3230    const int numDisplayedObjects = m_CatalogSortModel->rowCount();
 
 3231    const int totalCatalogObjects = m_CatalogModel->rowCount();
 
 3232    if (numDisplayedObjects == 1)
 
 3233        ui->tableCount->setText(QString(
"1/%1 %2").arg(totalCatalogObjects).arg(
i18n(
"object")));
 
 3235        ui->tableCount->setText(QString(
"%1/%2 %3").arg(numDisplayedObjects).arg(totalCatalogObjects).arg(
i18n(
"objects")));
 
 3238void ImagingPlanner::moveBackOneDay()
 
 3241    QString selection = currentObjectName();
 
 3242    ui->DateEdit->setDate(ui->DateEdit->date().addDays(-1));
 
 3246    scrollToName(selection);
 
 3249void ImagingPlanner::moveForwardOneDay()
 
 3251    QString selection = currentObjectName();
 
 3252    ui->DateEdit->setDate(ui->DateEdit->date().addDays(1));
 
 3256    scrollToName(selection);
 
 3259QString ImagingPlanner::currentObjectName()
 const 
 3261    QString 
name = ui->CatalogView->selectionModel()->currentIndex().siblingAtColumn(NAME_COLUMN).
data(
 
 3268    QString 
name = currentObjectName();
 
 3269    return getObject(name);
 
 3274void ImagingPlanner::objectDetails()
 
 3276    CatalogObject *current = currentCatalogObject();
 
 3277    if (current == 
nullptr)
 
 3279    auto ut = KStarsData::Instance()->
ut();
 
 3281    QPointer<DetailDialog> dd =
 
 3287void ImagingPlanner::centerOnSkymap()
 
 3289    if (!Options::imagingPlannerCenterOnSkyMap())
 
 3291    reallyCenterOnSkymap();
 
 3294void ImagingPlanner::reallyCenterOnSkymap()
 
 3296    CatalogObject *current = currentCatalogObject();
 
 3297    if (current == 
nullptr)
 
 3303        DPRINTF(stderr, 
"found a 0,0 object\n");
 
 3308    KStarsDateTime time = KStarsData::Instance()->
clock()->
utc();
 
 3309    dms lst = getGeo()->GSTtoLST(time.
gst());
 
 3314    bool keepGround = Options::showGround();
 
 3315    bool keepAnimatedSlew = Options::useAnimatedSlewing();
 
 3316    Options::setShowGround(
false);
 
 3317    Options::setUseAnimatedSlewing(
false);
 
 3323    Options::setShowGround(keepGround);
 
 3324    Options::setUseAnimatedSlewing(keepAnimatedSlew);
 
 3327void ImagingPlanner::setSelection(
int flag, 
bool enabled)
 
 3329    auto rows = ui->CatalogView->selectionModel()->selectedRows();
 
 3338    QList<QModelIndex> sourceIndeces;
 
 3339    for (
int i = 0; i < rows.size(); ++i)
 
 3341        auto proxyIndex  = rows[i].siblingAtColumn(FLAGS_COLUMN);
 
 3342        auto sourceIndex = m_CatalogSortModel->mapToSource(proxyIndex);
 
 3343        sourceIndeces.
append(sourceIndex);
 
 3346    for (
int i = 0; i < sourceIndeces.
size(); ++i)
 
 3348        auto &sourceIndex = sourceIndeces[i];
 
 3352            setFlag(sourceIndex, flag, m_CatalogModel.data());
 
 3354            clearFlag(sourceIndex, flag, m_CatalogModel.data());
 
 3356        QString 
name = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NAME_COLUMN)).toString();
 
 3357        int flags = m_CatalogModel->data(sourceIndex.siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
 
 3358        QString notes = m_CatalogModel->
data(sourceIndex.siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).
toString();
 
 3359        saveToDB(name, flags, notes);
 
 3361        if (flag == IMAGED_BIT)
 
 3362            highlightImagedObject(sourceIndex, 
enabled);
 
 3363        if (flag == PICKED_BIT)
 
 3364            highlightPickedObject(sourceIndex, 
enabled);
 
 3369void ImagingPlanner::highlightImagedObject(
const QModelIndex &index, 
bool imaged)
 
 3372    QColor m_DefaultCellBackground(36, 35, 35);
 
 3373    QColor m_ImagedObjectBackground(10, 65, 10);
 
 3374    QString themeName = KSTheme::Manager::instance()->currentThemeName().
toLatin1().
data();
 
 3375    if (themeName == 
"High Key" || themeName == 
"Default" || themeName == 
"White Balance")
 
 3377        m_DefaultCellBackground = QColor(240, 240, 240);
 
 3378        m_ImagedObjectBackground = QColor(180, 240, 180);
 
 3380    for (
int col = 0; col < LAST_COLUMN; ++col)
 
 3383        m_CatalogModel->setData(colIndex, imaged ? m_ImagedObjectBackground : m_DefaultCellBackground, 
Qt::BackgroundRole);
 
 3387void ImagingPlanner::highlightPickedObject(
const QModelIndex &index, 
bool picked)
 
 3389    for (
int col = 0; col < LAST_COLUMN; ++col)
 
 3393        auto ff = qvariant_cast<QFont>(
font);
 
 3395        ff.setItalic(picked);
 
 3396        ff.setUnderline(picked);
 
 3402void ImagingPlanner::setSelectionPicked()
 
 3404    setSelection(PICKED_BIT, 
true);
 
 3407void ImagingPlanner::setSelectionNotPicked()
 
 3409    setSelection(PICKED_BIT, 
false);
 
 3412void ImagingPlanner::setSelectionImaged()
 
 3414    setSelection(IMAGED_BIT, 
true);
 
 3417void ImagingPlanner::setSelectionNotImaged()
 
 3419    setSelection(IMAGED_BIT, 
false);
 
 3422void ImagingPlanner::setSelectionIgnored()
 
 3424    setSelection(IGNORED_BIT, 
true);
 
 3427void ImagingPlanner::setSelectionNotIgnored()
 
 3429    setSelection(IGNORED_BIT, 
false);
 
 3432int ImagingPlanner::currentObjectFlags()
 
 3434    auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(FLAGS_COLUMN);
 
 3435    const bool hasFlags = ui->CatalogView->model()->data(index, FLAGS_ROLE).canConvert<
int>();
 
 3438    return ui->CatalogView->model()->data(index, FLAGS_ROLE).toInt();
 
 3441QString ImagingPlanner::currentObjectNotes()
 
 3443    auto index = ui->CatalogView->selectionModel()->currentIndex().
siblingAtColumn(NOTES_COLUMN);
 
 3444    const bool hasNotes = ui->CatalogView->
model()->
data(index, NOTES_ROLE).
canConvert<QString>();
 
 3447    return ui->CatalogView->model()->data(index, NOTES_ROLE).toString();
 
 3450void ImagingPlanner::setCurrentObjectNotes(
const QString ¬es)
 
 3452    auto index = ui->CatalogView->selectionModel()->currentIndex();
 
 3457    auto sourceIndex = m_CatalogSortModel->mapToSource(sibling);
 
 3459    m_CatalogModel->setData(sourceIndex, n, NOTES_ROLE);
 
 3462ImagingPlannerPopup::ImagingPlannerPopup() : 
QMenu(nullptr)
 
 3471void ImagingPlannerPopup::init(ImagingPlanner * planner, 
const QStringList &names,
 
 3472                               const bool * imaged, 
const bool * picked, 
const bool * ignored)
 
 3475    if (names.
size() == 0) 
return;
 
 3478    if (names.
size() == 1)
 
 3480    else if (names.
size() <= 3)
 
 3483        for (
int i = 1; i < names.
size(); i++)
 
 3484            title.append(QString(
", %1").arg(names[i]));
 
 3487        title = 
i18n(
"%1, %2 and %3 other objects", names[0], names[1], names.
size() - 2);
 
 3491    QString word = names.
size() == 1 ? names[0] : 
i18n(
"objects");
 
 3493    if (imaged == 
nullptr)
 
 3495        addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
 
 3496        addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
 
 3499        addAction(
i18n(
"Mark %1 as NOT imaged", word), planner, &ImagingPlanner::setSelectionNotImaged);
 
 3501        addAction(
i18n(
"Mark %1 as already imaged", word), planner, &ImagingPlanner::setSelectionImaged);
 
 3503    if (picked == 
nullptr)
 
 3505        addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
 
 3506        addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
 
 3509        addAction(
i18n(
"Un-pick %1", word), planner, &ImagingPlanner::setSelectionNotPicked);
 
 3511        addAction(
i18n(
"Pick %1", word), planner, &ImagingPlanner::setSelectionPicked);
 
 3514    if (ignored == 
nullptr)
 
 3516        addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
 
 3517        addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
 
 3521        addAction(
i18n(
"Stop ignoring %1", word), planner, &ImagingPlanner::setSelectionNotIgnored);
 
 3523        addAction(
i18n(
"Ignore %1", word), planner, &ImagingPlanner::setSelectionIgnored);
 
 3526    addAction(
i18n(
"Center %1 on SkyMap", names[0]), planner, &ImagingPlanner::reallyCenterOnSkymap);
 
 3528    addAction(
i18n(
"Screenshot some image of %1, plate-solve it, and temporarily place it on the SkyMap", names[0]), planner,
 
 3529              &ImagingPlanner::takeScreenshot);
 
 3533ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name, 
bool picked, 
bool imaged,
 
 3534        bool ignored, 
const QString ¬es) : m_Name(
name), m_Notes(notes)
 
 3539ImagingPlannerDBEntry::ImagingPlannerDBEntry(
const QString &name, 
int flags, 
const QString ¬es)
 
 3540    : m_Name(
name), m_Flags(flags), m_Notes(notes)
 
 3544void ImagingPlannerDBEntry::getFlags(
bool * picked, 
bool * imaged, 
bool * ignored)
 
 3546    *picked = m_Flags & PickedBit;
 
 3547    *imaged = m_Flags & ImagedBit;
 
 3548    *ignored = m_Flags & IgnoredBit;
 
 3552void ImagingPlannerDBEntry::setFlags(
bool picked, 
bool imaged, 
bool ignored)
 
 3555    if (picked) m_Flags |= PickedBit;
 
 3556    if (imaged) m_Flags |= ImagedBit;
 
 3557    if (ignored) m_Flags |= IgnoredBit;
 
 3560void ImagingPlanner::saveToDB(
const QString &name, 
bool picked, 
bool imaged,
 
 3561                              bool ignored, 
const QString ¬es)
 
 3563    ImagingPlannerDBEntry e(name, 0, notes);
 
 3564    e.setFlags(picked, imaged, ignored);
 
 3568void ImagingPlanner::saveToDB(
const QString &name, 
int flags, 
const QString ¬es)
 
 3570    ImagingPlannerDBEntry e(name, flags, notes);
 
 3575void ImagingPlanner::loadFromDB()
 
 3580    m_CatalogSortModel->setSourceModel(
nullptr);
 
 3582    auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 3583    KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 3584    KStarsDateTime ut  = getGeo()->LTtoUT(KStarsDateTime(midnight));
 
 3585    KSAlmanac ksal(ut, getGeo());
 
 3587    QList<ImagingPlannerDBEntry> 
list;
 
 3589    QHash<QString, ImagingPlannerDBEntry> dbData;
 
 3590    QHash<QString, int> dbNotes;
 
 3591    for (
const auto &entry : list)
 
 3593        dbData[entry.m_Name] = entry;
 
 3596    int rows = m_CatalogModel->rowCount();
 
 3597    for (
int i = 0; i < rows; ++i)
 
 3599        const QString &
name = m_CatalogModel->item(i, NAME_COLUMN)->text();
 
 3600        auto entry = dbData.
find(name);
 
 3601        if (entry != dbData.
end())
 
 3603            QVariant f = entry->m_Flags;
 
 3604            m_CatalogModel->item(i, FLAGS_COLUMN)->setData(f, FLAGS_ROLE);
 
 3605            if (entry->m_Flags & IMAGED_BIT)
 
 3606                highlightImagedObject(m_CatalogModel->index(i, NAME_COLUMN), 
true);
 
 3607            if (entry->m_Flags & PICKED_BIT)
 
 3608                highlightPickedObject(m_CatalogModel->index(i, NAME_COLUMN), 
true);
 
 3609            QVariant n = entry->m_Notes;
 
 3610            m_CatalogModel->item(i, NOTES_COLUMN)->setData(n, NOTES_ROLE);
 
 3614    m_CatalogSortModel->setSourceModel(m_CatalogModel.data());
 
 3617void ImagingPlanner::loadImagedFile()
 
 3619    if (m_loadingCatalog)
 
 3627    QFile inputFile(fileName);
 
 3631        QStringList failedNames;
 
 3632        QTextStream in(&inputFile);
 
 3638            name = tweakNames(name);
 
 3639            if (getObject(name))
 
 3642                auto startIndex = m_CatalogModel->index(0, NAME_COLUMN);
 
 3643                QVariant value(name);
 
 3645                if (matches.size() > 0)
 
 3647                    setFlag(matches[0], IMAGED_BIT, m_CatalogModel);
 
 3648                    highlightImagedObject(matches[0], 
true);
 
 3651                    QString 
name = m_CatalogModel->
data(matches[0].siblingAtColumn(NAME_COLUMN)).toString();
 
 3652                    int flags = m_CatalogModel->data(matches[0].siblingAtColumn(FLAGS_COLUMN), FLAGS_ROLE).toInt();
 
 3653                    QString notes = m_CatalogModel->
data(matches[0].siblingAtColumn(NOTES_COLUMN), NOTES_ROLE).toString();
 
 3654                    saveToDB(name, flags, notes);
 
 3658                    DPRINTF(stderr, 
"ooops! internal inconsitency--got an object but match didn't work");
 
 3662                failedNames.
append(name);
 
 3665        if (failedNames.
size() == 0)
 
 3668                KSNotification::info(
i18n(
"Successfully marked %1 objects as read", numSuccess));
 
 3670                KSNotification::sorry(
i18n(
"Empty file"));
 
 3674            int num = std::min((
int)failedNames.
size(), 10);
 
 3675            QString sample = QString(
"\"%1\"").arg(failedNames[0]);
 
 3676            for (
int i = 1; i < num; ++i)
 
 3677                sample.
append(QString(
" \"%1\"").arg(failedNames[i]));
 
 3678            if (numSuccess == 0 && failedNames.
size() <= 10)
 
 3679                KSNotification::sorry(
i18n(
"Failed marking all of these objects imaged: %1", sample));
 
 3680            else if (numSuccess == 0)
 
 3681                KSNotification::sorry(
i18n(
"Failed marking %1 objects imaged, including: %2", failedNames.
size(), sample));
 
 3682            else if (numSuccess > 0 && failedNames.
size() <= 10)
 
 3683                KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2: %3",
 
 3684                                           numSuccess, failedNames.
size() == 1 ? 
"this" : 
"these", sample));
 
 3686                KSNotification::sorry(
i18n(
"Succeeded marking %1 objects imaged. Failed with %2 including these: %3",
 
 3687                                           numSuccess, failedNames.
size(), sample));
 
 3692        KSNotification::sorry(
i18n(
"Sorry, couldn't open file: \"%1\"", fileName));
 
 3696void ImagingPlanner::addCatalogImageInfo(
const CatalogImageInfo &info)
 
 3698    m_CatalogImageInfoMap[info.m_Name.toLower()] = info;
 
 3701bool ImagingPlanner::findCatalogImageInfo(
const QString &name, CatalogImageInfo * info)
 
 3704    if (
result == m_CatalogImageInfoMap.end())
 
 3706    if (
result->m_Filename.isEmpty())
 
 3712void ImagingPlanner::loadCatalogViaMenu()
 
 3714    QString startDir = Options::imagingPlannerCatalogPath();
 
 3716        startDir = defaultDirectory();
 
 3725void ImagingPlanner::loadCatalog(
const QString &path)
 
 3727    removeEventFilters();
 
 3734    m_loadingCatalog = 
true;
 
 3735    loadCatalogFromFile(path);
 
 3743    m_loadingCatalog = 
false;
 
 3744    installEventFilters();
 
 3747    if (m_CatalogSortModel->rowCount() > 0)
 
 3749        auto name = m_CatalogSortModel->index(0, 0).
data().toString();
 
 3751        QItemSelection selection, deselection;
 
 3752        selection.
select(m_CatalogSortModel->index(0, 0), m_CatalogSortModel->index(0, 0));
 
 3753        selectionChanged(selection, deselection);
 
 3757CatalogImageInfo::CatalogImageInfo(
const QString &csv)
 
 3762    QStringList columns = line.
split(
",");
 
 3763    if (columns.
size() < 1 || columns[0].isEmpty())
 
 3766    m_Name     = columns[column++];
 
 3767    if (columns.
size() <= column) 
return;
 
 3768    m_Filename = columns[column++];
 
 3769    if (columns.
size() <= column) 
return;
 
 3770    m_Author   = columns[column++];
 
 3771    if (columns.
size() <= column) 
return;
 
 3772    m_Link     = columns[column++];
 
 3773    if (columns.
size() <= column) 
return;
 
 3774    m_License  = columns[column++];
 
 3795void ImagingPlanner::loadCatalogFromFile(
QString path, 
bool reset)
 
 3797    QFile inputFile(path);
 
 3801        m_numMissingImage = 0;
 
 3803    int numMissingImage = 0, numWithImage = 0;
 
 3804    if (!inputFile.exists())
 
 3806        emit popupSorry(
i18n(
"Sorry, catalog file doesn't exist: \"%1\"", path));
 
 3809    QStringList objectNames;
 
 3812        const auto tz = QTimeZone(getGeo()->TZ() * 3600);
 
 3813        const KStarsDateTime midnight = KStarsDateTime(getDate().addDays(1), QTime(0, 1));
 
 3814        const KStarsDateTime ut  = getGeo()->LTtoUT(KStarsDateTime(midnight));
 
 3815        const KSAlmanac ksal(ut, getGeo());
 
 3819            Options::setImagingPlannerCatalogPath(path);
 
 3820            Options::self()->save();
 
 3821            if (m_CatalogModel->rowCount() > 0)
 
 3822                m_CatalogModel->removeRows(0, m_CatalogModel->rowCount());
 
 3825        QTextStream in(&inputFile);
 
 3828            CatalogImageInfo info(in.readLine().trimmed());
 
 3829            const QString 
name = info.m_Name;
 
 3837                const auto match = re.match(name);
 
 3838                if (
match.hasMatch())
 
 3840                    const QString catFilename = 
match.captured(1);
 
 3841                    if (catFilename.
isEmpty()) 
continue;
 
 3842                    const QFileInfo fInfo(catFilename);
 
 3844                    QString catFullPath = catFilename;
 
 3845                    if (!fInfo.isAbsolute())
 
 3847                        const QString catDir = QFileInfo(path).absolutePath();
 
 3848                        catFullPath = QString(
"%1%2%3").
arg(catDir)
 
 3851                    if (catFullPath != path)
 
 3852                        loadCatalogFromFile(catFullPath, 
false);
 
 3862                const auto match = re.match(name);
 
 3863                if (
match.hasMatch())
 
 3865                    const QString catFilename = 
match.captured(1);
 
 3866                    if (catFilename.
isEmpty()) 
continue;
 
 3867                    const QFileInfo fInfo(catFilename);
 
 3869                    QString catFullPath = catFilename;
 
 3870                    if (!fInfo.isAbsolute())
 
 3872                        const QString catDir = QFileInfo(path).absolutePath();
 
 3873                        catFullPath = QString(
"%1%2%3").
arg(catDir)
 
 3876                    std::pair<bool, QString> out = m_manager.import_catalog(catFullPath, 
false);
 
 3877                    DPRINTF(stderr, 
"Load of KStars catalog %s %s%s\n", catFullPath.
toLatin1().
data(),
 
 3878                            out.first ? 
"succeeded." : 
"failed: ", out.second.toLatin1().data());
 
 3887                const auto match = re.match(name);
 
 3888                if (
match.hasMatch())
 
 3890                    const QString catIDstr = 
match.captured(1);
 
 3891                    if (catIDstr.
isEmpty()) 
continue;
 
 3894                    const int catID = catIDstr.
toInt(&ok);
 
 3895                    if (ok && m_manager.catalog_exists(catID))
 
 3897                        const std::pair<bool, QString> out = m_manager.remove_catalog(catID);
 
 3898                        DPRINTF(stderr, 
"Removal of out-of-date catalog %d %s%s\n", catID,
 
 3899                                out.first ? 
"succeeded." : 
"failed: ", out.second.toLatin1().data());
 
 3904            objectNames.
append(name);
 
 3905            if (!info.m_Filename.isEmpty())
 
 3908                QFileInfo fInfo(info.m_Filename);
 
 3909                if (fInfo.isRelative())
 
 3910                    info.m_Filename = QString(
"%1%2%3").arg(QFileInfo(path).absolutePath())
 
 3912                addCatalogImageInfo(info);
 
 3923        int num = 0, numBad = 0, iteration = 0;
 
 3925        for (
const auto &name : objectNames)
 
 3927            setStatus(
i18n(
"%1/%2: Adding %3", ++iteration, objectNames.size(), name));
 
 3928            if (addCatalogItem(ksal, name, 0)) num++;
 
 3935        m_numWithImage += numWithImage;
 
 3936        m_numMissingImage += numMissingImage;
 
 3937        DPRINTF(stderr, 
"Catalog %s: %d of %d have catalog images\n",
 
 3942        emit popupSorry(
i18n(
"Sorry, couldn't open file: \"%1\"", path));
 
 3946void ImagingPlanner::sorry(
const QString &message)
 
 3948    KSNotification::sorry(message);
 
 3951void ImagingPlanner::captureRegion(
const QImage &screenshot)
 
 3953    if (m_PlateSolve.get()) 
disconnect(m_PlateSolve.get());
 
 3957    m_ScreenShotImage = screenshot;
 
 3960    QString tempQImage = QDir(temporaryPath).filePath(
"screenshot.png");
 
 3961    m_ScreenShotImage.
save(tempQImage);
 
 3962    FITSData::ImageToFITS(tempQImage, 
"png", m_ScreenShotFilename);
 
 3966    if (!m_PlateSolve.get())
 
 3967        m_PlateSolve.reset(
new PlateSolve(
this));
 
 3969    m_PlateSolve->setImageDisplay(m_ScreenShotImage);
 
 3970    if (currentCatalogObject())
 
 3972        m_PlateSolve->setPosition(*currentCatalogObject());
 
 3973        m_PlateSolve->setUsePosition(
true);
 
 3974        m_PlateSolve->setUseScale(
false);
 
 3975        m_PlateSolve->setLinear(
false);
 
 3976        reallyCenterOnSkymap();
 
 3979    m_PlateSolve->setWindowTitle(QString(
"Plate Solve for %1").arg(currentObjectName()));
 
 3980    m_PlateSolve->show();
 
 3981    if (Options::imagingPlannerStartSolvingImmediately())
 
 3985void ImagingPlanner::takeScreenshot()
 
 3987    if (!currentCatalogObject())
 
 3990    const QString messageID = 
"ImagingPlannerScreenShotInfo";
 
 3991    const QString screenshotInfo =
 
 3992        QString(
"<p><b>Taking a screenshot of %1 for the SkyMap</b></p>" 
 3993                "<p>This allows you to screenshot/copy a good example image of %1 from another application, " 
 3994                "such as a browser viewing %1 on Astrobin. It then plate-solves that screenshot and overlays " 
 3995                "it temporarily on the SkyMap.</p>" 
 3996                "<p>You can use this to help you frame your future %1 capture. " 
 3997                "The SkyMap overlay will only be visible in the current KStars session.</p>" 
 3998                "<p>In order to do this, you should make the image you wish to copy visible " 
 3999                "on your screen now, before clicking OK. After you click OK you will see the mouse pointer change " 
 4000                "to the screenshot pointer. You then drag your mouse over the part of the %1 image " 
 4001                "you wish to copy. If you check do-not-ask-again, then you must make sure that your desired image " 
 4002                "is already visible before you run this.</p>" 
 4003                "<p>After you take your screenshot, the system will bring up a menu to help plate-solve the image. " 
 4004                "Click SOLVE on that menu to start the process, unless it is automatically started. " 
 4005                "Once successfully plate-solved, your image will be overlayed onto the SkyMap.").arg(currentObjectName());
 
 4006#if KIO_VERSION >= QT_VERSION_CHECK(5, 100, 0) 
 4010                                        KGuiItem(
i18nc(
"@action:button", 
"OK")),
 
 4011                                        KGuiItem(
i18nc(
"@action:button", 
"Cancel")),
 
 4016    const int result = KMessageBox::questionYesNo(
this, screenshotInfo, 
"ScreenShot",
 
 4017                       KGuiItem(
"OK"), KGuiItem(
"Cancel"), messageID);
 
 4018    if (
result != KMessageBox::Yes)
 
 4024        m_CaptureWidget.reset();
 
 4030    if (m_CaptureWidget.get()) 
disconnect(m_CaptureWidget.get());
 
 4031    m_CaptureWidget.reset(
new ScreenCapture());
 
 4034    disconnect(m_CaptureWidget.get(), &ScreenCapture::aborted, 
nullptr, 
nullptr);
 
 4035    QObject::connect(m_CaptureWidget.get(), &ScreenCapture::aborted, 
this, [
this]()
 
 4037        disconnect(m_CaptureWidget.get());
 
 4038        m_CaptureWidget.reset();
 
 4040        this->activateWindow();
 
 4042    m_CaptureWidget->show();
 
 4045void ImagingPlanner::extractImage()
 
 4047    disconnect(m_PlateSolve.get(), &PlateSolve::solverFailed, 
nullptr, 
nullptr);
 
 4048    connect(m_PlateSolve.get(), &PlateSolve::solverFailed, 
this, [
this]()
 
 4050        disconnect(m_PlateSolve.get());
 
 4052    disconnect(m_PlateSolve.get(), &PlateSolve::solverSuccess, 
nullptr, 
nullptr);
 
 4053    connect(m_PlateSolve.get(), &PlateSolve::solverSuccess, 
this, [
this]()
 
 4055        disconnect(m_PlateSolve.get());
 
 4056        const FITSImage::Solution &solution = m_PlateSolve->solution();
 
 4057        ImageOverlay overlay;
 
 4058        overlay.m_Orientation = solution.orientation;
 
 4059        overlay.m_RA = solution.ra;
 
 4060        overlay.m_DEC = solution.dec;
 
 4061        overlay.m_ArcsecPerPixel = solution.pixscale;
 
 4062        overlay.m_EastToTheRight = solution.parity;
 
 4063        overlay.m_Status = ImageOverlay::AVAILABLE;
 
 4065        const bool mirror = !solution.parity;
 
 4066        const int scaleWidth = std::min(m_ScreenShotImage.width(), Options::imageOverlayMaxDimension());
 
 4067        QImage *processedImg = new QImage;
 
 4069            *processedImg = m_ScreenShotImage.mirrored(true, false).scaledToWidth(scaleWidth); 
 
 4071            *processedImg = m_ScreenShotImage.scaledToWidth(scaleWidth);
 
 4072        overlay.m_Img.reset(processedImg);
 
 4073        overlay.m_Width = processedImg->width();
 
 4074        overlay.m_Height = processedImg->height();
 
 4075        KStarsData::Instance()->skyComposite()->imageOverlay()->show();
 
 4076        KStarsData::Instance()->skyComposite()->imageOverlay()->addTemporaryImageOverlay(overlay);
 
 4078        KStars::Instance()->activateWindow();
 
 4079        KStars::Instance()->raise();
 
 4080        m_PlateSolve->close();
 
 4082    m_PlateSolve->solveImage(m_ScreenShotFilename);
 
a dms subclass that caches its sine and cosine values every time the angle is changed.
 
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
 
CatalogObject & insertStaticObject(const CatalogObject &obj)
Insert an object obj into m_static_objects and return a reference to the newly inserted object.
 
static QString processSearchText(QString searchText)
Do some post processing on the search text to interpret what the user meant This could include replac...
 
int size()
Return the numbers of flags.
 
void remove(int index)
Remove a flag.
 
void add(const SkyPoint &flagPoint, QString epoch, QString image, QString label, QColor labelColor)
Add a flag.
 
Contains all relevant information for specifying a location on Earth: City Name, State/Province name,...
 
A class that implements methods to find sun rise, sun set, twilight begin / end times,...
 
Provides necessary information about the Moon.
 
void findPhase(const KSSun *Sun=nullptr)
Determine the phase angle of the moon, and assign the appropriate moon image.
 
const QImage & image() const
 
void updateCoords(const KSNumbers *num, bool includePlanets=true, const CachingDms *lat=nullptr, const CachingDms *LST=nullptr, bool forceRecompute=false) override
Update position of the planet (reimplemented from SkyPoint)
 
bool AddImagingPlannerEntry(const ImagingPlannerDBEntry &entry)
Adds a new Imaging Planner row into the database.
 
bool GetAllImagingPlannerEntries(QList< ImagingPlannerDBEntry > *entryList)
Gets all the Imaging Planner rows from the database.
 
const KStarsDateTime & ut() const
 
Q_INVOKABLE SimClock * clock()
 
SkyMapComposite * skyComposite()
 
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
 
KStarsDateTime addSecs(double s) const
 
void setDate(const QDate &d)
Assign the Date according to a QDate object.
 
static KStars * Instance()
 
KStarsData * data() const
 
const KStarsDateTime & utc() const
 
SkyObject * findByName(const QString &name, bool exact=true) override
Search the children of this SkyMapComposite for a SkyObject whose name matches the argument.
 
void setClickedPoint(const SkyPoint *f)
Set the ClickedPoint to the skypoint given as an argument.
 
void setClickedObject(SkyObject *o)
Set the ClickedObject pointer to the argument.
 
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
 
void slotCenter()
Center the display at the point ClickedPoint.
 
Provides all necessary information about an object in the sky: its coordinates, name(s),...
 
virtual QString name(void) const
 
virtual QString longname(void) const
 
QString name2(void) const
 
TYPE
The type classification of the SkyObject.
 
The sky coordinates of a point in the sky.
 
const CachingDms & dec() const
 
const CachingDms & ra0() const
 
virtual void updateCoordsNow(const KSNumbers *num)
updateCoordsNow Shortcut for updateCoords( const KSNumbers *num, false, nullptr, nullptr,...
 
void setRA(dms &r)
Sets RA, the current Right Ascension.
 
const CachingDms & ra() const
 
dms angularDistanceTo(const SkyPoint *sp, double *const positionAngle=nullptr) const
Computes the angular distance between two SkyObjects.
 
void EquatorialToHorizontal(const CachingDms *LST, const CachingDms *lat)
Determine the (Altitude, Azimuth) coordinates of the SkyPoint from its (RA, Dec) coordinates,...
 
void setRA0(dms r)
Sets RA0, the catalog Right Ascension.
 
const CachingDms & dec0() const
 
void setDec0(dms d)
Sets Dec0, the catalog Declination.
 
An angle, stored as degrees, but expressible in many ways.
 
const double & Degrees() const
 
QString i18nc(const char *context, const char *text, const TYPE &arg...)
 
QString i18n(const char *text, const TYPE &arg...)
 
Type type(const QSqlDatabase &db)
 
StartupCondition
Conditions under which a SchedulerJob may start.
 
QMap< QString, uint16_t > CapturedFramesMap
mapping signature --> frames count
 
CompletionCondition
Conditions under which a SchedulerJob may complete.
 
KCRASH_EXPORT void setFlags(KCrash::CrashFlags flags)
 
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
 
KIOCORE_EXPORT CopyJob * move(const QList< QUrl > &src, const QUrl &dest, JobFlags flags=DefaultFlags)
 
KIOCORE_EXPORT QString number(KIO::filesize_t size)
 
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
 
GeoCoordinates geo(const QVariant &location)
 
QString path(const QString &relativePath)
 
ButtonCode questionTwoActions(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const QString &dontAskAgainName=QString(), Options options=Notify)
 
void enableMessage(const QString &dontShowAgainName)
 
KIOCORE_EXPORT QString dir(const QString &fileClass)
 
KIOCORE_EXPORT QStringList list(const QString &fileClass)
 
QString name(StandardAction id)
 
QString label(StandardShortcut id)
 
const QList< QKeySequence > & end()
 
void initialize(StandardShortcut id)
 
std::pair< bool, CatalogObject > resolveName(const QString &name)
Resolve the name of the given DSO and extract data from various sources.
 
virtual QVariant data(const QModelIndex &index, int role) const const=0
 
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const=0
 
virtual QModelIndex parent(const QModelIndex &index) const const=0
 
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
 
qsizetype length() const const
 
QByteArray & replace(QByteArrayView before, QByteArrayView after)
 
void resize(qsizetype newSize, char c)
 
qsizetype size() const const
 
QByteArray toBase64(Base64Options options) const const
 
std::string toStdString() const const
 
void processEvents(QEventLoop::ProcessEventsFlags flags)
 
QDate addDays(qint64 ndays) const const
 
QString toString(QStringView format, QCalendar cal) const const
 
QDateTime addSecs(qint64 s) const const
 
bool isValid() const const
 
qint64 secsTo(const QDateTime &other) const const
 
void setTimeZone(const QTimeZone &toZone)
 
void dateChanged(QDate date)
 
bool openUrl(const QUrl &url)
 
QString absolutePath() const const
 
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
 
bool exists() const const
 
bool mkpath(const QString &dirPath) const const
 
qint64 elapsed() const const
 
int exec(ProcessEventsFlags flags)
 
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
 
QDateTime birthTime() const const
 
iterator find(const Key &key)
 
QIcon fromTheme(const QString &name)
 
bool save(QIODevice *device, const char *format, int quality) const const
 
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
 
QImage scaledToHeight(int height, Qt::TransformationMode mode) const const
 
QModelIndexList indexes() const const
 
void select(const QModelIndex &topLeft, const QModelIndex &bottomRight)
 
void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
 
void append(QList< T > &&value)
 
qsizetype indexOf(const AT &value, qsizetype from) const const
 
void push_back(parameter_type value)
 
qsizetype size() const const
 
bool isValid() const const
 
const QAbstractItemModel * model() const const
 
QModelIndex siblingAtColumn(int column) const const
 
int globalX() const const
 
int globalY() const const
 
NetworkError error() const const
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
bool disconnect(const QMetaObject::Connection &connection)
 
QString tr(const char *sourceText, const char *disambiguation, int n)
 
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
 
QPixmap scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
 
qsizetype capturedStart(QStringView name) const const
 
bool hasMatch() const const
 
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const const override
 
virtual QVariant data(int role) const const
 
virtual void setData(const QVariant &value, int role)
 
void setTextAlignment(Qt::Alignment alignment)
 
QString & append(QChar ch)
 
QString arg(Args &&... args) const const
 
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
 
bool isEmpty() const const
 
QString mid(qsizetype position, qsizetype n) const const
 
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
 
qsizetype size() const const
 
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
 
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
 
int toInt(bool *ok, int base) const const
 
QByteArray toLatin1() const const
 
QString toLower() const const
 
QString toUpper() const const
 
QByteArray toUtf8() const const
 
QString trimmed() const const
 
QTextStream & dec(QTextStream &stream)
 
QTextStream & endl(QTextStream &stream)
 
QTextStream & fixed(QTextStream &stream)
 
QTextStream & left(QTextStream &stream)
 
QTextStream & right(QTextStream &stream)
 
void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier, int delay)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
 
bool isValid(int h, int m, int s, int ms)
 
QString toString(QStringView format) const const
 
void setInterval(int msec)
 
bool isActive() const const
 
bool isEmpty() const const
 
bool canConvert() const const
 
int toInt(bool *ok) const const
 
QString toString() const const