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) @@ -3996,15 +4006,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 +4246,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/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..."; @@ -1253,7 +1286,7 @@ /* 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 +1301,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 +1393,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 +1982,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 +2066,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.")); @@ -3000,7 +3033,7 @@ setCurrentJob(nullptr); - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) schedulerTimer.start(); if (preemptiveShutdown == false) @@ -3970,7 +4003,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 +4097,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 +5003,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 +6264,7 @@ void Scheduler::resetAllJobs() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) return; // Reset capture count of all jobs before re-evaluating