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, [&]() @@ -2441,6 +2442,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) @@ -2590,6 +2600,10 @@ 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()); @@ -4043,15 +4057,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")); @@ -4264,10 +4297,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 @@ -311,11 +311,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. */ @@ -727,6 +739,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 @@ -169,6 +169,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); @@ -454,7 +455,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; @@ -726,47 +727,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); @@ -841,6 +816,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); @@ -857,6 +864,26 @@ watchJobChanges(true); } +void Scheduler::queueTableSelectionChanged(QModelIndex current, QModelIndex previous) +{ + Q_UNUSED(previous); + + // prevent selection when not idle + if (state != SCHEDULER_IDLE) + return; + + 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()); @@ -882,19 +909,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) @@ -1067,8 +1096,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) @@ -1085,7 +1122,7 @@ void Scheduler::toggleScheduler() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) { preemptiveShutdown = false; stop(); @@ -1096,7 +1133,7 @@ void Scheduler::stop() { - if (state != SCHEDULER_RUNNIG) + if (state != SCHEDULER_RUNNING) return; qCInfo(KSTARS_EKOS_SCHEDULER) << "Scheduler is stopping..."; @@ -1251,7 +1288,7 @@ /* Reset and re-evaluate all scheduler jobs, then start the Scheduler */ startJobEvaluation(); - state = SCHEDULER_RUNNIG; + state = SCHEDULER_RUNNING; emit newStatus(state); schedulerTimer.start(); @@ -1266,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."; @@ -1358,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: @@ -1947,7 +1984,7 @@ /* Apply sorting to queue table, and mark it for saving if it changes */ mDirty = reorderJobs(sortedJobs) | mDirty; - if (jobEvaluationOnly || state != SCHEDULER_RUNNIG) + if (jobEvaluationOnly || state != SCHEDULER_RUNNING) { qCInfo(KSTARS_EKOS_SCHEDULER) << "Ekos finished evaluating jobs, no job selection required."; jobEvaluationOnly = false; @@ -2031,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.")); @@ -2203,6 +2240,9 @@ return; setCurrentJob(job); + int index = jobs.indexOf(job); + if (index >= 0) + queueTable->selectRow(index); QDateTime const now = KStarsData::Instance()->lt(); @@ -2667,7 +2707,7 @@ setCurrentJob(nullptr); - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) schedulerTimer.start(); if (preemptiveShutdown == false) @@ -3637,7 +3677,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 @@ -3731,11 +3771,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; @@ -4639,7 +4680,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++) @@ -5920,7 +5961,7 @@ void Scheduler::resetAllJobs() { - if (state == SCHEDULER_RUNNIG) + if (state == SCHEDULER_RUNNING) return; // Reset capture count of all jobs before re-evaluating