1 /*
2 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "filtermanager.h"
8 #include <kstars_debug.h>
9
10 #include "indi_debug.h"
11 #include "kstarsdata.h"
12 #include "kstars.h"
13 #include "Options.h"
14 #include "auxiliary/kspaths.h"
15 #include "auxiliary/ksmessagebox.h"
16 #include "ekos/auxiliary/filterdelegate.h"
17
18 #include <QTimer>
19 #include <QSqlTableModel>
20 #include <QSqlDatabase>
21 #include <QSqlRecord>
22
23 #include <basedevice.h>
24
25 #include <algorithm>
26
27 namespace Ekos
28 {
29
FilterManager()30 FilterManager::FilterManager() : QDialog(KStars::Instance())
31 {
32 #ifdef Q_OS_OSX
33 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
34 #endif
35
36 setupUi(this);
37
38 connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
39 connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
40
41 QSqlDatabase userdb = QSqlDatabase::cloneDatabase(KStarsData::Instance()->userdb()->GetDatabase(), "filter_db");
42 userdb.open();
43
44 kcfg_FlatSyncFocus->setChecked(Options::flatSyncFocus());
45 connect(kcfg_FlatSyncFocus, &QCheckBox::toggled, [this]()
46 {
47 Options::setFlatSyncFocus(kcfg_FlatSyncFocus->isChecked());
48 });
49
50 filterModel = new QSqlTableModel(this, userdb);
51 filterView->setModel(filterModel);
52
53 // No Edit delegate
54 noEditDelegate = new NotEditableDelegate(filterView);
55 filterView->setItemDelegateForColumn(4, noEditDelegate);
56
57 // Exposure delegate
58 exposureDelegate = new ExposureDelegate(filterView);
59 filterView->setItemDelegateForColumn(5, exposureDelegate);
60
61 // Offset delegate
62 offsetDelegate = new OffsetDelegate(filterView);
63 filterView->setItemDelegateForColumn(6, offsetDelegate);
64
65 // Auto Focus delegate
66 useAutoFocusDelegate = new UseAutoFocusDelegate(filterView);
67 filterView->setItemDelegateForColumn(7, useAutoFocusDelegate);
68
69 // Set Delegates
70 lockDelegate = new LockDelegate(m_currentFilterLabels, filterView);
71 filterView->setItemDelegateForColumn(8, lockDelegate);
72
73 // Absolute Focus Position
74 filterView->setItemDelegateForColumn(9, noEditDelegate);
75
76 connect(filterModel, &QSqlTableModel::dataChanged, [this](const QModelIndex & topLeft, const QModelIndex &,
77 const QVector<int> &)
78 {
79 reloadFilters();
80 if (topLeft.column() == 5)
81 emit exposureChanged(filterModel->data(topLeft).toDouble());
82 });
83 }
84
refreshFilterModel()85 void FilterManager::refreshFilterModel()
86 {
87 if (m_currentFilterDevice == nullptr || m_currentFilterLabels.empty())
88 return;
89
90 QString vendor(m_currentFilterDevice->getDeviceName());
91
92 //QSqlDatabase::removeDatabase("filter_db");
93 //QSqlDatabase userdb = QSqlDatabase::cloneDatabase(KStarsData::Instance()->userdb()->GetDatabase(), "filter_db");
94 //userdb.open();
95
96 //delete (filterModel);
97
98 //filterModel = new QSqlTableModel(this, userdb);
99 if (!filterModel)
100 {
101 QSqlDatabase userdb = QSqlDatabase::cloneDatabase(KStarsData::Instance()->userdb()->GetDatabase(), "filter_db");
102 userdb.open();
103 filterModel = new QSqlTableModel(this, userdb);
104 filterView->setModel(filterModel);
105 }
106 filterModel->setTable("filter");
107 filterModel->setFilter(QString("vendor='%1'").arg(vendor));
108 filterModel->select();
109 filterModel->setEditStrategy(QSqlTableModel::OnFieldChange);
110
111 // If we have an existing table but it doesn't match the number of current filters
112 // then we remove it.
113 if (filterModel->rowCount() > 0 && filterModel->rowCount() != m_currentFilterLabels.count())
114 {
115 for (int i = 0; i < filterModel->rowCount(); i++)
116 filterModel->removeRow(i);
117
118 filterModel->select();
119 }
120
121 // If it is first time, let's populate data
122 if (filterModel->rowCount() == 0)
123 {
124 for (QString &filter : m_currentFilterLabels)
125 KStarsData::Instance()->userdb()->AddFilter(vendor, "", "", filter, 0, 1.0, false, "--", 0);
126
127 filterModel->select();
128 // Seems ->select() is not enough, have to create a new model.
129 /*delete (filterModel);
130 filterModel = new QSqlTableModel(this, userdb);
131 filterModel->setTable("filter");
132 filterModel->setFilter(QString("vendor='%1'").arg(m_currentFilterDevice->getDeviceName()));
133 filterModel->select();
134 filterModel->setEditStrategy(QSqlTableModel::OnManualSubmit);*/
135 }
136 // Make sure all the filter colors match DB. If not update model to sync with INDI filter values
137 else
138 {
139 for (int i = 0; i < filterModel->rowCount(); ++i)
140 {
141 QModelIndex index = filterModel->index(i, 4);
142 if (filterModel->data(index).toString() != m_currentFilterLabels[i])
143 {
144 filterModel->setData(index, m_currentFilterLabels[i]);
145 }
146 }
147 }
148
149 lockDelegate->setCurrentFilterList(m_currentFilterLabels);
150
151 filterModel->setHeaderData(4, Qt::Horizontal, i18n("Filter"));
152
153 filterModel->setHeaderData(5, Qt::Horizontal, i18n("Filter exposure time during focus"), Qt::ToolTipRole);
154 filterModel->setHeaderData(5, Qt::Horizontal, i18n("Exposure"));
155
156 filterModel->setHeaderData(6, Qt::Horizontal, i18n("Relative offset in steps"), Qt::ToolTipRole);
157 filterModel->setHeaderData(6, Qt::Horizontal, i18n("Offset"));
158
159 filterModel->setHeaderData(7, Qt::Horizontal, i18n("Start Auto Focus when filter is activated"), Qt::ToolTipRole);
160 filterModel->setHeaderData(7, Qt::Horizontal, i18n("Auto Focus"));
161
162 filterModel->setHeaderData(8, Qt::Horizontal, i18n("Lock specific filter when running Auto Focus"), Qt::ToolTipRole);
163 filterModel->setHeaderData(8, Qt::Horizontal, i18n("Lock Filter"));
164
165 filterModel->setHeaderData(9, Qt::Horizontal,
166 i18n("Flat frames are captured at this focus position. It is updated automatically by focus process if enabled."),
167 Qt::ToolTipRole);
168 filterModel->setHeaderData(9, Qt::Horizontal, i18n("Flat Focus Position"));
169
170 filterView->hideColumn(0);
171 filterView->hideColumn(1);
172 filterView->hideColumn(2);
173 filterView->hideColumn(3);
174
175 reloadFilters();
176 }
177
reloadFilters()178 void FilterManager::reloadFilters()
179 {
180 qDeleteAll(m_ActiveFilters);
181 currentFilter = nullptr;
182 targetFilter = nullptr;
183 m_ActiveFilters.clear();
184 operationQueue.clear();
185
186 for (int i = 0; i < filterModel->rowCount(); ++i)
187 {
188 QSqlRecord record = filterModel->record(i);
189 QString id = record.value("id").toString();
190 QString vendor = record.value("Vendor").toString();
191 QString model = record.value("Model").toString();
192 QString type = record.value("Type").toString();
193 QString color = record.value("Color").toString();
194 double exposure = record.value("Exposure").toDouble();
195 int offset = record.value("Offset").toInt();
196 QString lockedFilter = record.value("LockedFilter").toString();
197 bool useAutoFocus = record.value("UseAutoFocus").toInt() == 1;
198 int absFocusPos = record.value("AbsoluteFocusPosition").toInt();
199 OAL::Filter *o = new OAL::Filter(id, model, vendor, type, color, exposure, offset, useAutoFocus, lockedFilter,
200 absFocusPos);
201 m_ActiveFilters.append(o);
202 }
203 }
204
setCurrentFilterWheel(ISD::GDInterface * filter)205 void FilterManager::setCurrentFilterWheel(ISD::GDInterface *filter)
206 {
207 if (m_currentFilterDevice == filter)
208 return;
209 else if (m_currentFilterDevice)
210 m_currentFilterDevice->disconnect(this);
211
212 m_currentFilterDevice = filter;
213
214 connect(filter, &ISD::GenericDevice::textUpdated, this, &FilterManager::processText);
215 connect(filter, &ISD::GenericDevice::numberUpdated, this, &FilterManager::processNumber);
216 connect(filter, &ISD::GenericDevice::switchUpdated, this, &FilterManager::processSwitch);
217 connect(filter, &ISD::GDInterface::Disconnected, [&]()
218 {
219 m_currentFilterLabels.clear();
220 m_currentFilterPosition = -1;
221 //m_currentFilterDevice = nullptr;
222 m_FilterNameProperty = nullptr;
223 m_FilterPositionProperty = nullptr;
224 });
225
226 m_FilterNameProperty = nullptr;
227 m_FilterPositionProperty = nullptr;
228 m_FilterConfirmSet = nullptr;
229 initFilterProperties();
230 }
231
initFilterProperties()232 void FilterManager::initFilterProperties()
233 {
234 if (m_FilterNameProperty && m_FilterPositionProperty)
235 {
236 if (m_FilterConfirmSet == nullptr)
237 m_FilterConfirmSet = m_currentFilterDevice->getBaseDevice()->getSwitch("CONFIRM_FILTER_SET");
238 return;
239 }
240
241 filterNameLabel->setText(m_currentFilterDevice->getDeviceName());
242
243 m_currentFilterLabels.clear();
244
245 m_FilterNameProperty = m_currentFilterDevice->getBaseDevice()->getText("FILTER_NAME");
246 m_FilterPositionProperty = m_currentFilterDevice->getBaseDevice()->getNumber("FILTER_SLOT");
247 m_FilterConfirmSet = m_currentFilterDevice->getBaseDevice()->getSwitch("CONFIRM_FILTER_SET");
248
249 m_currentFilterPosition = getFilterPosition(true);
250 m_currentFilterLabels = getFilterLabels(true);
251
252 if (m_currentFilterLabels.isEmpty() == false)
253 refreshFilterModel();
254
255 if (m_currentFilterPosition >= 1 && m_currentFilterPosition <= m_ActiveFilters.count())
256 lastFilterOffset = m_ActiveFilters[m_currentFilterPosition - 1]->offset();
257 }
258
getFilterLabels(bool forceRefresh)259 QStringList FilterManager::getFilterLabels(bool forceRefresh)
260 {
261 if (forceRefresh == false || m_FilterNameProperty == nullptr)
262 return m_currentFilterLabels;
263
264 QStringList filterList;
265
266 QStringList filterAlias = Options::filterAlias();
267
268 for (int i = 0; i < m_FilterPositionProperty->np[0].max; i++)
269 {
270 QString item;
271
272 if (m_FilterNameProperty != nullptr && (i < m_FilterNameProperty->ntp))
273 item = m_FilterNameProperty->tp[i].text;
274 else if (i < filterAlias.count() && filterAlias[i].isEmpty() == false)
275 item = filterAlias.at(i);
276
277 filterList.append(item);
278 }
279
280 return filterList;
281 }
282
getFilterPosition(bool forceRefresh)283 int FilterManager::getFilterPosition(bool forceRefresh)
284 {
285 if (forceRefresh == false)
286 return m_currentFilterPosition;
287
288 return static_cast<int>(m_FilterPositionProperty->np[0].value);
289 }
290
setFilterPosition(uint8_t position,FilterPolicy policy)291 bool FilterManager::setFilterPosition(uint8_t position, FilterPolicy policy)
292 {
293 // Position 1 to Max
294 if (position > m_ActiveFilters.count())
295 return false;
296
297 m_Policy = policy;
298 currentFilter = m_ActiveFilters[m_currentFilterPosition - 1];
299 targetFilter = m_ActiveFilters[position - 1];
300
301 if (currentFilter == targetFilter)
302 {
303 emit ready();
304 return true;
305 }
306
307 buildOperationQueue(FILTER_CHANGE);
308
309 executeOperationQueue();
310
311 return true;
312 }
313
processNumber(INumberVectorProperty * nvp)314 void FilterManager::processNumber(INumberVectorProperty *nvp)
315 {
316 if (nvp->s != IPS_OK || strcmp(nvp->name, "FILTER_SLOT") || m_currentFilterDevice == nullptr
317 || (nvp->device != m_currentFilterDevice->getDeviceName()))
318 return;
319
320 m_FilterPositionProperty = nvp;
321
322 if (m_currentFilterPosition != static_cast<int>(m_FilterPositionProperty->np[0].value))
323 {
324 m_currentFilterPosition = static_cast<int>(m_FilterPositionProperty->np[0].value);
325 emit positionChanged(m_currentFilterPosition);
326 }
327
328 if (state == FILTER_CHANGE)
329 executeOperationQueue();
330 // If filter is changed externally, record its current offset as the starting offset.
331 else if (state == FILTER_IDLE && m_ActiveFilters.count() >= m_currentFilterPosition)
332 lastFilterOffset = m_ActiveFilters[m_currentFilterPosition - 1]->offset();
333
334 // Check if we have to apply Focus Offset
335 // Focus offsets are always applied first
336
337
338
339 // Check if we have to start Auto Focus
340 // If new filter position changed, and new filter policy is to perform auto-focus then autofocus is initiated.
341
342 // Capture Module
343 // 3x L ---> 3x HA ---> 3x L
344 // Capture calls setFilterPosition("L").
345 // 0. Change filter to desired filter "L"
346 // 1. Is there any offset from last offset that needs to be applied?
347 // 1.1 Yes --> Apply focus offset and wait until position is changed:
348 // 1.1.1 Position complete, now check for useAutoFocus policy (#2).
349 // 1.1.2 Position failed, retry?
350 // 1.2 No --> Go to #2
351 // 2. Is there autofocus policy for current filter?
352 // 2.1. Yes --> Check filter lock policy
353 // 2.1.1 If filter lock is another filter --> Change filter
354 // 2.1.2 If filter lock is same filter --> proceed to 2.3
355 // 2.2 No --> Process to 2.3
356 // 2.3 filter lock policy filter is applied, start autofocus.
357 // 2.4 Autofocus complete. Check filter lock policy
358 // 2.4.1 If filter lock policy was applied --> revert filter
359 // 2.4.1.1 If filter offset policy is applicable --> Apply offset
360 // 2.4.1.2 If no filter offset policy is applicable --> Go to 2.5
361 // 2.4.2 No filter lock policy, go to 2.5
362 // 2.5 All complete, emit ready()
363
364 // Example. Current filter L. setFilterPosition("HA"). AutoFocus = YES. HA lock policy: L, HA offset policy: +100 with respect to L
365 // Operation Stack. offsetDiff = 100
366 // If AutoFocus && current filter = lock policy filter
367 // AUTO_FOCUS (on L)
368 // CHANGE_FILTER (to HA)
369 // APPLY_OFFSET: +100
370
371 // Example. Current filter L. setFilterPosition("HA"). AutoFocus = No. HA lock policy: L, HA offset policy: +100 with respect to L
372 // Operation Stack. offsetDiff = 100
373 // CHANGE_FILTER (to HA)
374 // APPLY_OFFSET: +100
375
376
377
378
379 // Example. Current filter R. setFilterPosition("B"). AutoFocus = YES. B lock policy: "--", B offset policy: +70 with respect to L
380 // R offset = -50 with respect to L
381 // FILTER_CHANGE (to B)
382 // FILTER_OFFSET (+120)
383 // AUTO_FOCUS
384
385 // Example. Current filter R. setFilterPosition("HA"). AutoFocus = YES. HA lock policy: L, HA offset policy: +100 with respect to L
386 // R offset = -50 with respect to L
387 // Operation Stack. offsetDiff = +150
388 // CHANGE_FILTER (to L)
389 // APPLY_OFFSET: +50 (L - R)
390 // AUTO_FOCUS
391 // CHANGE_FILTER (HA)
392 // APPLY_OFFSET: +100
393
394
395
396 // Example. Current filter R. setFilterPosition("HA"). AutoFocus = No. HA lock policy: L, HA offset policy: +100 with respect to L
397 // R offset = -50 with respect to L
398 // Operation Stack. offsetDiff = +150
399 // CHANGE_FILTER (to HA)
400 // APPLY_OFFSET: +150 (HA - R)
401
402
403
404 // Example. Current filter L. setFilterPosition("R"). AutoFocus = Yes. R lock policy: R, R offset policy: -50 with respect to L
405 // Operation Stack. offsetDiff = -50
406 // CHANGE_FILTER (to R)
407 // APPLY_OFFSET: -50 (R - L)
408 // AUTO_FOCUS
409
410
411 }
412
processText(ITextVectorProperty * tvp)413 void FilterManager::processText(ITextVectorProperty *tvp)
414 {
415 if (strcmp(tvp->name, "FILTER_NAME") || m_currentFilterDevice == nullptr
416 || (tvp->device != m_currentFilterDevice->getDeviceName()) )
417 return;
418
419 m_FilterNameProperty = tvp;
420
421 QStringList newFilterLabels = getFilterLabels(true);
422
423 if (newFilterLabels != m_currentFilterLabels)
424 {
425 m_currentFilterLabels = newFilterLabels;
426
427 refreshFilterModel();
428
429 emit labelsChanged(newFilterLabels);
430 }
431 }
432
processSwitch(ISwitchVectorProperty * svp)433 void FilterManager::processSwitch(ISwitchVectorProperty *svp)
434 {
435 if (m_currentFilterDevice == nullptr || (svp->device != m_currentFilterDevice->getDeviceName()))
436 return;
437
438 }
439
buildOperationQueue(FilterState operation)440 void FilterManager::buildOperationQueue(FilterState operation)
441 {
442 operationQueue.clear();
443 m_useTargetFilter = false;
444
445 switch (operation)
446 {
447 case FILTER_CHANGE:
448 {
449 if ( (m_Policy & CHANGE_POLICY) && targetFilter != currentFilter)
450 m_useTargetFilter = true;
451
452 if (m_useTargetFilter)
453 {
454 operationQueue.enqueue(FILTER_CHANGE);
455 if (m_FocusReady && (m_Policy & OFFSET_POLICY))
456 operationQueue.enqueue(FILTER_OFFSET);
457 }
458
459 if (m_FocusReady && (m_Policy & AUTOFOCUS_POLICY) && targetFilter->useAutoFocus())
460 operationQueue.enqueue(FILTER_AUTOFOCUS);
461 }
462 break;
463
464 default:
465 break;
466 }
467 }
468
executeOperationQueue()469 bool FilterManager::executeOperationQueue()
470 {
471 if (operationQueue.isEmpty())
472 {
473 state = FILTER_IDLE;
474 emit newStatus(state);
475 emit ready();
476 return false;
477 }
478
479 FilterState nextOperation = operationQueue.dequeue();
480
481 bool actionRequired = true;
482
483 switch (nextOperation)
484 {
485 case FILTER_CHANGE:
486 {
487 if (m_ConfirmationPending)
488 return true;
489
490 state = FILTER_CHANGE;
491 if (m_useTargetFilter)
492 targetFilterPosition = m_ActiveFilters.indexOf(targetFilter) + 1;
493 m_currentFilterDevice->runCommand(INDI_SET_FILTER, &targetFilterPosition);
494 emit newStatus(state);
495
496 if (m_FilterConfirmSet)
497 {
498 // if (KMessageBox::questionYesNo(KStars::Instance(),
499 // i18n("Set filter to %1. Is filter set?", targetFilter->color()),
500 // i18n("Confirm Filter")) == KMessageBox::Yes)
501 // m_currentFilterDevice->runCommand(INDI_CONFIRM_FILTER);
502
503 connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this]()
504 {
505 //QObject::disconnect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, nullptr);
506 KSMessageBox::Instance()->disconnect(this);
507 m_ConfirmationPending = false;
508 m_currentFilterDevice->runCommand(INDI_CONFIRM_FILTER);
509 });
510 connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this]()
511 {
512 //QObject::disconnect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, nullptr);
513 KSMessageBox::Instance()->disconnect(this);
514 m_ConfirmationPending = false;
515 });
516
517 m_ConfirmationPending = true;
518
519 KSMessageBox::Instance()->questionYesNo(i18n("Set filter to %1. Is filter set?", targetFilter->color()),
520 i18n("Confirm Filter"));
521 }
522 }
523 break;
524
525 case FILTER_OFFSET:
526 {
527 state = FILTER_OFFSET;
528 if (m_useTargetFilter)
529 {
530 targetFilterOffset = targetFilter->offset() - lastFilterOffset;
531 lastFilterOffset = targetFilter->offset();
532 currentFilter = targetFilter;
533 m_useTargetFilter = false;
534 }
535 if (targetFilterOffset == 0)
536 actionRequired = false;
537 else
538 {
539 emit newFocusOffset(targetFilterOffset, false);
540 emit newStatus(state);
541 }
542 }
543 break;
544
545 case FILTER_AUTOFOCUS:
546 state = FILTER_AUTOFOCUS;
547 qCDebug(KSTARS) << "FilterManager.cpp is triggering autofocus.";
548 emit newStatus(state);
549 emit checkFocus(0.01);
550 break;
551
552 default:
553 break;
554 }
555
556 // If an additional action is required, return return and continue later
557 if (actionRequired)
558 return true;
559 // Otherwise, continue processing the queue
560 else
561 return executeOperationQueue();
562 }
563
executeOneOperation(FilterState operation)564 bool FilterManager::executeOneOperation(FilterState operation)
565 {
566 bool actionRequired = false;
567
568 switch (operation)
569 {
570 default:
571 break;
572 }
573
574 return actionRequired;
575 }
576
setFocusOffsetComplete()577 void FilterManager::setFocusOffsetComplete()
578 {
579 if (state == FILTER_OFFSET)
580 executeOperationQueue();
581 }
582
getFilterExposure(const QString & name) const583 double FilterManager::getFilterExposure(const QString &name) const
584 {
585 if (m_currentFilterLabels.empty() ||
586 m_currentFilterPosition < 1 ||
587 m_currentFilterPosition > m_currentFilterLabels.count())
588 return 1;
589
590 QString color = name;
591 if (color.isEmpty())
592 color = m_currentFilterLabels[m_currentFilterPosition - 1];
593 // Search for locked filter by filter color name
594 auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), [color](OAL::Filter * oneFilter)
595 {
596 return (oneFilter->color() == color);
597 });
598
599 if (pos != m_ActiveFilters.end())
600 return (*pos)->exposure();
601
602 // Default value
603 return 1;
604 }
605
setFilterExposure(int index,double exposure)606 bool FilterManager::setFilterExposure(int index, double exposure)
607 {
608 if (m_currentFilterLabels.empty())
609 return false;
610
611 QString color = m_currentFilterLabels[index];
612 for (int i = 0; i < m_ActiveFilters.count(); i++)
613 {
614 if (color == m_ActiveFilters[i]->color())
615 {
616 filterModel->setData(filterModel->index(i, 5), exposure);
617 filterModel->submitAll();
618 refreshFilterModel();
619 return true;
620 }
621 }
622
623 return false;
624 }
625
setFilterAbsoluteFocusPosition(int index,int absFocusPos)626 bool FilterManager::setFilterAbsoluteFocusPosition(int index, int absFocusPos)
627 {
628 if (index < 0 || index >= m_currentFilterLabels.count())
629 return false;
630
631 QString color = m_currentFilterLabels[index];
632 for (int i = 0; i < m_ActiveFilters.count(); i++)
633 {
634 if (color == m_ActiveFilters[i]->color())
635 {
636 filterModel->setData(filterModel->index(i, 9), absFocusPos);
637 filterModel->submitAll();
638 refreshFilterModel();
639 return true;
640 }
641 }
642
643 return false;
644 }
645
getFilterLock(const QString & name) const646 QString FilterManager::getFilterLock(const QString &name) const
647 {
648 // Search for locked filter by filter color name
649 auto pos = std::find_if(m_ActiveFilters.begin(), m_ActiveFilters.end(), [name](OAL::Filter * oneFilter)
650 {
651 return (oneFilter->color() == name);
652 });
653
654 if (pos != m_ActiveFilters.end())
655 return (*pos)->lockedFilter();
656
657 // Default value
658 return "--";
659 }
660
removeDevice(ISD::GDInterface * device)661 void FilterManager::removeDevice(ISD::GDInterface *device)
662 {
663 if (m_currentFilterDevice && (m_currentFilterDevice->getDeviceName() == device->getDeviceName()))
664 {
665 m_FilterNameProperty = nullptr;
666 m_FilterPositionProperty = nullptr;
667 m_currentFilterDevice = nullptr;
668 m_currentFilterLabels.clear();
669 m_currentFilterPosition = 0;
670 qDeleteAll(m_ActiveFilters);
671 m_ActiveFilters.clear();
672 delete(filterModel);
673 filterModel = nullptr;
674 }
675 }
676
setFocusStatus(Ekos::FocusState focusState)677 void FilterManager::setFocusStatus(Ekos::FocusState focusState)
678 {
679 if (state == FILTER_AUTOFOCUS)
680 {
681 switch (focusState)
682 {
683 case FOCUS_COMPLETE:
684 executeOperationQueue();
685 break;
686
687 case FOCUS_FAILED:
688 if (++retries == 3)
689 {
690 retries = 0;
691 emit failed();
692 return;
693 }
694 // Restart again
695 emit checkFocus(0.01);
696 break;
697
698 default:
699 break;
700
701 }
702 }
703 }
704
syncAbsoluteFocusPosition(int index)705 bool FilterManager::syncAbsoluteFocusPosition(int index)
706 {
707 if (index < 0 || index > m_ActiveFilters.count())
708 {
709 qCWarning(KSTARS_INDI) << __FUNCTION__ << "index" << index << "is out of bounds.";
710 return false;
711 }
712
713 int absFocusPos = m_ActiveFilters[index]->absoluteFocusPosition();
714
715 if (m_FocusAbsPosition == absFocusPos)
716 {
717 m_FocusAbsPositionPending = false;
718 return true;
719 }
720 else if (m_FocusAbsPositionPending == false)
721 {
722 m_FocusAbsPositionPending = true;
723 emit newFocusOffset(absFocusPos, true);
724 }
725
726 return false;
727 }
728
setFilterNames(const QStringList & newLabels)729 bool FilterManager::setFilterNames(const QStringList &newLabels)
730 {
731 if (m_currentFilterDevice == nullptr || m_currentFilterLabels.empty())
732 return false;
733
734 m_currentFilterDevice->runCommand(INDI_SET_FILTER_NAMES, const_cast<QStringList*>(&newLabels));
735 return true;
736 }
737
toJSON()738 QJsonObject FilterManager::toJSON()
739 {
740 if (!m_currentFilterDevice)
741 return QJsonObject();
742
743 QJsonArray filters;
744
745 for (int i = 0; i < filterModel->rowCount(); ++i)
746 {
747 QJsonObject oneFilter =
748 {
749 {"index", i},
750 {"label", filterModel->data(filterModel->index(i, FM_LABEL)).toString()},
751 {"exposure", filterModel->data(filterModel->index(i, FM_EXPOSURE)).toDouble()},
752 {"offset", filterModel->data(filterModel->index(i, FM_OFFSET)).toInt()},
753 {"autofocus", filterModel->data(filterModel->index(i, FM_AUTO_FOCUS)).toBool()},
754 {"lock", filterModel->data(filterModel->index(i, FM_LOCK_FILTER)).toString()},
755 {"flat", filterModel->data(filterModel->index(i, FM_FLAT_FOCUS)).toInt()},
756 };
757
758 filters.append(oneFilter);
759 }
760
761 QJsonObject data =
762 {
763 {"device", m_currentFilterDevice->getDeviceName()},
764 {"filters", filters}
765 };
766
767 return data;
768
769 }
770
setFilterData(const QJsonObject & settings)771 void FilterManager::setFilterData(const QJsonObject &settings)
772 {
773 if (!m_currentFilterDevice)
774 return;
775
776 if (settings["device"].toString() != m_currentFilterDevice->getDeviceName())
777 return;
778
779 QJsonArray filters = settings["filters"].toArray();
780 QStringList labels = getFilterLabels();
781
782 for (auto oneFilterRef : filters)
783 {
784 QJsonObject oneFilter = oneFilterRef.toObject();
785 int row = oneFilter["index"].toInt();
786
787 labels[row] = oneFilter["label"].toString();
788 filterModel->setData(filterModel->index(row, FM_LABEL), oneFilter["label"].toString());
789 filterModel->setData(filterModel->index(row, FM_EXPOSURE), oneFilter["exposure"].toDouble());
790 filterModel->setData(filterModel->index(row, FM_OFFSET), oneFilter["offset"].toInt());
791 filterModel->setData(filterModel->index(row, FM_AUTO_FOCUS), oneFilter["autofocus"].toBool());
792 filterModel->setData(filterModel->index(row, FM_LOCK_FILTER), oneFilter["lock"].toString());
793 filterModel->setData(filterModel->index(row, FM_FLAT_FOCUS), oneFilter["flat"].toInt());
794 }
795
796 setFilterNames(labels);
797 filterModel->submitAll();
798 refreshFilterModel();
799 }
800
801 }
802