diff --git a/kstars/ekos/align/align.cpp b/kstars/ekos/align/align.cpp --- a/kstars/ekos/align/align.cpp +++ b/kstars/ekos/align/align.cpp @@ -3642,8 +3642,10 @@ if (pahStage == PAH_FIRST_ROTATE) { // only wait for telescope to slew to new position if manual slewing is switched off - if(!PAHManual->isChecked()){ + if(!PAHManual->isChecked()) + { double deltaAngle = fabs(telescopeCoord.ra().deltaAngle(targetPAH.ra()).Degrees()); + qCDebug(KSTARS_EKOS_ALIGN) << "First mount rotation remainging degrees:" << deltaAngle; if (deltaAngle <= PAH_ROTATION_THRESHOLD) { currentTelescope->StopWE(); @@ -3672,8 +3674,10 @@ else if (pahStage == PAH_SECOND_ROTATE) { // only wait for telescope to slew to new position if manual slewing is switched off - if(!PAHManual->isChecked()){ + if(!PAHManual->isChecked()) + { double deltaAngle = fabs(telescopeCoord.ra().deltaAngle(targetPAH.ra()).Degrees()); + qCDebug(KSTARS_EKOS_ALIGN) << "Second mount rotation remainging degrees:" << deltaAngle; if (deltaAngle <= PAH_ROTATION_THRESHOLD) { currentTelescope->StopWE(); diff --git a/kstars/ekos/capture/capture.h b/kstars/ekos/capture/capture.h --- a/kstars/ekos/capture/capture.h +++ b/kstars/ekos/capture/capture.h @@ -596,6 +596,7 @@ // Jobs void resetJobs(); + void selectJob(QModelIndex i); void editJob(QModelIndex i); void resetJobEdit(); void executeJob(); @@ -710,6 +711,9 @@ // If exposure timed out, let's handle it. void processCaptureTimeout(); + // selection of a job + void selectedJobChanged(QModelIndex current, QModelIndex previous); + /* Capture */ /** diff --git a/kstars/ekos/capture/capture.cpp b/kstars/ekos/capture/capture.cpp --- a/kstars/ekos/capture/capture.cpp +++ b/kstars/ekos/capture/capture.cpp @@ -144,6 +144,7 @@ connect(queueSaveAsB, &QPushButton::clicked, this, &Ekos::Capture::saveSequenceQueueAs); connect(queueLoadB, &QPushButton::clicked, this, static_cast(&Ekos::Capture::loadSequenceQueue)); connect(resetB, &QPushButton::clicked, this, &Ekos::Capture::resetJobs); + connect(queueTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Ekos::Capture::selectedJobChanged); connect(queueTable, &QAbstractItemView::doubleClicked, this, &Ekos::Capture::editJob); connect(queueTable, &QTableWidget::itemSelectionChanged, this, &Ekos::Capture::resetJobEdit); connect(setTemperatureB, &QPushButton::clicked, [&]() @@ -2403,6 +2404,15 @@ currentRow = queueTable->rowCount() - 1; removeJob(currentRow); + + // update selection + if (queueTable->rowCount() == 0) + return; + + if (currentRow > queueTable->rowCount()) + queueTable->selectRow(queueTable->rowCount()-1); + else + queueTable->selectRow(currentRow); } void Capture::removeJob(int index) @@ -2541,14 +2551,20 @@ foreach (QAbstractButton * button, queueEditButtonGroup->buttons()) button->setEnabled(!enable); + + queueTable->setEnabled(!enable); } void Capture::prepareJob(SequenceJob * job) { activeJob = job; qCDebug(KSTARS_EKOS_CAPTURE) << "Preparing capture job" << job->getSignature() << "for execution."; + int index = jobs.indexOf(job); + if (index >= 0) + queueTable->selectRow(index); + if (activeJob->getActiveCCD() != currentCCD) { setCamera(activeJob->getActiveCCD()->getDeviceName()); @@ -3996,15 +4012,34 @@ emit settingsUpdated(settings); } -void Capture::editJob(QModelIndex i) +void Capture::selectedJobChanged(QModelIndex current, QModelIndex previous) +{ + Q_UNUSED(previous); + selectJob(current); +} + +void Capture::selectJob(QModelIndex i) { + if (i.row() < 0 || (i.row()+1) > jobs.size()) + return; + SequenceJob * job = jobs.at(i.row()); if (job == nullptr) return; syncGUIToJob(job); + if (isBusy || jobs.size() < 2) + return; + + queueUpB->setEnabled(i.row() > 0); + queueDownB->setEnabled(i.row()+1 < jobs.size()); +} + +void Capture::editJob(QModelIndex i) +{ + selectJob(i); appendLogText(i18n("Editing job #%1...", i.row() + 1)); addToQueueB->setIcon(QIcon::fromTheme("dialog-ok-apply")); @@ -4217,10 +4252,10 @@ activeJob = nullptr; //m_TargetName.clear(); //stop(); - qDeleteAll(jobs); - jobs.clear(); while (queueTable->rowCount() > 0) queueTable->removeRow(0); + qDeleteAll(jobs); + jobs.clear(); } QString Capture::getSequenceQueueStatus() diff --git a/kstars/ekos/ekos.h b/kstars/ekos/ekos.h --- a/kstars/ekos/ekos.h +++ b/kstars/ekos/ekos.h @@ -158,7 +158,7 @@ typedef enum { SCHEDULER_IDLE, /*< Scheduler is stopped. */ SCHEDULER_STARTUP, /*< Scheduler is starting the observatory up. */ - SCHEDULER_RUNNIG, /*< Scheduler is running. */ + SCHEDULER_RUNNING, /*< Scheduler is running. */ SCHEDULER_PAUSED, /*< Scheduler is paused by the end-user. */ SCHEDULER_SHUTDOWN, /*< Scheduler is shutting the observatory down. */ SCHEDULER_ABORTED, /*< Scheduler is stopped in error. */ diff --git a/kstars/ekos/guide/internalguide/internalguider.h b/kstars/ekos/guide/internalguide/internalguider.h --- a/kstars/ekos/guide/internalguide/internalguider.h +++ b/kstars/ekos/guide/internalguide/internalguider.h @@ -169,6 +169,7 @@ int ra_total_pulse { 0 }; int de_total_pulse { 0 }; double phi { 0 }; + uint8_t backlash { 0 }; } m_CalibrationParams; struct diff --git a/kstars/ekos/guide/internalguide/internalguider.cpp b/kstars/ekos/guide/internalguide/internalguider.cpp --- a/kstars/ekos/guide/internalguide/internalguider.cpp +++ b/kstars/ekos/guide/internalguide/internalguider.cpp @@ -531,6 +531,7 @@ ROT_Z = RotateZ(-M_PI * m_CalibrationParams.phi / 180.0); // derotates... m_CalibrationCoords.ra_distance = 0; + m_CalibrationParams.backlash = 0; emit newPulse(RA_DEC_DIR, m_CalibrationParams.last_pulse); m_CalibrationParams.ra_iterations++; @@ -604,13 +605,19 @@ // Also increase pulse width if we are going FARTHER and not back to our original position else if ( (fabs(cur_x-m_CalibrationCoords.last_x) < 0.5 && fabs(cur_y-m_CalibrationCoords.last_y) < 0.5) || star_pos.x > m_CalibrationCoords.ra_distance) { - // Increase pulse by 200% - m_CalibrationParams.last_pulse = Options::calibrationPulseDuration()*2; + m_CalibrationParams.backlash++; + + // Increase pulse to 200% after we tried to fight against backlash 2 times at least + if (m_CalibrationParams.backlash > 2) + m_CalibrationParams.last_pulse = Options::calibrationPulseDuration()*2; + else + m_CalibrationParams.last_pulse = Options::calibrationPulseDuration(); } else { m_CalibrationParams.ra_total_pulse += m_CalibrationParams.last_pulse; m_CalibrationParams.last_pulse = Options::calibrationPulseDuration(); + m_CalibrationParams.backlash = 0; } m_CalibrationCoords.last_x = cur_x; m_CalibrationCoords.last_y = cur_y; diff --git a/kstars/ekos/scheduler/scheduler.h b/kstars/ekos/scheduler/scheduler.h --- a/kstars/ekos/scheduler/scheduler.h +++ b/kstars/ekos/scheduler/scheduler.h @@ -324,11 +324,23 @@ void setJobManipulation(bool can_reorder, bool can_delete); /** + * @brief set all GUI fields to the values of the given scheduler job + */ + void syncGUIToJob(SchedulerJob *job); + + /** * @brief jobSelectionChanged Update UI state when the job list is clicked once. */ void clickQueueTable(QModelIndex index); /** + * @brief Update scheduler parameters to the currently selected scheduler job + * @param current table position + * @param previous table position + */ + void queueTableSelectionChanged(QModelIndex current, QModelIndex previous); + + /** * @brief reorderJobs Change the order of jobs in the UI based on a subset of its jobs. */ bool reorderJobs(QList reordered_sublist); @@ -783,6 +795,5 @@ static const uint32_t FOCUS_INACTIVITY_TIMEOUT = 120000; static const uint32_t CAPTURE_INACTIVITY_TIMEOUT = 120000; static const uint16_t GUIDE_INACTIVITY_TIMEOUT = 60000; - }; } diff --git a/kstars/ekos/scheduler/scheduler.cpp b/kstars/ekos/scheduler/scheduler.cpp --- a/kstars/ekos/scheduler/scheduler.cpp +++ b/kstars/ekos/scheduler/scheduler.cpp @@ -171,6 +171,7 @@ connect(queueDownB, &QPushButton::clicked, this, &Scheduler::moveJobDown); connect(evaluateOnlyB, &QPushButton::clicked, this, &Scheduler::startJobEvaluation); connect(sortJobsB, &QPushButton::clicked, this, &Scheduler::sortJobsPerAltitude); + connect(queueTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Scheduler::queueTableSelectionChanged); connect(queueTable, &QAbstractItemView::clicked, this, &Scheduler::clickQueueTable); connect(queueTable, &QAbstractItemView::doubleClicked, this, &Scheduler::loadJob); @@ -456,7 +457,7 @@ void Scheduler::saveJob() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) { appendLogText(i18n("Warning: You cannot add or modify a job while the scheduler is running.")); return; @@ -728,47 +729,21 @@ } } -void Scheduler::loadJob(QModelIndex i) +void Scheduler::syncGUIToJob(SchedulerJob *job) { - if (jobUnderEdit == i.row()) - return; - - if (state == SCHEDULER_RUNNIG) - { - appendLogText(i18n("Warning: you cannot add or modify a job while the scheduler is running.")); - return; - } - - SchedulerJob * const job = jobs.at(i.row()); - - if (job == nullptr) - return; - - watchJobChanges(false); - - //job->setState(SchedulerJob::JOB_IDLE); - //job->setStage(SchedulerJob::STAGE_IDLE); - nameEdit->setText(job->getName()); prioritySpin->setValue(job->getPriority()); raBox->showInHours(job->getTargetCoords().ra0()); decBox->showInDegrees(job->getTargetCoords().dec0()); if (job->getFITSFile().isEmpty() == false) - { fitsEdit->setText(job->getFITSFile().toLocalFile()); - fitsURL = job->getFITSFile(); - } else - { fitsEdit->clear(); - fitsURL = QUrl(); - } sequenceEdit->setText(job->getSequenceFile().toLocalFile()); - sequenceURL = job->getSequenceFile(); trackStepCheck->setChecked(job->getStepPipeline() & SchedulerJob::USE_TRACK); focusStepCheck->setChecked(job->getStepPipeline() & SchedulerJob::USE_FOCUS); @@ -843,6 +818,38 @@ break; } + setJobManipulation(!Options::sortSchedulerJobs(), true); +} + +void Scheduler::loadJob(QModelIndex i) +{ + if (jobUnderEdit == i.row()) + return; + + if (state == SCHEDULER_RUNNING) + { + appendLogText(i18n("Warning: you cannot add or modify a job while the scheduler is running.")); + return; + } + + SchedulerJob * const job = jobs.at(i.row()); + + if (job == nullptr) + return; + + watchJobChanges(false); + + //job->setState(SchedulerJob::JOB_IDLE); + //job->setStage(SchedulerJob::STAGE_IDLE); + syncGUIToJob(job); + + if (job->getFITSFile().isEmpty() == false) + fitsURL = job->getFITSFile(); + else + fitsURL = QUrl(); + + sequenceURL = job->getSequenceFile(); + /* Turn the add button into an apply button */ setJobAddApply(false); @@ -859,6 +866,22 @@ watchJobChanges(true); } +void Scheduler::queueTableSelectionChanged(QModelIndex current, QModelIndex previous) +{ + Q_UNUSED(previous); + + if (current.row() < 0 || (current.row()+1) > jobs.size()) + return; + + SchedulerJob * const job = jobs.at(current.row()); + + if (job == nullptr) + return; + + resetJobEdit(); + syncGUIToJob(job); +} + void Scheduler::clickQueueTable(QModelIndex index) { setJobManipulation(!Options::sortSchedulerJobs() && index.isValid(), index.isValid()); @@ -884,19 +907,21 @@ void Scheduler::setJobManipulation(bool can_reorder, bool can_delete) { + bool can_edit = (state == SCHEDULER_IDLE); + if (can_reorder) { int const currentRow = queueTable->currentRow(); - queueUpB->setEnabled(0 < currentRow); - queueDownB->setEnabled(currentRow < queueTable->rowCount() - 1); + queueUpB->setEnabled(can_edit && 0 < currentRow); + queueDownB->setEnabled(can_edit && currentRow < queueTable->rowCount() - 1); } else { queueUpB->setEnabled(false); queueDownB->setEnabled(false); } - sortJobsB->setEnabled(can_reorder); - removeFromQueueB->setEnabled(can_delete); + sortJobsB->setEnabled(can_edit && can_reorder); + removeFromQueueB->setEnabled(can_edit && can_delete); } bool Scheduler::reorderJobs(QList reordered_sublist) @@ -1069,8 +1094,16 @@ startB->setEnabled(false); pauseB->setEnabled(false); } - /* Else load the settings of the job that was just deleted */ - else loadJob(queueTable->currentIndex()); + + /* Else update the selection */ + else + { + if (currentRow > queueTable->rowCount()) + currentRow = queueTable->rowCount() - 1; + + loadJob(queueTable->currentIndex()); + queueTable->selectRow(currentRow); + } /* If needed, reset edit mode to clean up UI */ if (jobUnderEdit >= 0) @@ -1087,7 +1120,7 @@ void Scheduler::toggleScheduler() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) { preemptiveShutdown = false; stop(); @@ -1098,7 +1131,7 @@ void Scheduler::stop() { - if (state != SCHEDULER_RUNNIG) + if (state != SCHEDULER_RUNNING) return; qCInfo(KSTARS_EKOS_SCHEDULER) << "Scheduler is stopping..."; @@ -1210,6 +1243,7 @@ setJobManipulation(false, false); mosaicB->setEnabled(true); evaluateOnlyB->setEnabled(true); + queueTable->setEnabled(true); } void Scheduler::start() @@ -1250,10 +1284,11 @@ evaluateOnlyB->setEnabled(false); startupB->setEnabled(false); shutdownB->setEnabled(false); + queueTable->setEnabled(false); /* Reset and re-evaluate all scheduler jobs, then start the Scheduler */ startJobEvaluation(); - state = SCHEDULER_RUNNIG; + state = SCHEDULER_RUNNING; emit newStatus(state); schedulerTimer.start(); @@ -1268,7 +1303,7 @@ /* Edit-related buttons are still disabled */ /* The end-user cannot update the schedule, don't re-evaluate jobs. Timer schedulerTimer is already running. */ - state = SCHEDULER_RUNNIG; + state = SCHEDULER_RUNNING; emit newStatus(state); qCDebug(KSTARS_EKOS_SCHEDULER) << "Scheduler paused."; @@ -1360,7 +1395,7 @@ case SchedulerJob::JOB_ABORTED: /* If job is aborted and we're running, keep its evaluation until there is nothing else to do */ - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) continue; /* Fall through */ case SchedulerJob::JOB_IDLE: @@ -1949,7 +1984,7 @@ /* Apply sorting to queue table, and mark it for saving if it changes */ mDirty = reorderJobs(sortedJobs); - if (jobEvaluationOnly || state != SCHEDULER_RUNNIG) + if (jobEvaluationOnly || state != SCHEDULER_RUNNING) { qCInfo(KSTARS_EKOS_SCHEDULER) << "Ekos finished evaluating jobs, no job selection required."; jobEvaluationOnly = false; @@ -2033,7 +2068,7 @@ } else { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) appendLogText(i18n("Scheduler is awake. Jobs shall be started when ready...")); else appendLogText(i18n("Scheduler is awake. Jobs shall be started when scheduler is resumed.")); @@ -2536,6 +2571,9 @@ return; setCurrentJob(job); + int index = jobs.indexOf(job); + if (index >= 0) + queueTable->selectRow(index); QDateTime const now = KStarsData::Instance()->lt(); @@ -3000,7 +3038,7 @@ setCurrentJob(nullptr); - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) schedulerTimer.start(); if (preemptiveShutdown == false) @@ -3970,7 +4008,7 @@ bool Scheduler::manageConnectionLoss() { - if (SCHEDULER_RUNNIG != state) + if (SCHEDULER_RUNNING != state) return false; // Don't manage loss if Ekos is actually down in the state machine @@ -4064,11 +4102,12 @@ if (jobUnderEdit >= 0) resetJobEdit(); - qDeleteAll(jobs); - jobs.clear(); while (queueTable->rowCount() > 0) queueTable->removeRow(0); + qDeleteAll(jobs); + jobs.clear(); + LilXML *xmlParser = newLilXML(); char errmsg[MAXRBUF]; XMLEle *root = nullptr; @@ -4969,7 +5008,7 @@ if (sender() == startupProcedureButtonGroup || sender() == shutdownProcedureGroup) return; - if (0 <= jobUnderEdit && state != SCHEDULER_RUNNIG && 0 <= queueTable->currentRow()) + if (0 <= jobUnderEdit && state != SCHEDULER_RUNNING && 0 <= queueTable->currentRow()) { // Now that jobs are sorted, reset jobs that are later than the edited one for re-evaluation for (int row = jobUnderEdit; row < jobs.size(); row++) @@ -6230,7 +6269,7 @@ void Scheduler::resetAllJobs() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) return; // Reset capture count of all jobs before re-evaluating diff --git a/org.kde.kstars.appdata.xml b/org.kde.kstars.appdata.xml --- a/org.kde.kstars.appdata.xml +++ b/org.kde.kstars.appdata.xml @@ -250,7 +250,7 @@
  • Herunterladbare Kataloge einschließlich Messier-Bilder, Abell-Katalog, Sharpless-Katalog und Lynds Dunkelnebel-Katalog
  • Downloadable catalogues including Messier Images, Abell Planetary Nebulae, Sharpless Catalogue, Lynds Dark Nebula Catalogue
  • Los catálogos que puede descargar contienen imágenes de objetos Messier, Nebulosas planetarias Abell, el Catálogo Sharpless y el catálogo de nebulosas oscuras Lynds
  • -
  • Catálogos dispoñíbeis para descarga entre os que atopará imaxes de Messier, as nebulosas planetarias Abell, o catálogo Sharpless ou o catálogo de nebulosa escura de Lynds.
  • +
  • Catálogos dispoñíbeis para descarga entre os que hai imaxes de Messier, as nebulosas planetarias Abell, o catálogo Sharpless ou o catálogo de nebulosa escura de Lynds.
  • Katalog yang dapat didownload termasuk Messier Images, Abell Planetary Nebulae, Sharpless Catalogue, Lynds Dark Nebula Catalog
  • Catalogi die kunnen worden gedownload, met inbegrip van Messier objecten, Abell planetaire nevels, Sharpless Catalogus, Lynds Dark Nebula Catalog (catalogus donkere nevels)
  • Katalogi do pobrania zawierające obrazy Messier, Mgławicę planetarną Abell, Katalog Sharpless, Katalog Lynds Dark Nebula