7#include "imageoverlaycomponent.h" 
   11#include "skypainter.h" 
   14#include "fitsviewer/fitsdata.h" 
   16#include "auxiliary/kspaths.h" 
   19#include <QTableWidget> 
   20#include <QImageReader> 
   23#include <QtConcurrent> 
   24#include <QRegularExpression> 
   26#include "ekos/auxiliary/solverutils.h" 
   27#include "ekos/auxiliary/stellarsolverprofile.h" 
   49constexpr int UNPROCESSED_INDEX = 0;
 
   50constexpr int OK_INDEX = 4;
 
   73void setupTableItem(
QTableWidget *table, 
int row, 
int column, 
const QString &text, 
bool editable = 
true)
 
   77    if (column >= NUM_COLUMNS)
 
   84    table->
setItem(row, column, item);
 
   88bool overlaySorter(
const ImageOverlay &o1, 
const ImageOverlay &o2)
 
  103    QRegularExpression re3(
"^(\\d+)\\s*h\\s(\\d+)\\s*[m\'\\s]\\s*(\\d+\\.*\\d*)\\s*([s\"]?)$");
 
  105    return re1.match(trimmedInput).hasMatch() ||
 
  106           re2.match(trimmedInput).hasMatch() ||
 
  107           re3.match(trimmedInput).hasMatch();
 
  114    if (!item) 
return false;
 
  127    return toDecString(
dms(dec));
 
  135    m_Directory = 
dir.absolutePath();
 
  146void ImageOverlayComponent::cellChanged(
int row, 
int col)
 
  148    if (!m_Initialized || col < 0 || col >= NUM_COLUMNS || row < 0 || row >= m_ImageOverlayTable->rowCount()) 
return;
 
  151    if (col == STATUS_COL || col == EAST_TO_RIGHT_COL) 
return;
 
  153    QTableWidgetItem *item = m_ImageOverlayTable->item(row, col);
 
  157    QString itemString = item->
text();
 
  158    auto overlay = m_Overlays[row];
 
  162        const bool useHMS = isHMS(itemString);
 
  166            item->
setText(dms(overlay.m_RA).toHMSString());
 
  167            QString msg = 
i18n(
"Bad RA string entered for %1. Reset to original value.", overlay.m_Filename);
 
  174    else if (col == DEC_COL)
 
  180            item->
setText(toDecString(overlay.m_DEC));
 
  181            QString msg = 
i18n(
"Bad DEC string entered for %1. Reset to original value.", overlay.m_Filename);
 
  185            item->
setText(toDecString(decDMS));
 
  187    else if (col == ORIENTATION_COL)
 
  189        bool angleOK = 
false;
 
  190        double angle = itemString.
toDouble(&angleOK);
 
  191        if (!angleOK || angle > 360 || angle < -360)
 
  193            item->
setText(QString(
"%1").arg(overlay.m_Orientation, 0, 
'f', 2));
 
  194            QString msg = 
i18n(
"Bad orientation angle string entered for %1. Reset to original value.", overlay.m_Filename);
 
  198    else if (col == ARCSEC_PER_PIXEL_COL)
 
  200        bool scaleOK = 
false;
 
  201        double scale = itemString.
toDouble(&scaleOK);
 
  202        if (!scaleOK || scale < 0 || scale > 1000)
 
  204            item->
setText(QString(
"%1").arg(overlay.m_ArcsecPerPixel, 0, 
'f', 2));
 
  205            QString msg = 
i18n(
"Bad scale angle string entered for %1. Reset to original value.", overlay.m_Filename);
 
  213void ImageOverlayComponent::statusCellChanged(
int row)
 
  215    if (row < 0 || row >= m_ImageOverlayTable->rowCount()) 
return;
 
  217    auto overlay = m_Overlays[row];
 
  224    QComboBox *statusItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(row, STATUS_COL));
 
  229        QTableWidgetItem *raItem = m_ImageOverlayTable->item(row, RA_COL);
 
  231        const bool useHMS = isHMS(raItem->
text());
 
  233        if (!raOK || raDMS.
Degrees() == 0)
 
  235            QString msg = 
i18n(
"Cannot set status to OK. Legal non-0 RA value required.");
 
  241        QTableWidgetItem *decItem = m_ImageOverlayTable->item(row, DEC_COL);
 
  242        if (!decItem) 
return;
 
  246            QString msg = 
i18n(
"Cannot set status to OK. Legal non-0 DEC value required.");
 
  251        bool angleOK = 
false;
 
  252        QTableWidgetItem *angleItem = m_ImageOverlayTable->item(row, ORIENTATION_COL);
 
  253        if (!angleItem) 
return;
 
  254        const double angle = angleItem->
text().
toDouble(&angleOK);
 
  255        if (!angleOK || angle > 360 || angle < -360)
 
  257            QString msg = 
i18n(
"Cannot set status to OK. Legal orientation value required.");
 
  262        bool scaleOK = 
false;
 
  263        QTableWidgetItem *scaleItem = m_ImageOverlayTable->item(row, ARCSEC_PER_PIXEL_COL);
 
  264        if (!scaleItem) 
return;
 
  265        const double scale = scaleItem->
text().
toDouble(&scaleOK);
 
  266        if (!scaleOK || scale < 0 || scale > 1000)
 
  268            QString msg = 
i18n(
"Cannot set status to OK. Legal non-0 a-s/px value required.");
 
  275            QComboBox *statusItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(row, STATUS_COL));
 
  280            m_Overlays[row].m_Status = ImageOverlay::AVAILABLE;
 
  281            m_Overlays[row].m_RA = raDMS.
Degrees();
 
  282            m_Overlays[row].m_DEC = decDMS.
Degrees();
 
  283            m_Overlays[row].m_ArcsecPerPixel = scale;
 
  284            m_Overlays[row].m_Orientation = angle;
 
  285            const QComboBox *ewItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(row, EAST_TO_RIGHT_COL));
 
  286            m_Overlays[row].m_EastToTheRight = ewItem->
currentIndex();
 
  288            if (m_Overlays[row].m_Img.get() == 
nullptr)
 
  291                const QString fullFilename = QString(
"%1/%2").arg(m_Directory).arg(m_Overlays[row].m_Filename);
 
  292                QImage *img = loadImageFile(fullFilename, !m_Overlays[row].m_EastToTheRight);
 
  293                m_Overlays[row].m_Width = img->
width();
 
  294                m_Overlays[row].m_Height = img->
height();
 
  295                m_Overlays[row].m_Img.reset(img);
 
  298            QString msg = 
i18n(
"Stored OK status for %1.", m_Overlays[row].m_Filename);
 
  305ImageOverlayComponent::~ImageOverlayComponent()
 
  307    if (m_LoadImagesFuture.isRunning())
 
  309        m_LoadImagesFuture.cancel();
 
  310        m_LoadImagesFuture.waitForFinished();
 
  314void ImageOverlayComponent::selectionChanged()
 
  316    if (m_Initialized && Options::showSelectedImageOverlay())
 
  322    return Options::showImageOverlays();
 
 
  327#if !defined(KSTARS_LITE) 
 
  342    m_ImageOverlayTable = table;
 
  347    m_SolveButton = solveButton;
 
  348    m_TableGroupBox = tableGroupBox;
 
  349    m_SolverProfile = solverProfile;
 
  352    m_StatusDisplay = statusDisplay;
 
  359    initSolverProfiles();
 
  363void ImageOverlayComponent::initSolverProfiles()
 
  365    QString savedOptionsProfiles = QDir(KSPaths::writableLocation(
 
  368    QList<SSolver::Parameters> optionsList;
 
  369    if(QFile(savedOptionsProfiles).exists())
 
  370        optionsList = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles);
 
  372        optionsList = Ekos::getDefaultAlignOptionsProfiles();
 
  374    m_SolverProfile->clear();
 
  375    for(
auto ¶m : optionsList)
 
  376        m_SolverProfile->addItem(param.listName);
 
  377    m_SolverProfile->setCurrentIndex(Options::solveOptionsProfile());
 
  380void ImageOverlayComponent::updateStatusDisplay(
const QString &message)
 
  382    if (!m_StatusDisplay)
 
  384    m_LogText.insert(0, message);
 
  385    m_StatusDisplay->setPlainText(m_LogText.join(
"\n"));
 
  390void ImageOverlayComponent::updateTable()
 
  394    QDir directory(m_Directory);
 
  395    emit updateLog(
i18n(
"Updating from directory: %1", m_Directory));
 
  396    QStringList images = directory.entryList(QStringList() << 
"*", 
QDir::Files);
 
  397    QSet<QString> imageFiles;
 
  398    foreach(QString filename, images)
 
  400        if (!FITSData::readableFilename(filename))
 
  402        imageFiles.
insert(filename);
 
  406    QList<QString> sortedImageFiles;
 
  407    for (
const auto &fn : imageFiles)
 
  409    std::sort(sortedImageFiles.
begin(), sortedImageFiles.
end(), overlaySorter);
 
  412    QList<ImageOverlay> tempOverlays;
 
  413    QMap<QString, int> tempMap;
 
  415    for (
int i = 0; i < m_Overlays.size(); ++i)
 
  417        auto &fname = m_Overlays[i].m_Filename;
 
  418        if (sortedImageFiles.
indexOf(fname) >= 0)
 
  420            tempOverlays.
append(m_Overlays[i]);
 
  421            tempMap[fname] = tempOverlays.
size() - 1;
 
  426    m_Overlays = tempOverlays;
 
  427    m_Filenames = tempMap;
 
  431    for (
const auto &filename : sortedImageFiles)
 
  433        auto item = m_Filenames.find(filename);
 
  434        if (item == m_Filenames.end())
 
  437            ImageOverlay overlay(filename);
 
  438            const int size = m_Filenames.size();  
 
  439            m_Overlays.push_back(overlay);
 
  440            m_Filenames[filename] = size;
 
  444    emit updateLog(
i18n(
"%1 overlays (%2 new, %3 deleted) %4 solved", m_Overlays.size(), numNew, numDeleted,
 
  446    m_TableGroupBox->setTitle(
i18n(
"Image Overlays.  %1 images, %2 available.", m_Overlays.size(), numAvailable()));
 
  453void ImageOverlayComponent::loadAllImageFiles()
 
  455#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) 
  456    m_LoadImagesFuture = 
QtConcurrent::run(&ImageOverlayComponent::loadImageFileLoop, 
this);
 
  458    m_LoadImagesFuture = 
QtConcurrent::run(
this, &ImageOverlayComponent::loadImageFileLoop);
 
  462void ImageOverlayComponent::loadImageFileLoop()
 
  464    emit updateLog(
i18n(
"Loading image files..."));
 
  465    while (loadImageFile());
 
  467    for (
const auto &o : m_Overlays)
 
  468        if (o.m_Img.get() != 
nullptr)
 
  470    emit updateLog(
i18n(
"%1 image files loaded.", num));
 
  472    m_ImageOverlayTable->setEditTriggers(m_EditTriggers);
 
  473    m_Initialized = 
true;
 
  476void ImageOverlayComponent::addTemporaryImageOverlay(
const ImageOverlay &overlay)
 
  478    m_TemporaryOverlays.push_back(overlay);
 
  481QImage *ImageOverlayComponent::loadImageFile (
const QString &fullFilename, 
bool mirror)
 
  483    QSharedPointer<QImage> tempImage(
new QImage(fullFilename));
 
  484    if (tempImage.get() == 
nullptr) 
return nullptr;
 
  485    int scaleWidth = std::min(tempImage->width(), Options::imageOverlayMaxDimension());
 
  486    QImage *processedImg = 
new QImage;
 
  495bool ImageOverlayComponent::loadImageFile()
 
  497    bool updatedSomething = 
false;
 
  499    for (
auto &o : m_Overlays)
 
  501        if (o.m_Status == o.ImageOverlay::AVAILABLE && o.m_Img.get() == 
nullptr)
 
  504            QImage *img = loadImageFile(fullFilename, !o.m_EastToTheRight);
 
  506            updatedSomething = 
true;
 
  513    return updatedSomething;
 
  518void ImageOverlayComponent::initializeGui()
 
  520    if (!m_ImageOverlayTable) 
return;
 
  526    setupTable(m_ImageOverlayTable);
 
  529    for (
int i = 0; i < m_Overlays.size(); ++i)
 
  531        const ImageOverlay &overlay = m_Overlays[row];
 
  533        setupTableItem(m_ImageOverlayTable, row, FILENAME_COL, overlay.m_Filename, 
false);
 
  535        QStringList StatusNames =
 
  539        QComboBox *statusBox = 
new QComboBox();
 
  540        for (
int i = 0; i < ImageOverlay::NUM_STATUS; ++i)
 
  541            statusBox->
addItem(StatusNames[i]);
 
  545            statusCellChanged(row);
 
  548        m_ImageOverlayTable->setCellWidget(row, STATUS_COL, statusBox);
 
  550        setupTableItem(m_ImageOverlayTable, row, ORIENTATION_COL, QString(
"%1").arg(overlay.m_Orientation, 0, 
'f', 2));
 
  551        setupTableItem(m_ImageOverlayTable, row, RA_COL, dms(overlay.m_RA).toHMSString());
 
  552        setupTableItem(m_ImageOverlayTable, row, DEC_COL, toDecString(overlay.m_DEC));
 
  553        setupTableItem(m_ImageOverlayTable, row, ARCSEC_PER_PIXEL_COL, QString(
"%1").arg(overlay.m_ArcsecPerPixel, 0, 
'f', 2));
 
  556        setupTableItem(m_ImageOverlayTable, row, WIDTH_COL, QString(
"%1").arg(overlay.m_Width), 
false);
 
  557        setupTableItem(m_ImageOverlayTable, row, HEIGHT_COL, QString(
"%1").arg(overlay.m_Height), 
false);
 
  559        QComboBox *mirroredBox = 
new QComboBox();
 
  569        m_ImageOverlayTable->setCellWidget(row, EAST_TO_RIGHT_COL, mirroredBox);
 
  573    m_ImageOverlayTable->resizeColumnsToContents();
 
  574    m_TableGroupBox->setTitle(
i18n(
"Image Overlays.  %1 images, %2 available.", m_Overlays.size(), numAvailable()));
 
  579void ImageOverlayComponent::loadFromUserDB()
 
  581    QList<ImageOverlay *> 
list;
 
  584    std::sort(m_Overlays.begin(), m_Overlays.end(), overlaySorter);
 
  587    for (
const auto &o : m_Overlays)
 
  589        m_Filenames[o.m_Filename] = index;
 
  594void ImageOverlayComponent::saveToUserDB()
 
  597    for (
const ImageOverlay &metadata : m_Overlays)
 
  601void ImageOverlayComponent::solveImage(
const QString &filename)
 
  603    if (!m_Initialized) 
return;
 
  604    m_SolveButton->setText(
i18n(
"Abort"));
 
  605    const int solverTimeout = Options::imageOverlayTimeout();
 
  607    QString savedOptionsProfiles = QDir(KSPaths::writableLocation(
 
  609    auto profiles = (QFile(savedOptionsProfiles).exists()) ?
 
  610                    StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles) :
 
  611                    Ekos::getDefaultAlignOptionsProfiles();
 
  613    const int index = m_SolverProfile->currentIndex();
 
  614    auto parameters = index < profiles.size() ? profiles.at(index) : profiles.at(0);
 
  616    parameters.search_radius = parameters.search_radius * 2;
 
  621    if (m_RowsToSolve.size() > 1)
 
  622        emit updateLog(
i18n(
"Solving: %1. %2 in queue.", filename, m_RowsToSolve.size()));
 
  624        emit updateLog(
i18n(
"Solving: %1.", filename));
 
  628    int row = m_RowsToSolve[0];
 
  629    QString raString = m_ImageOverlayTable->item(row, RA_COL)->text().toLatin1().data();
 
  630    QString decString = m_ImageOverlayTable->item(row, DEC_COL)->text().toLatin1().data();
 
  631    QString scaleString = m_ImageOverlayTable->item(row, ARCSEC_PER_PIXEL_COL)->text().toLatin1().data();
 
  634    const bool useHMS = isHMS(raString);
 
  637    bool scaleOK = 
false;
 
  638    double scale = scaleString.
toDouble(&scaleOK);
 
  639    scaleOK = scaleOK && scale != 0.00;
 
  642    if (!scaleOK && Options::imageOverlayDefaultScale() > 0.0001)
 
  644        scale = Options::imageOverlayDefaultScale();
 
  650        auto lowScale = scale * 0.75;
 
  651        auto highScale = scale * 1.25;
 
  652        m_Solver->useScale(
true, lowScale, highScale);
 
  657    m_Solver->runSolver(filename);
 
  660void ImageOverlayComponent::tryAgain()
 
  662    m_TryAgainTimer.stop();
 
  663    if (!m_Initialized) 
return;
 
  664    if (m_RowsToSolve.size() > 0)
 
  668int ImageOverlayComponent::numAvailable()
 
  671    for (
const auto &o : m_Overlays)
 
  672        if (o.m_Status == ImageOverlay::AVAILABLE)
 
  677void ImageOverlayComponent::show()
 
  679    if (!m_Initialized || !m_ImageOverlayTable) 
return;
 
  680    auto selections = m_ImageOverlayTable->selectionModel();
 
  681    if (selections->hasSelection())
 
  683        auto selectedIndexes = selections->selectedIndexes();
 
  684        const int row = selectedIndexes.at(0).row();
 
  685        if (m_Overlays.size() > row && row >= 0)
 
  687            if (m_Overlays[row].m_Status != ImageOverlay::AVAILABLE)
 
  689                emit updateLog(
i18n(
"Can't show %1. Not plate solved.", m_Overlays[row].m_Filename));
 
  692            if (m_Overlays[row].m_Img.get() == 
nullptr)
 
  694                emit updateLog(
i18n(
"Can't show %1. Image not loaded.", m_Overlays[row].m_Filename));
 
  697            const double ra = m_Overlays[row].m_RA;
 
  698            const double dec = m_Overlays[row].m_DEC;
 
  701            auto localTime = KStarsData::Instance()->
geo()->UTtoLT(KStarsData::Instance()->clock()->utc());
 
  702            const dms raDms(ra), decDms(dec);
 
  703            SkyPoint coord(raDms, decDms);
 
  704            coord.apparentCoord(
static_cast<long double>(J2000), 
KStars::Instance()->data()->ut().djd());
 
  707            Options::setIsTracking(
false);
 
  710            SkyMap::Instance()->
setFocus(dms(coord.ra()), dms(coord.dec()));
 
  713            double zoomFactor = (400 * 60.0 *  10800.0) / (m_Overlays[row].m_Width * m_Overlays[row].m_ArcsecPerPixel * 
dms::PI);
 
  721void ImageOverlayComponent::abortSolving()
 
  723    if (!m_Initialized) 
return;
 
  724    m_RowsToSolve.clear();
 
  727    emit updateLog(
i18n(
"Solving aborted."));
 
  728    m_SolveButton->setText(
i18n(
"Solve"));
 
  731void ImageOverlayComponent::startSolving()
 
  733    if (!m_Initialized) 
return;
 
  734    if (m_SolveButton->text() == 
i18n(
"Abort"))
 
  739    if (m_Solver && m_Solver->isRunning())
 
  742        if (m_RowsToSolve.size() > 0)
 
  743            m_TryAgainTimer.start(2000);
 
  747    if (m_RowsToSolve.size() == 0)
 
  749        QSet<int> selectedRows;
 
  750        auto selections = m_ImageOverlayTable->selectionModel();
 
  751        if (selections->hasSelection())
 
  754            auto selectedIndexes = selections->selectedIndexes();
 
  755            for (
int i = 0; i < selectedIndexes.count(); ++i)
 
  758                const int row = selectedIndexes.at(i).row();
 
  759                if ((m_Overlays[row].m_Status == ImageOverlay::AVAILABLE) &&
 
  760                        !shouldSolveAnyway(m_ImageOverlayTable, row))
 
  762                    emit updateLog(
i18n(
"Skipping already solved: %1.", m_Overlays[row].m_Filename));
 
  768        m_RowsToSolve.clear();
 
  769        for (
int row : selectedRows)
 
  770            m_RowsToSolve.push_back(row);
 
  773    if (m_RowsToSolve.size() > 0)
 
  775        const int row = m_RowsToSolve[0];
 
  776        const QString filename =
 
  777            QString(
"%1/%2").
arg(m_Directory).
arg(m_Overlays[row].m_Filename);
 
  778        if ((m_Overlays[row].m_Status == ImageOverlay::AVAILABLE) &&
 
  779                !shouldSolveAnyway(m_ImageOverlayTable, row))
 
  781            emit updateLog(
i18n(
"%1 already solved. Skipping.", filename));
 
  782            m_RowsToSolve.removeFirst();
 
  783            if (m_RowsToSolve.size() > 0)
 
  788        auto img = 
new QImage(filename);
 
  789        m_Overlays[row].m_Width = img->width();
 
  790        m_Overlays[row].m_Height = img->height();
 
  791        solveImage(filename);
 
  795void ImageOverlayComponent::reload()
 
  797    if (!m_Initialized) 
return;
 
  798    m_Initialized = 
false;
 
  799    emit updateLog(
i18n(
"Reloading. Image overlays temporarily disabled."));
 
  804void ImageOverlayComponent::solverDone(
bool timedOut, 
bool success, 
const FITSImage::Solution &solution,
 
  805                                       double elapsedSeconds)
 
  807    disconnect(m_Solver.get(), &SolverUtils::done, 
this, &ImageOverlayComponent::solverDone);
 
  808    m_SolveButton->setText(
i18n(
"Solve"));
 
  809    if (m_RowsToSolve.size() == 0)
 
  812    const int solverRow = m_RowsToSolve[0];
 
  813    m_RowsToSolve.removeFirst();
 
  815    QComboBox *statusItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(solverRow, STATUS_COL));
 
  819        m_Overlays[solverRow].m_Status = ImageOverlay::PLATE_SOLVE_FAILURE;
 
  820        statusItem->
setCurrentIndex(
static_cast<int>(m_Overlays[solverRow].m_Status));
 
  825        m_Overlays[solverRow].m_Status = ImageOverlay::PLATE_SOLVE_FAILURE;
 
  826        statusItem->
setCurrentIndex(
static_cast<int>(m_Overlays[solverRow].m_Status));
 
  830        m_Overlays[solverRow].m_Orientation = solution.orientation;
 
  831        m_Overlays[solverRow].m_RA = solution.ra;
 
  832        m_Overlays[solverRow].m_DEC = solution.dec;
 
  833        m_Overlays[solverRow].m_ArcsecPerPixel = solution.pixscale;
 
  834        m_Overlays[solverRow].m_EastToTheRight = solution.parity;
 
  835        m_Overlays[solverRow].m_Status = ImageOverlay::AVAILABLE;
 
  837        QString msg = 
i18n(
"Solver success in %1s: RA %2 DEC %3 Scale %4 Angle %5",
 
  846        auto overlay = m_Overlays[solverRow];
 
  847        m_ImageOverlayTable->item(solverRow, RA_COL)->setText(dms(overlay.m_RA).toHMSString());
 
  848        m_ImageOverlayTable->item(solverRow, DEC_COL)->setText(toDecString(overlay.m_DEC));
 
  849        m_ImageOverlayTable->item(solverRow, ARCSEC_PER_PIXEL_COL)->setText(
 
  850            QString(
"%1").arg(overlay.m_ArcsecPerPixel, 0, 
'f', 2));
 
  851        m_ImageOverlayTable->item(solverRow, ORIENTATION_COL)->setText(QString(
"%1").arg(overlay.m_Orientation, 0, 
'f', 2));
 
  852        QComboBox *ewItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(solverRow, EAST_TO_RIGHT_COL));
 
  855        QComboBox *statusItem = 
dynamic_cast<QComboBox*
>(m_ImageOverlayTable->cellWidget(solverRow, STATUS_COL));
 
  859        QString fullFilename = QString(
"%1/%2").
arg(m_Directory).
arg(m_Overlays[solverRow].m_Filename);
 
  860        QImage *img = loadImageFile(fullFilename, !m_Overlays[solverRow].m_EastToTheRight);
 
  861        m_Overlays[solverRow].m_Img.reset(img);
 
  865    if (m_RowsToSolve.size() > 0)
 
  869        emit updateLog(
i18n(
"Done solving. %1 available.", numAvailable()));
 
  870        m_TableGroupBox->setTitle(
i18n(
"Image Overlays.  %1 images, %2 available.", m_Overlays.size(), numAvailable()));
 
void draw(SkyPainter *skyp) override
Draw the object on the SkyMap skyp a pointer to the SkyPainter to use.
 
bool GetAllImageOverlays(QList< ImageOverlay > *imageOverlayList)
Gets all the image overlay rows from the database.
 
bool AddImageOverlay(const ImageOverlay &overlay)
Adds a new image overlay row into the database.
 
bool DeleteAllImageOverlays()
Deletes all image overlay rows from the database.
 
static KStars * Instance()
 
SkyComponent represents an object on the sky map.
 
SkyComposite is a kind of container class for SkyComponent objects.
 
void setZoomFactor(double factor)
@ Set zoom factor.
 
void forceUpdate(bool now=false)
Recalculates the positions of objects in the sky, and then repaints the sky map.
 
void setFocus(SkyPoint *f)
sets the central focus point of the sky map.
 
void setFocusObject(SkyObject *o)
Set the FocusObject pointer to the argument.
 
void setFocusPoint(SkyPoint *f)
set the FocusPoint; the position that is to be the next Destination.
 
Draws things on the sky, without regard to backend.
 
virtual bool drawImageOverlay(const QList< ImageOverlay > *imageOverlays, bool useCache=false)=0
drawImageOverlay Draws a user-supplied image onto the skymap
 
An angle, stored as degrees, but expressible in many ways.
 
virtual bool setFromString(const QString &s, bool isDeg=true)
Attempt to parse the string argument as a dms value, and set the dms object accordingly.
 
static constexpr double PI
PI is a const static member; it's public so that it can be used anywhere, as long as dms....
 
const QString toHMSString(const bool machineReadable=false, const bool highPrecision=false) const
 
const double & Degrees() const
 
QString i18n(const char *text, const TYPE &arg...)
 
KIOCORE_EXPORT QString dir(const QString &fileClass)
 
KIOCORE_EXPORT QStringList list(const QString &fileClass)
 
void setText(const QString &text)
 
void activated(int index)
 
void addItem(const QIcon &icon, const QString &text, const QVariant &userData)
 
QImage mirrored(bool horizontal, bool vertical) &&
 
QImage scaledToWidth(int width, Qt::TransformationMode mode) const const
 
void append(QList< T > &&value)
 
qsizetype indexOf(const AT &value, qsizetype from) const const
 
void push_back(parameter_type value)
 
qsizetype size() const const
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
bool disconnect(const QMetaObject::Connection &connection)
 
iterator insert(const T &value)
 
QString arg(Args &&... args) const const
 
QString number(double n, char format, int precision)
 
double toDouble(bool *ok) const const
 
QString toLower() const const
 
QString trimmed() const const
 
QTextStream & dec(QTextStream &stream)
 
void setShowGrid(bool show)
 
void setWordWrap(bool on)
 
void setText(const QString &text)
 
void setTextAlignment(Qt::Alignment alignment)
 
QString text() const const
 
QFuture< T > run(Function function,...)
 
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)