Kstars

indielement.cpp
1/*
2 SPDX-FileCopyrightText: 2003 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5
6 2004-01-15 INDI element is the most basic unit of the INDI KStars client.
7*/
8
9#include "indielement.h"
10
11#include "indiproperty.h"
12#include "indigroup.h"
13#include "indidevice.h"
14
15#include "kstars.h"
16#include "ksnotification.h"
17
18#include <indicom.h>
19
20#include <KSqueezedTextLabel>
21#include <KLocalizedString>
22#include <KLed>
23#include <KMessageBox>
24
25#include <QButtonGroup>
26#include <QCheckBox>
27#include <QDir>
28#include <QDoubleSpinBox>
29#include <QFileDialog>
30#include <QLineEdit>
31#include <QPushButton>
32#include <QSlider>
33
34extern const char *libindi_strings_context;
35
36/*******************************************************************
37** INDI Element
38*******************************************************************/
39INDI_E::INDI_E(INDI_P *gProp, INDI::Property dProp) : QWidget(gProp), guiProp(gProp), dataProp(dProp)
40{
41 EHBox = new QHBoxLayout;
42 EHBox->setObjectName("Element Horizontal Layout");
43 EHBox->setContentsMargins(0, 0, 0, 0);
44}
45
46void INDI_E::buildSwitch(QButtonGroup *groupB, ISwitch *sw)
47{
48 name = sw->name;
49 label = i18nc(libindi_strings_context, sw->label);
50
51 if (label == "(I18N_EMPTY_MESSAGE)")
52 label = sw->label;
53
54 sp = sw;
55
56 if (label.isEmpty())
57 label = i18nc(libindi_strings_context, sw->name);
58
59 if (label == "(I18N_EMPTY_MESSAGE)")
60 label = sw->name;
61
62 if (groupB == nullptr)
63 return;
64
65 switch (guiProp->getGUIType())
66 {
67 case PG_BUTTONS:
68 push_w = new QPushButton(label, this);
69 push_w->setStyleSheet(":checked {background-color: darkGreen}");
70 push_w->setCheckable(true);
71 groupB->addButton(push_w);
72
73 syncSwitch();
74
75 guiProp->addWidget(push_w);
76
77 push_w->show();
78
79 if (dataProp.getPermission() == IP_RO)
80 push_w->setEnabled(sw->s == ISS_ON);
81
82 break;
83
84 case PG_RADIO:
85 check_w = new QCheckBox(label, this);
86 groupB->addButton(check_w);
87
88 syncSwitch();
89
90 guiProp->addWidget(check_w);
91
92 check_w->show();
93
94 if (dataProp.getPermission() == IP_RO)
95 check_w->setEnabled(sw->s == ISS_ON);
96
97 break;
98
99 default:
100 break;
101 }
102}
103
104void INDI_E::buildMenuItem(ISwitch *sw)
105{
106 buildSwitch(nullptr, sw);
107}
108
109void INDI_E::buildText(IText *itp)
110{
111 name = itp->name;
112 if (itp->label[0])
113 label = i18nc(libindi_strings_context, itp->label);
114
115 if (label == "(I18N_EMPTY_MESSAGE)")
116 label = itp->label;
117
118 tp = itp;
119
120 if (label.isEmpty())
121 label = i18nc(libindi_strings_context, itp->name);
122
123 if (label == "(I18N_EMPTY_MESSAGE)")
124 label = itp->name;
125
126 setupElementLabel();
127
128 if (tp->text[0])
129 text = i18nc(libindi_strings_context, tp->text);
130
131 switch (dataProp.getPermission())
132 {
133 case IP_RW:
134 setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio());
135 setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio());
136
137 break;
138
139 case IP_RO:
140 setupElementRead(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
141 break;
142
143 case IP_WO:
144 setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
145 break;
146 }
147
148 guiProp->addLayout(EHBox);
149}
150
151void INDI_E::setupElementLabel()
152{
154
155 label_w = new KSqueezedTextLabel(this);
156 label_w->setMinimumWidth(ELEMENT_LABEL_WIDTH * KStars::Instance()->devicePixelRatio());
157 label_w->setMaximumWidth(ELEMENT_LABEL_WIDTH * KStars::Instance()->devicePixelRatio());
158 label_w->setMargin(2);
159
160 palette.setColor(label_w->backgroundRole(), QColor(224, 232, 238));
161 label_w->setPalette(palette);
162 label_w->setTextFormat(Qt::RichText);
164 label_w->setWordWrap(true);
165
166 label_w->setStyleSheet("border: 1px solid grey; border-radius: 2px");
167
168 if (label.length() > MAX_LABEL_LENGTH)
169 {
170 QFont tempFont(label_w->font());
171 tempFont.setPointSize(tempFont.pointSize() - MED_INDI_FONT);
172 label_w->setFont(tempFont);
173 }
174
175 label_w->setText(label);
176
177 EHBox->addWidget(label_w);
178}
179
180void INDI_E::syncSwitch()
181{
182 if (sp == nullptr)
183 return;
184
185 QFont buttonFont;
186
187 switch (guiProp->getGUIType())
188 {
189 case PG_BUTTONS:
190 if (sp->s == ISS_ON)
191 {
192 push_w->setChecked(true);
193 //push_w->setDown(true);
194 buttonFont = push_w->font();
195 buttonFont.setBold(true);
196 push_w->setFont(buttonFont);
197
198 if (dataProp.getPermission() == IP_RO)
199 push_w->setEnabled(true);
200 }
201 else
202 {
203 push_w->setChecked(false);
204 //push_w->setDown(false);
205 buttonFont = push_w->font();
206 buttonFont.setBold(false);
207 push_w->setFont(buttonFont);
208
209 if (dataProp.getPermission() == IP_RO)
210 push_w->setEnabled(false);
211 }
212 break;
213
214 case PG_RADIO:
215 if (sp->s == ISS_ON)
216 {
217 check_w->setChecked(true);
218 if (dataProp.getPermission() == IP_RO)
219 check_w->setEnabled(true);
220 }
221 else
222 {
223 check_w->setChecked(false);
224 if (dataProp.getPermission() == IP_RO)
225 check_w->setEnabled(false);
226 }
227 break;
228
229 default:
230 break;
231 }
232}
233
234void INDI_E::syncText()
235{
236 if (tp == nullptr)
237 return;
238
239 if (dataProp.getPermission() != IP_WO)
240 {
241 if (tp->text[0])
242 read_w->setText(i18nc(libindi_strings_context, tp->text));
243 else
244 read_w->setText(tp->text);
245 }
246 // If write-only
247 else
248 {
249 write_w->setText(tp->text);
250 }
251}
252
253void INDI_E::syncNumber()
254{
255 char iNumber[MAXINDIFORMAT];
256 if (np == nullptr || read_w == nullptr)
257 return;
258
259 numberFormat(iNumber, np->format, np->value);
260
261 text = iNumber;
262
263 read_w->setText(text);
264
265 if (spin_w)
266 {
267 if (np->min != spin_w->minimum())
268 setMin();
269 if (np->max != spin_w->maximum())
270 setMax();
271 }
272}
273
274void INDI_E::updateTP()
275{
276 if (tp == nullptr)
277 return;
278
279 IUSaveText(tp, write_w->text().toHtmlEscaped().toLatin1().constData());
280}
281
282void INDI_E::updateNP()
283{
284 if (np == nullptr)
285 return;
286
287 if (write_w != nullptr)
288 {
289 if (write_w->text().isEmpty())
290 return;
291
292 f_scansexa(write_w->text().replace(',', '.').toLatin1().constData(), &(np->value));
293 return;
294 }
295
296 if (spin_w != nullptr)
297 np->value = spin_w->value();
298}
299
300void INDI_E::setText(const QString &newText)
301{
302 if (tp == nullptr)
303 return;
304
305 switch (dataProp.getPermission())
306 {
307 case IP_RO:
308 read_w->setText(newText);
309 break;
310
311 case IP_WO:
312 case IP_RW:
313 text = newText;
314 IUSaveText(tp, newText.toLatin1().constData());
315 read_w->setText(newText);
316 write_w->setText(newText);
317 break;
318 }
319}
320
321void INDI_E::setValue(double value)
322{
323 if (spin_w == nullptr || np == nullptr)
324 return;
325 // ensure that min <= value <= max
326 if (value < np->min || value > np->max)
327 return;
328
329 spin_w->setValue(value);
330 spinChanged(value);
331}
332
333void INDI_E::buildBLOB(IBLOB *ibp)
334{
335 name = ibp->name;
336 label = i18nc(libindi_strings_context, ibp->label);
337
338 if (label == "(I18N_EMPTY_MESSAGE)")
339 label = ibp->label;
340
341 bp = ibp;
342
343 if (label.isEmpty())
344 label = i18nc(libindi_strings_context, ibp->name);
345
346 if (label == "(I18N_EMPTY_MESSAGE)")
347 label = ibp->name;
348
349 setupElementLabel();
350
351 text = i18n("INDI DATA STREAM");
352
353 switch (dataProp.getPermission())
354 {
355 case IP_RW:
356 setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio());
357 setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio());
358 setupBrowseButton();
359 break;
360
361 case IP_RO:
362 setupElementRead(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
363 break;
364
365 case IP_WO:
366 setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
367 setupBrowseButton();
368 break;
369 }
370
371 guiProp->addLayout(EHBox);
372}
373
374void INDI_E::buildNumber(INumber *inp)
375{
376 bool scale = false;
377 char iNumber[MAXINDIFORMAT];
378
379 name = inp->name;
380 label = i18nc(libindi_strings_context, inp->label);
381
382 if (label == "(I18N_EMPTY_MESSAGE)")
383 label = inp->label;
384
385 np = inp;
386
387 if (label.isEmpty())
388 label = i18nc(libindi_strings_context, inp->name);
389
390 if (label == "(I18N_EMPTY_MESSAGE)")
391 label = inp->name;
392
393 numberFormat(iNumber, np->format, np->value);
394 text = iNumber;
395
396 setupElementLabel();
397
398 if (np->step != 0 && (np->max - np->min) / np->step <= 100)
399 scale = true;
400
401 switch (dataProp.getPermission())
402 {
403 case IP_RW:
404 setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio());
405 if (scale)
406 setupElementScale(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio());
407 else
408 setupElementWrite(ELEMENT_WRITE_WIDTH * KStars::Instance()->devicePixelRatio());
409
410 guiProp->addLayout(EHBox);
411 break;
412
413 case IP_RO:
414 setupElementRead(ELEMENT_READ_WIDTH * KStars::Instance()->devicePixelRatio());
415 guiProp->addLayout(EHBox);
416 break;
417
418 case IP_WO:
419 if (scale)
420 setupElementScale(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
421 else
422 setupElementWrite(ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio());
423
424 guiProp->addLayout(EHBox);
425
426 break;
427 }
428}
429
430void INDI_E::buildLight(ILight *ilp)
431{
432 name = ilp->name;
433 label = i18nc(libindi_strings_context, ilp->label);
434
435 if (label == "(I18N_EMPTY_MESSAGE)")
436 label = ilp->label;
437
438 lp = ilp;
439
440 if (label.isEmpty())
441 label = i18nc(libindi_strings_context, ilp->name);
442
443 if (label == "(I18N_EMPTY_MESSAGE)")
444 label = ilp->name;
445
446 led_w = new KLed(this);
447 led_w->setMaximumSize(16, 16);
448 led_w->setLook(KLed::Sunken);
449
450 syncLight();
451
452 EHBox->addWidget(led_w);
453
454 setupElementLabel();
455
456 guiProp->addLayout(EHBox);
457}
458
459void INDI_E::syncLight()
460{
461 if (lp == nullptr)
462 return;
463
464 switch (lp->s)
465 {
466 case IPS_IDLE:
467 led_w->setColor(Qt::gray);
468 break;
469
470 case IPS_OK:
471 led_w->setColor(Qt::green);
472 break;
473
474 case IPS_BUSY:
475 led_w->setColor(Qt::yellow);
476 break;
477
478 case IPS_ALERT:
479 led_w->setColor(Qt::red);
480 break;
481 }
482}
483
484void INDI_E::setupElementScale(int length)
485{
486 if (np == nullptr)
487 return;
488
489 int steps = static_cast<int>((np->max - np->min) / np->step);
490 spin_w = new QDoubleSpinBox(this);
491 spin_w->setRange(np->min, np->max);
492 spin_w->setSingleStep(np->step);
493 spin_w->setValue(np->value);
494 spin_w->setDecimals(3);
495
496 slider_w = new QSlider(Qt::Horizontal, this);
497 slider_w->setRange(0, steps);
498 slider_w->setPageStep(1);
499 slider_w->setValue(static_cast<int>((np->value - np->min) / np->step));
500
501 connect(spin_w, SIGNAL(valueChanged(double)), this, SLOT(spinChanged(double)));
502 connect(slider_w, SIGNAL(sliderMoved(int)), this, SLOT(sliderChanged(int)));
503
504 if (length == ELEMENT_FULL_WIDTH * KStars::Instance()->devicePixelRatio())
506 else
508
509 spin_w->setMinimumWidth(static_cast<int>(length * 0.45));
510 slider_w->setMinimumWidth(static_cast<int>(length * 0.55));
511
512 EHBox->addWidget(slider_w);
513 EHBox->addWidget(spin_w);
514}
515
516void INDI_E::spinChanged(double value)
517{
518 int slider_value = static_cast<int>((value - np->min) / np->step);
519 slider_w->setValue(slider_value);
520}
521
522void INDI_E::sliderChanged(int value)
523{
524 double spin_value = (value * np->step) + np->min;
525 spin_w->setValue(spin_value);
526}
527
528void INDI_E::setMin()
529{
530 if (spin_w)
531 {
532 spin_w->setMinimum(np->min);
533 spin_w->setValue(np->value);
534 }
535 if (slider_w)
536 {
537 slider_w->setMaximum(static_cast<int>((np->max - np->min) / np->step));
538 slider_w->setMinimum(0);
539 slider_w->setPageStep(1);
540 slider_w->setValue(static_cast<int>((np->value - np->min) / np->step));
541 }
542}
543
544void INDI_E::setMax()
545{
546 if (spin_w)
547 {
548 spin_w->setMaximum(np->max);
549 spin_w->setValue(np->value);
550 }
551 if (slider_w)
552 {
553 slider_w->setMaximum(static_cast<int>((np->max - np->min) / np->step));
554 slider_w->setMinimum(0);
555 slider_w->setPageStep(1);
556 slider_w->setValue(static_cast<int>((np->value - np->min) / np->step));
557 }
558}
559
560void INDI_E::setupElementWrite(int length)
561{
562 write_w = new QLineEdit(this);
564 write_w->setMinimumWidth(length);
565 write_w->setMaximumWidth(length);
566
567 write_w->setText(text);
568
569 QObject::connect(write_w, SIGNAL(returnPressed()), guiProp, SLOT(sendText()));
570 EHBox->addWidget(write_w);
571}
572
573void INDI_E::setupElementRead(int length)
574{
575 read_w = new QLineEdit(this);
576 read_w->setMinimumWidth(length);
578 read_w->setCursorPosition(0);
580 read_w->setReadOnly(true);
581 read_w->setText(text);
582
583 EHBox->addWidget(read_w);
584}
585
586void INDI_E::setupBrowseButton()
587{
588 browse_w = new QPushButton(this);
589 browse_w->setIcon(QIcon::fromTheme("document-open"));
591 browse_w->setMinimumWidth(MIN_SET_WIDTH * KStars::Instance()->devicePixelRatio());
592 browse_w->setMaximumWidth(MAX_SET_WIDTH * KStars::Instance()->devicePixelRatio());
593
594 EHBox->addWidget(browse_w);
595 QObject::connect(browse_w, SIGNAL(clicked()), this, SLOT(browseBlob()));
596}
597
598void INDI_E::browseBlob()
599{
600 QFile fp;
601 QString filename;
602 QString format;
603 int pos = 0;
604 QUrl currentURL;
605
606 currentURL = QFileDialog::getOpenFileUrl();
607
608 // if user presses cancel
609 if (currentURL.isEmpty())
610 return;
611
612 if (currentURL.isValid())
613 write_w->setText(currentURL.toLocalFile());
614
615 fp.setFileName(currentURL.toLocalFile());
616
617 if ((pos = filename.lastIndexOf(".")) != -1)
618 format = filename.mid(pos, filename.length());
619
620 //qDebug() << Q_FUNC_INFO << "Filename is " << fp.fileName() << Qt::endl;
621
622 if (!fp.open(QIODevice::ReadOnly))
623 {
624 KSNotification::error( i18n("Cannot open file %1 for reading", filename));
625 return;
626 }
627
628 bp->bloblen = bp->size = fp.size();
629
630 bp->blob = static_cast<uint8_t *>(realloc(bp->blob, bp->size));
631 if (bp->blob == nullptr)
632 {
633 KSNotification::error( i18n("Not enough memory for file %1", filename));
634 fp.close();
635 return;
636 }
637
638 memcpy(bp->blob, fp.readAll().constData(), bp->size);
639
640 blobDirty = true;
641}
642
643QString INDI_E::getWriteField()
644{
645 if (write_w)
646 return write_w->text();
647 else
648 return nullptr;
649}
650
651QString INDI_E::getReadField()
652{
653 if (read_w)
654 return read_w->text();
655 else
656 return nullptr;
657}
INDI_P represents a single INDI property (Switch, Text, Number, Light, or BLOB).
void setColor(const QColor &color)
void setLook(Look look)
virtual void setAlignment(Qt::Alignment)
void setMargin(int margin)
void setText(const QString &text)
static KStars * Instance()
Definition kstars.h:121
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void setCheckable(bool)
void setChecked(bool)
void setIcon(const QIcon &icon)
void setMaximum(int)
void setMinimum(int)
void setPageStep(int)
void setRange(int min, int max)
void setValue(int)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void addButton(QAbstractButton *button, int id)
const char * constData() const const
void setDecimals(int prec)
void setRange(double minimum, double maximum)
void setSingleStep(double val)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual qint64 size() const const override
virtual void close() override
QUrl getOpenFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
void setBold(bool enable)
QIcon fromTheme(const QString &name)
QByteArray readAll()
void setTextFormat(Qt::TextFormat)
void setWordWrap(bool on)
void setAlignment(Qt::Alignment flag)
void setCursorPosition(int)
void setReadOnly(bool)
void setText(const QString &)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void setObjectName(QAnyStringView name)
qreal devicePixelRatio() const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QByteArray toLatin1() const const
AlignCenter
Horizontal
RichText
bool isEmpty() const const
bool isValid() const const
QString toLocalFile() const const
QPalette::ColorRole backgroundRole() const const
void setEnabled(bool)
void setFocusPolicy(Qt::FocusPolicy policy)
void setMaximumSize(const QSize &)
void setMaximumWidth(int maxw)
void setMinimumWidth(int minw)
void show()
void setSizePolicy(QSizePolicy)
void setStyleSheet(const QString &styleSheet)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:16:41 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.