Commit f1dbdc49 authored by Jasem Mutlaq's avatar Jasem Mutlaq

Make scheduler job edit more interactive to avoid usability problems with adding and editing jobs

parent 25ff36e9
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
#define UPDATE_PERIOD_MS 1000 #define UPDATE_PERIOD_MS 1000
#define SETTING_ALTITUDE_CUTOFF 3 #define SETTING_ALTITUDE_CUTOFF 3
#define DEFAULT_CULMINATION_TIME -60
#define DEFAULT_MIN_ALTITUDE 15
#define DEFAULT_MIN_MOON_SEPARATION 0
namespace Ekos namespace Ekos
{ {
...@@ -134,7 +138,7 @@ Scheduler::Scheduler() ...@@ -134,7 +138,7 @@ Scheduler::Scheduler()
raBox->setDegType(false); //RA box should be HMS-style raBox->setDegType(false); //RA box should be HMS-style
addToQueueB->setIcon(QIcon::fromTheme("list-add")); addToQueueB->setIcon(QIcon::fromTheme("list-add"));
addToQueueB->setToolTip(i18n("Add observation job to list.")); addToQueueB->setToolTip(i18n("Add observation job to list."));
removeFromQueueB->setIcon(QIcon::fromTheme("list-remove")); removeFromQueueB->setIcon(QIcon::fromTheme("list-remove"));
removeFromQueueB->setToolTip(i18n("Remove observation job from list.")); removeFromQueueB->setToolTip(i18n("Remove observation job from list."));
...@@ -161,32 +165,14 @@ Scheduler::Scheduler() ...@@ -161,32 +165,14 @@ Scheduler::Scheduler()
connect(addToQueueB,SIGNAL(clicked()),this,SLOT(addJob())); connect(addToQueueB,SIGNAL(clicked()),this,SLOT(addJob()));
connect(removeFromQueueB, SIGNAL(clicked()), this, SLOT(removeJob())); connect(removeFromQueueB, SIGNAL(clicked()), this, SLOT(removeJob()));
connect(evaluateOnlyB, SIGNAL(clicked()), this, SLOT(startJobEvaluation())); connect(evaluateOnlyB, SIGNAL(clicked()), this, SLOT(startJobEvaluation()));
connect(queueTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(editJob(QModelIndex))); connect(queueTable, SIGNAL(clicked(QModelIndex)), this, SLOT(loadJob(QModelIndex)));
connect(queueTable, SIGNAL(itemSelectionChanged()), this, SLOT(resetJobEdit())); //connect(queueTable, SIGNAL(itemSelectionChanged()), this, SLOT(resetJobEdit()));
connect(startB,SIGNAL(clicked()),this,SLOT(toggleScheduler())); connect(startB,SIGNAL(clicked()),this,SLOT(toggleScheduler()));
connect(queueSaveAsB,SIGNAL(clicked()),this,SLOT(saveAs())); connect(queueSaveAsB,SIGNAL(clicked()),this,SLOT(saveAs()));
connect(queueSaveB,SIGNAL(clicked()),this,SLOT(save())); connect(queueSaveB,SIGNAL(clicked()),this,SLOT(save()));
connect(queueLoadB,SIGNAL(clicked()),this,SLOT(load())); connect(queueLoadB,SIGNAL(clicked()),this,SLOT(load()));
connect(startupScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
connect(shutdownScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
connect(weatherCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(trackStepCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(focusStepCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(alignStepCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(guideStepCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(capCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(uncapCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(parkMountCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(unparkMountCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(parkDomeCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(unparkDomeCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(warmCCDCheck, SIGNAL(toggled(bool)), this, SLOT(setDirty()));
connect(startupScript, SIGNAL(textChanged(QString)), this, SLOT(setDirty()));
connect(shutdownScript, SIGNAL(textChanged(QString)), this, SLOT(setDirty()));
connect(fitsEdit, SIGNAL(textChanged(QString)), this, SLOT(setDirty()));
} }
Scheduler::~Scheduler() Scheduler::~Scheduler()
...@@ -194,6 +180,40 @@ Scheduler::~Scheduler() ...@@ -194,6 +180,40 @@ Scheduler::~Scheduler()
} }
void Scheduler::watchJobChanges(bool enable)
{
if (enable)
{
connect(fitsEdit, SIGNAL(editingFinished()), this, SLOT(setDirty()));
connect(startupScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
connect(shutdownScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
connect(stepsButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
connect(startupButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
connect(constraintButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
connect(completionButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
connect(startupProcedureButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
connect(shutdownProcedureGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
}
else
{
//disconnect(this, SLOT(setDirty()));
disconnect(fitsEdit, SIGNAL(editingFinished()), this, SLOT(setDirty()));
disconnect(startupScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
disconnect(shutdownScript, SIGNAL(editingFinished()), this, SLOT(setDirty()));
disconnect(stepsButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
disconnect(startupButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
disconnect(constraintButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
disconnect(completionButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
disconnect(startupProcedureButtonGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
disconnect(shutdownProcedureGroup, SIGNAL(buttonToggled(int,bool)), this, SLOT(setDirty()));
}
}
void Scheduler::appendLogText(const QString &text) void Scheduler::appendLogText(const QString &text)
{ {
...@@ -314,6 +334,12 @@ void Scheduler::selectShutdownScript() ...@@ -314,6 +334,12 @@ void Scheduler::selectShutdownScript()
} }
void Scheduler::addJob() void Scheduler::addJob()
{
jobUnderEdit = false;
saveJob();
}
void Scheduler::saveJob()
{ {
if (state == SCHEDULER_RUNNIG) if (state == SCHEDULER_RUNNIG)
...@@ -322,6 +348,8 @@ void Scheduler::addJob() ...@@ -322,6 +348,8 @@ void Scheduler::addJob()
return; return;
} }
watchJobChanges(false);
if(nameEdit->text().isEmpty()) if(nameEdit->text().isEmpty())
{ {
appendLogText(i18n("Target name is required.")); appendLogText(i18n("Target name is required."));
...@@ -401,9 +429,14 @@ void Scheduler::addJob() ...@@ -401,9 +429,14 @@ void Scheduler::addJob()
// Do we have minimum altitude constraint? // Do we have minimum altitude constraint?
if (altConstraintCheck->isChecked()) if (altConstraintCheck->isChecked())
job->setMinAltitude(minAltitude->value()); job->setMinAltitude(minAltitude->value());
else
job->setMinAltitude(-1);
// Do we have minimum moon separation constraint? // Do we have minimum moon separation constraint?
if (moonSeparationCheck->isChecked()) if (moonSeparationCheck->isChecked())
job->setMinMoonSeparation(minMoonSeparation->value()); job->setMinMoonSeparation(minMoonSeparation->value());
else
job->setMinMoonSeparation(-1);
// Check enforce weather constraints // Check enforce weather constraints
job->setEnforceWeather(weatherCheck->isChecked()); job->setEnforceWeather(weatherCheck->isChecked());
...@@ -494,14 +527,16 @@ void Scheduler::addJob() ...@@ -494,14 +527,16 @@ void Scheduler::addJob()
if (jobUnderEdit) if (jobUnderEdit)
{ {
jobUnderEdit = false; jobUnderEdit = false;
resetJobEdit(); //resetJobEdit();
appendLogText(i18n("Job #%1 changes applied.", currentRow+1)); //appendLogText(i18n("Job #%1 changes applied.", currentRow+1));
} }
startB->setEnabled(true); startB->setEnabled(true);
watchJobChanges(true);
} }
void Scheduler::editJob(QModelIndex i) void Scheduler::loadJob(QModelIndex i)
{ {
if (state == SCHEDULER_RUNNIG) if (state == SCHEDULER_RUNNIG)
{ {
...@@ -511,7 +546,9 @@ void Scheduler::editJob(QModelIndex i) ...@@ -511,7 +546,9 @@ void Scheduler::editJob(QModelIndex i)
SchedulerJob *job = jobs.at(i.row()); SchedulerJob *job = jobs.at(i.row());
if (job == NULL) if (job == NULL)
return; return;
watchJobChanges(false);
job->setState(SchedulerJob::JOB_IDLE); job->setState(SchedulerJob::JOB_IDLE);
job->setStage(SchedulerJob::STAGE_IDLE); job->setStage(SchedulerJob::STAGE_IDLE);
...@@ -546,10 +583,12 @@ void Scheduler::editJob(QModelIndex i) ...@@ -546,10 +583,12 @@ void Scheduler::editJob(QModelIndex i)
{ {
case SchedulerJob::START_ASAP: case SchedulerJob::START_ASAP:
asapConditionR->setChecked(true); asapConditionR->setChecked(true);
culminationOffset->setValue(DEFAULT_CULMINATION_TIME);
break; break;
case SchedulerJob::START_FORCE_NOW: case SchedulerJob::START_FORCE_NOW:
forceNowConditionR->setChecked(true); forceNowConditionR->setChecked(true);
culminationOffset->setValue(DEFAULT_CULMINATION_TIME);
break; break;
case SchedulerJob::START_CULMINATION: case SchedulerJob::START_CULMINATION:
...@@ -560,6 +599,7 @@ void Scheduler::editJob(QModelIndex i) ...@@ -560,6 +599,7 @@ void Scheduler::editJob(QModelIndex i)
case SchedulerJob::START_AT: case SchedulerJob::START_AT:
startupTimeConditionR->setChecked(true); startupTimeConditionR->setChecked(true);
startupTimeEdit->setDateTime(job->getStartupTime()); startupTimeEdit->setDateTime(job->getStartupTime());
culminationOffset->setValue(DEFAULT_CULMINATION_TIME);
break; break;
} }
...@@ -568,12 +608,22 @@ void Scheduler::editJob(QModelIndex i) ...@@ -568,12 +608,22 @@ void Scheduler::editJob(QModelIndex i)
altConstraintCheck->setChecked(true); altConstraintCheck->setChecked(true);
minAltitude->setValue(job->getMinAltitude()); minAltitude->setValue(job->getMinAltitude());
} }
else
{
altConstraintCheck->setChecked(false);
minAltitude->setValue(DEFAULT_MIN_ALTITUDE);
}
if (job->getMinMoonSeparation() >= 0) if (job->getMinMoonSeparation() >= 0)
{ {
moonSeparationCheck->setChecked(true); moonSeparationCheck->setChecked(true);
minMoonSeparation->setValue(job->getMinMoonSeparation()); minMoonSeparation->setValue(job->getMinMoonSeparation());
} }
else
{
moonSeparationCheck->setChecked(false);
minMoonSeparation->setValue(DEFAULT_MIN_MOON_SEPARATION);
}
weatherCheck->setChecked(job->getEnforceWeather()); weatherCheck->setChecked(job->getEnforceWeather());
...@@ -593,7 +643,7 @@ void Scheduler::editJob(QModelIndex i) ...@@ -593,7 +643,7 @@ void Scheduler::editJob(QModelIndex i)
break; break;
} }
appendLogText(i18n("Editing job #%1...", i.row()+1)); /*appendLogText(i18n("Editing job #%1...", i.row()+1));
addToQueueB->setIcon(QIcon::fromTheme("dialog-ok-apply")); addToQueueB->setIcon(QIcon::fromTheme("dialog-ok-apply"));
addToQueueB->setEnabled(true); addToQueueB->setEnabled(true);
...@@ -603,10 +653,13 @@ void Scheduler::editJob(QModelIndex i) ...@@ -603,10 +653,13 @@ void Scheduler::editJob(QModelIndex i)
addToQueueB->setToolTip(i18n("Apply job changes.")); addToQueueB->setToolTip(i18n("Apply job changes."));
removeFromQueueB->setToolTip(i18n("Cancel job changes.")); removeFromQueueB->setToolTip(i18n("Cancel job changes."));
jobUnderEdit = true; jobUnderEdit = true;*/
watchJobChanges(true);
} }
void Scheduler::resetJobEdit() /*void Scheduler::resetJobEdit()
{ {
if (jobUnderEdit) if (jobUnderEdit)
appendLogText(i18n("Editing job canceled.")); appendLogText(i18n("Editing job canceled."));
...@@ -618,15 +671,15 @@ void Scheduler::resetJobEdit() ...@@ -618,15 +671,15 @@ void Scheduler::resetJobEdit()
removeFromQueueB->setToolTip(i18n("Remove observation job from list.")); removeFromQueueB->setToolTip(i18n("Remove observation job from list."));
evaluateOnlyB->setEnabled(true); evaluateOnlyB->setEnabled(true);
} }*/
void Scheduler::removeJob() void Scheduler::removeJob()
{ {
if (jobUnderEdit) /*if (jobUnderEdit)
{ {
resetJobEdit(); resetJobEdit();
return; return;
} }*/
int currentRow = queueTable->currentRow(); int currentRow = queueTable->currentRow();
...@@ -2924,7 +2977,7 @@ bool Scheduler::processJobInfo(XMLEle *root) ...@@ -2924,7 +2977,7 @@ bool Scheduler::processJobInfo(XMLEle *root)
} }
} }
addJob(); saveJob();
return true; return true;
...@@ -3372,6 +3425,15 @@ void Scheduler::stopEkos() ...@@ -3372,6 +3425,15 @@ void Scheduler::stopEkos()
void Scheduler::setDirty() void Scheduler::setDirty()
{ {
mDirty = true; mDirty = true;
if (sender() == startupProcedureButtonGroup || sender() == shutdownProcedureGroup)
return;
if (state != SCHEDULER_RUNNIG && queueTable->selectedItems().isEmpty() == false)
{
jobUnderEdit=true;
saveJob();
}
} }
bool Scheduler::estimateJobTime(SchedulerJob *job) bool Scheduler::estimateJobTime(SchedulerJob *job)
...@@ -3988,7 +4050,7 @@ void Scheduler::startMosaicTool() ...@@ -3988,7 +4050,7 @@ void Scheduler::startMosaicTool()
raBox->setText(oneJob->skyCenter.ra0().toHMSString()); raBox->setText(oneJob->skyCenter.ra0().toHMSString());
decBox->setText(oneJob->skyCenter.dec0().toDMSString()); decBox->setText(oneJob->skyCenter.dec0().toDMSString());
addJob(); saveJob();
} }
delXMLEle(root); delXMLEle(root);
......
...@@ -171,7 +171,13 @@ protected slots: ...@@ -171,7 +171,13 @@ protected slots:
void selectShutdownScript(); void selectShutdownScript();
/** /**
* @brief addToQueue Construct a SchedulerJob and add it to the queue * @brief addToQueue Construct a SchedulerJob and add it to the queue or save job settings from current form values.
* jobUnderEdit determines whether to add or edit
*/
void saveJob();
/**
* @brief addJob Add a new job from form values
*/ */
void addJob(); void addJob();
...@@ -179,7 +185,7 @@ protected slots: ...@@ -179,7 +185,7 @@ protected slots:
* @brief editJob Edit an observation job * @brief editJob Edit an observation job
* @param i index model in queue table * @param i index model in queue table
*/ */
void editJob(QModelIndex i); void loadJob(QModelIndex i);
/** /**
* @brief removeJob Remove a job from the currently selected row. If no row is selected, it remove the last job in the queue. * @brief removeJob Remove a job from the currently selected row. If no row is selected, it remove the last job in the queue.
...@@ -191,7 +197,7 @@ protected slots: ...@@ -191,7 +197,7 @@ protected slots:
void saveAs(); void saveAs();
void load(); void load();
void resetJobEdit(); //void resetJobEdit();
/** /**
* @brief checkJobStatus Check the overall state of the scheduler, Ekos, and INDI. When all is OK, it call evaluateJobs(); * @brief checkJobStatus Check the overall state of the scheduler, Ekos, and INDI. When all is OK, it call evaluateJobs();
...@@ -224,6 +230,11 @@ protected slots: ...@@ -224,6 +230,11 @@ protected slots:
*/ */
void checkProcessExit(int exitCode); void checkProcessExit(int exitCode);
/**
* @brief watchJobChanges Watch any changes in form values and apply changes to current job selection or ignore any changes
* @param enable True to watch changes and apply them to current job, false to ignore changes
*/
void watchJobChanges(bool enable);
/** /**
* @brief setDirty Call it to mark the Ekos Scheduler List for change. Next time save button is invoked, the complete content is written to disk. * @brief setDirty Call it to mark the Ekos Scheduler List for change. Next time save button is invoked, the complete content is written to disk.
*/ */
......
...@@ -101,6 +101,9 @@ ...@@ -101,6 +101,9 @@
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">stepsButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -114,6 +117,9 @@ ...@@ -114,6 +117,9 @@
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">stepsButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -127,6 +133,9 @@ ...@@ -127,6 +133,9 @@
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">stepsButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -140,6 +149,9 @@ ...@@ -140,6 +149,9 @@
<property name="checked"> <property name="checked">
<bool>true</bool> <bool>true</bool>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">stepsButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -462,6 +474,12 @@ ...@@ -462,6 +474,12 @@
</item> </item>
<item> <item>
<widget class="QTableWidget" name="queueTable"> <widget class="QTableWidget" name="queueTable">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="rowCount"> <property name="rowCount">
<number>0</number> <number>0</number>
</property> </property>
...@@ -636,6 +654,9 @@ ...@@ -636,6 +654,9 @@
<property name="text"> <property name="text">
<string>Alt &gt; </string> <string>Alt &gt; </string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">constraintButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
...@@ -663,6 +684,9 @@ ...@@ -663,6 +684,9 @@
<property name="text"> <property name="text">
<string>Moon &gt; </string> <string>Moon &gt; </string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">constraintButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
...@@ -694,6 +718,9 @@ ...@@ -694,6 +718,9 @@
<property name="text"> <property name="text">
<string>Weather</string> <string>Weather</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">constraintButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -830,6 +857,9 @@ ...@@ -830,6 +857,9 @@
<property name="text"> <property name="text">
<string>UnPark Dome</string> <string>UnPark Dome</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">startupProcedureButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -843,6 +873,9 @@ ...@@ -843,6 +873,9 @@
<property name="text"> <property name="text">
<string>UnPark Mount</string> <string>UnPark Mount</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">startupProcedureButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -853,6 +886,9 @@ ...@@ -853,6 +886,9 @@
<property name="text"> <property name="text">
<string>UnCap</string> <string>UnCap</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">startupProcedureButtonGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -929,6 +965,9 @@ ...@@ -929,6 +965,9 @@
<property name="text"> <property name="text">
<string>Warm CCD</string> <string>Warm CCD</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">shutdownProcedureGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -939,6 +978,9 @@ ...@@ -939,6 +978,9 @@
<property name="text"> <property name="text">
<string>Cap</string> <string>Cap</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">shutdownProcedureGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -952,6 +994,9 @@ ...@@ -952,6 +994,9 @@
<property name="text"> <property name="text">
<string>Park Mount</string> <string>Park Mount</string>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">shutdownProcedureGroup</string>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
...@@ -965,6 +1010,9 @@ ...@@ -965,6 +1010,9 @@
<property name="text"> <property name="text">