3 Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com)
5 This application is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
13 #include "indiproperty.h"
14 #include "indigroup.h"
15 #include "indidevice.h"
16 #include "devicemanager.h"
19 #include "indi/indicom.h"
22 #include "timedialog.h"
24 #include "indi/base64.h"
25 #include "indi/indicom.h"
27 #include <kpopupmenu.h>
28 #include <klineedit.h>
31 #include <kcombobox.h>
32 #include <kpushbutton.h>
33 #include <knuminput.h>
35 #include <kmessagebox.h>
37 #include <qbuttongroup.h>
38 #include <qcheckbox.h>
43 #include <qdatastream.h>
48 /*******************************************************************
49 ** INDI Property: contains widgets, labels, and their status
50 *******************************************************************/
51 INDI_P::INDI_P(INDI_G
*parentGroup
, QString inName
)
57 el
.setAutoDelete(true);
61 indistd
= new INDIStdProperty(this, pg
->dp
->parent
->ksw
, pg
->dp
->stdDev
);
63 PHBox
= new QHBoxLayout(0, 0, KDialogBase::spacingHint());
64 PVBox
= new QVBoxLayout(0, 0, KDialogBase::spacingHint());
68 assosiatedPopup
= NULL
;
72 /* INDI property desstructor, makes sure everything is "gone" right */
75 pg
->propertyLayout
->removeItem(PHBox
);
83 bool INDI_P::isOn(QString component
)
88 lp
= findElement(component
);
93 if (lp
->check_w
&& lp
->check_w
->isChecked())
95 if (lp
->push_w
&& lp
->push_w
->isDown())
101 INDI_E
* INDI_P::findElement(QString elementName
)
103 INDI_E
*element
= NULL
;
105 for (element
= el
.first(); element
!= NULL
; element
= el
.next())
106 if (element
->name
== elementName
|| element
->label
== elementName
)
112 void INDI_P::drawLt(PState lstate
)
116 /* set state light */
120 light
->setColor(Qt::gray
);
124 light
->setColor(Qt::green
);
126 disconnect( this, SIGNAL(okState()), 0, 0 );
130 light
->setColor(Qt::yellow
);
134 light
->setColor(Qt::red
);
144 void INDI_P::newText()
148 for (lp
= el
.first(); lp
!= NULL
; lp
= el
.next())
152 lp
->targetValue
= lp
->spin_w
->value();
153 /* PG_NUMERIC or PG_TEXT */
159 if (lp
->write_w
->text().isEmpty())
160 lp
->text
= lp
->read_w
->text();
162 lp
->text
= lp
->write_w
->text();
169 lp
->text
= lp
->write_w
->text();
173 if (guitype
== PG_NUMERIC
)
175 f_scansexa(lp
->text
.ascii(), &(lp
->targetValue
));
176 if ((lp
->targetValue
> lp
->max
|| lp
->targetValue
< lp
->min
))
178 KMessageBox::error(0, i18n("Invalid range. Valid values range from %1 to %2").arg(lp
->min
).arg(lp
->max
));
189 /* perform any std functions */
192 if (guitype
== PG_TEXT
)
193 pg
->dp
->parentMgr
->sendNewText(this);
194 else if (guitype
== PG_NUMERIC
)
195 pg
->dp
->parentMgr
->sendNewNumber(this);
199 void INDI_P::convertSwitch(int id
)
205 if (assosiatedPopup
== NULL
)
208 //kdDebug() << "Name: " << name << " ID: " << id << endl;
209 /* Special case is EXPOSE_DURATION, not a switch */
210 if (stdID
== EXPOSE_DURATION
&& assosiatedPopup
->text(id
) == label
)
216 lp
= findElement(assosiatedPopup
->text(id
));
221 for (uint i
=0; i
< el
.count(); i
++)
223 if (el
.at(i
)->label
== assosiatedPopup
->text(id
))
230 if (indistd
->convertSwitch(switchIndex
, lp
))
232 else if (lp
->state
== PS_OFF
)
233 newSwitch(switchIndex
);
237 void INDI_P::newSwitch(int id
)
248 if (lp
->state
== PS_ON
)
251 for (unsigned int i
=0; i
< el
.count(); i
++)
252 el
.at(i
)->state
= PS_OFF
;
258 for (unsigned int i
=0; i
< el
.count(); i
++)
260 if (i
== (unsigned int) id
) continue;
262 el
.at(i
)->push_w
->setDown(false);
263 buttonFont
= el
.at(i
)->push_w
->font();
264 buttonFont
.setBold(FALSE
);
265 el
.at(i
)->push_w
->setFont(buttonFont
);
266 el
.at(i
)->state
= PS_OFF
;
269 lp
->push_w
->setDown(true);
270 buttonFont
= lp
->push_w
->font();
271 buttonFont
.setBold(TRUE
);
272 lp
->push_w
->setFont(buttonFont
);
278 lp
->state
= lp
->state
== PS_ON
? PS_OFF
: PS_ON
;
279 lp
->check_w
->setChecked(lp
->state
== PS_ON
);
291 if (indistd
->newSwitch(id
, lp
))
294 pg
->dp
->parentMgr
->sendNewSwitch (this, id
);
299 /* Display file dialog to select and upload a file to the client
300 Loop through blobs and send each accordingly
302 void INDI_P::newBlob()
307 QDataStream binaryStream
;
308 int data64_size
=0, pos
=0;
310 unsigned char *data
, *data64
;
311 bool sending (false);
314 for (unsigned int i
=0; i
< el
.count(); i
++)
316 filename
= el
.at(i
)->write_w
->text();
317 if (filename
.isEmpty())
323 fp
.setName(filename
);
325 if ( (pos
= filename
.findRev(".")) != -1)
326 format
= filename
.mid (pos
, filename
.length());
328 if (!fp
.open(IO_ReadOnly
))
330 KMessageBox::error(0, i18n("Cannot open file %1 for reading").arg(filename
));
335 binaryStream
.setDevice(&fp
);
337 data_file
= new char[fp
.size()];
338 if (data_file
== NULL
)
340 KMessageBox::error(0, i18n("Not enough memory to load %1").arg(filename
));
346 binaryStream
.readRawBytes(data_file
, fp
.size());
347 data
= (unsigned char *) data_file
;
349 data64
= new unsigned char[4*fp
.size()/3+4];
352 KMessageBox::error(0, i18n("Not enough memory to convert file %1 to base64").arg(filename
));
358 data64_size
= to64frombits (data64
, data
, fp
.size());
362 if (sending
== false)
365 pg
->dp
->parentMgr
->startBlob (pg
->dp
->name
, name
, QString(timestamp()));
368 pg
->dp
->parentMgr
->sendOneBlob(el
.at(i
)->name
, data64_size
, format
, data64
);
375 /* Nothing been made, no changes */
376 if (!sending
&& !valid
)
379 pg
->dp
->parentMgr
->finishBlob();
390 /* build widgets for property pp using info in root.
392 void INDI_P::addGUI (XMLEle
*root
)
397 /* add to GUI group */
398 light
= new KLed (pg
->propertyContainer
);
399 light
->setMaximumSize(16,16);
400 light
->setLook(KLed::Sunken
);
401 //light->setShape(KLed::Rectangular);
404 /* #1 First widegt is the LED status indicator */
405 PHBox
->addWidget(light
);
407 /* #2 add label for prompt */
408 prompt
= findAtt(root
, "label", errmsg
);
413 label
= valuXMLAtt(prompt
);
415 // use property name if label is empty
419 label_w
= new QLabel(label
, pg
->propertyContainer
);
422 label_w
= new QLabel(label
, pg
->propertyContainer
);
424 label_w
->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType
)0, (QSizePolicy::SizeType
)5, 0, 0, label_w
->sizePolicy().hasHeightForWidth() ) );
425 label_w
->setFrameShape( QLabel::GroupBoxPanel
);
426 label_w
->setMinimumWidth(PROPERTY_LABEL_WIDTH
);
427 label_w
->setMaximumWidth(PROPERTY_LABEL_WIDTH
);
428 label_w
->setTextFormat( QLabel::RichText
);
429 label_w
->setAlignment( int( QLabel::WordBreak
| QLabel::AlignVCenter
| QLabel::AlignHCenter
) );
431 PHBox
->addWidget(label_w
);
436 /* #3 Add the Vertical layout thay may contain several elements */
437 PHBox
->addLayout(PVBox
);
440 int INDI_P::buildTextGUI(XMLEle
*root
, char errmsg
[])
445 QString textName
, textLabel
;
448 for (text
= nextXMLEle (root
, 1); text
!= NULL
; text
= nextXMLEle (root
, 0))
450 if (strcmp (tagXMLEle(text
), "defText"))
453 ap
= findXMLAtt(text
, "name");
456 kdDebug() << "Error: unable to find attribute 'name' for property " << name
<< endl
;
460 textName
= valuXMLAtt(ap
);
461 /*char * tname = strcpy(new char[ strlen(valuXMLAtt(ap)) + 1], valuXMLAtt(ap));*/
463 ap
= findXMLAtt(text
, "label");
467 kdDebug() << "Error: unable to find attribute 'label' for property " << name
<< endl
;
471 textLabel
= valuXMLAtt(ap
);
472 //char * tlabel = strcpy(new char[ strlen(valuXMLAtt(ap)) + 1], valuXMLAtt(ap));
474 if (textLabel
.isEmpty())
475 textLabel
= textName
;
476 //tlabel = strcpy (new char [ strlen(tname) + 1], tname);
478 lp
= new INDI_E(this, textName
, textLabel
);
480 lp
->buildTextGUI(QString(pcdataXMLEle(text
)));
489 // INDI STD, but we use our own controls
492 setupSetButton("Time");
493 QObject::connect(set_w
, SIGNAL(clicked()), indistd
, SLOT(newTime()));
497 setupSetButton("Set");
498 QObject::connect(set_w
, SIGNAL(clicked()), this, SLOT(newText()));
505 int INDI_P::buildNumberGUI (XMLEle
*root
, char errmsg
[])
508 double min
=0, max
=0, step
=0;
512 QString numberName
, numberLabel
;
515 for (number
= nextXMLEle (root
, 1); number
!= NULL
; number
= nextXMLEle (root
, 0))
517 if (strcmp (tagXMLEle(number
), "defNumber"))
520 ap
= findXMLAtt(number
, "name");
523 kdDebug() << "Error: unable to find attribute 'name' for property " << name
<< endl
;
527 numberName
= valuXMLAtt(ap
);
529 ap
= findXMLAtt(number
, "label");
533 kdDebug() << "Error: unable to find attribute 'label' for property " << name
<< endl
;
537 numberLabel
= valuXMLAtt(ap
);
539 if (numberLabel
.isEmpty())
540 numberLabel
= numberName
;
542 lp
= new INDI_E(this, numberName
, numberLabel
);
544 ap
= findXMLAtt (number
, "min");
546 min
= atof(valuXMLAtt(ap
));
547 ap
= findXMLAtt (number
, "max");
549 max
= atof(valuXMLAtt(ap
));
550 ap
= findXMLAtt (number
, "step");
552 step
= atof(valuXMLAtt(ap
));
553 ap
= findXMLAtt (number
, "format");
555 strcpy(format
,valuXMLAtt(ap
));
557 lp
->initNumberValues(min
, max
, step
, format
);
559 lp
->buildNumberGUI(atof(pcdataXMLEle(number
)));
568 if (name
== "EXPOSE_DURATION")
569 setupSetButton("Start");
571 setupSetButton("Set");
573 QObject::connect(set_w
, SIGNAL(clicked()), this, SLOT(newText()));
579 void INDI_P::setupSetButton(QString caption
)
581 set_w
= new QPushButton(caption
, pg
->propertyContainer
);
582 set_w
->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType
)5, (QSizePolicy::SizeType
)0, 0, 0, set_w
->sizePolicy().hasHeightForWidth() ) );
583 set_w
->setMinimumWidth( MIN_SET_WIDTH
);
584 set_w
->setMaximumWidth( MAX_SET_WIDTH
);
586 PHBox
->addWidget(set_w
);
589 int INDI_P::buildMenuGUI(XMLEle
*root
, char errmsg
[])
594 QString switchName
, switchLabel
;
595 QStringList menuOptions
;
600 // build pulldown menu first
601 // create each switch.
602 // N.B. can only be one in On state.
603 for (sep
= nextXMLEle (root
, 1), i
=0; sep
!= NULL
; sep
= nextXMLEle (root
, 0), i
++)
605 /* look for switch tage */
606 if (strcmp (tagXMLEle(sep
), "defSwitch"))
610 ap
= findAtt (sep
, "name", errmsg
);
614 switchName
= valuXMLAtt(ap
);
617 ap
= findAtt (sep
, "label", errmsg
);
621 switchLabel
= valuXMLAtt(ap
);
623 if (switchLabel
.isEmpty())
624 switchLabel
= switchName
;
626 lp
= new INDI_E(this, switchName
, switchLabel
);
628 if (pg
->dp
->crackSwitchState (pcdataXMLEle(sep
), &(lp
->state
)) < 0)
630 snprintf (errmsg
, ERRMSG_SIZE
, "INDI: <%.64s> unknown state %.64s for %.64s %.64s %.64s",
631 tagXMLEle(root
), valuXMLAtt(ap
), name
.ascii(), lp
->name
.ascii(), name
.ascii());
635 menuOptions
.append(switchLabel
);
637 if (lp
->state
== PS_ON
)
641 snprintf (errmsg
, ERRMSG_SIZE
, "INDI: <%.64s> %.64s %.64s has multiple On switches",
642 tagXMLEle(root
), name
.ascii(), lp
->name
.ascii());
652 om_w
= new KComboBox(pg
->propertyContainer
);
653 om_w
->insertStringList(menuOptions
);
654 om_w
->setCurrentItem(onItem
);
656 HorSpacer
= new QSpacerItem( 20, 20, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
658 PHBox
->addWidget(om_w
);
659 PHBox
->addItem(HorSpacer
);
661 QObject::connect(om_w
, SIGNAL(activated(int)), this, SLOT(newSwitch(int)));
666 int INDI_P::buildSwitchesGUI(XMLEle
*root
, char errmsg
[])
674 QString switchName
, switchLabel
;
677 groupB
= new QButtonGroup(0);
678 groupB
->setFrameShape(QFrame::NoFrame
);
679 if (guitype
== PG_BUTTONS
)
680 groupB
->setExclusive(true);
682 QObject::connect(groupB
, SIGNAL(clicked(int)), this, SLOT(newSwitch(int)));
684 for (sep
= nextXMLEle (root
, 1), j
=-1; sep
!= NULL
; sep
= nextXMLEle (root
, 0))
686 /* look for switch tage */
687 if (strcmp (tagXMLEle(sep
), "defSwitch"))
691 ap
= findAtt (sep
, "name", errmsg
);
695 switchName
= valuXMLAtt(ap
);
698 ap
= findAtt (sep
, "label", errmsg
);
702 switchLabel
= valuXMLAtt(ap
);
704 if (switchLabel
.isEmpty())
705 switchLabel
= switchName
;
707 lp
= new INDI_E(this, switchName
, switchLabel
);
709 if (pg
->dp
->crackSwitchState (pcdataXMLEle(sep
), &(lp
->state
)) < 0)
711 snprintf (errmsg
, ERRMSG_SIZE
, "INDI: <%.64s> unknown state %.64s for %.64s %.64s %.64s",
712 tagXMLEle(root
), valuXMLAtt(ap
), name
.ascii(), name
.ascii(), lp
->name
.ascii());
722 button
= new KPushButton(switchLabel
, pg
->propertyContainer
);
723 button
->setMinimumWidth(BUTTON_WIDTH
);
724 button
->setMaximumWidth(BUTTON_WIDTH
);
725 groupB
->insert(button
, j
);
727 if (lp
->state
== PS_ON
)
729 button
->setDown(true);
730 buttonFont
= button
->font();
731 buttonFont
.setBold(TRUE
);
732 button
->setFont(buttonFont
);
737 PHBox
->addWidget(button
);
739 // FIXME: do we need this?
745 checkbox
= new QCheckBox(switchLabel
, pg
->propertyContainer
);
746 checkbox
->setMinimumWidth(BUTTON_WIDTH
);
747 checkbox
->setMaximumWidth(BUTTON_WIDTH
);
748 groupB
->insert(checkbox
, j
);
750 if (lp
->state
== PS_ON
)
751 checkbox
->setChecked(true);
753 lp
->check_w
= checkbox
;
755 PHBox
->addWidget(checkbox
);
772 HorSpacer
= new QSpacerItem( 20, 20, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
774 PHBox
->addItem(HorSpacer
);
779 int INDI_P::buildLightsGUI(XMLEle
*root
, char errmsg
[])
784 QString sname
, slabel
;
786 for (lep
= nextXMLEle (root
, 1); lep
!= NULL
; lep
= nextXMLEle (root
, 0))
788 if (strcmp (tagXMLEle(lep
), "defLight"))
792 ap
= findAtt (lep
, "name", errmsg
);
793 if (!ap
) return (-1);
795 sname
= valuXMLAtt(ap
);
798 ap
= findAtt (lep
, "label", errmsg
);
799 if (!ap
) return (-1);
801 slabel
= valuXMLAtt(ap
);
802 if (slabel
.isEmpty())
805 lp
= new INDI_E(this, sname
, slabel
);
807 if (pg
->dp
->crackLightState (pcdataXMLEle(lep
), &lp
->state
) < 0)
809 snprintf (errmsg
, ERRMSG_SIZE
, "INDI: <%.64s> unknown state %.64s for %.64s %.64s %.64s",
810 tagXMLEle(root
), valuXMLAtt(ap
), pg
->dp
->name
.ascii(), name
.ascii(), sname
.ascii());
818 HorSpacer
= new QSpacerItem( 20, 20, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
820 PHBox
->addItem(HorSpacer
);
826 * Return 0 if okay, -1 if error */
827 int INDI_P::buildBLOBGUI(XMLEle
*root
, char errmsg
[])
832 QString blobName
, blobLabel
;
835 for (blob
= nextXMLEle (root
, 1); blob
!= NULL
; blob
= nextXMLEle (root
, 0))
837 if (strcmp (tagXMLEle(blob
), "defBLOB"))
840 ap
= findXMLAtt(blob
, "name");
843 kdDebug() << "Error: unable to find attribute 'name' for property " << name
<< endl
;
847 blobName
= valuXMLAtt(ap
);
848 /*char * tname = strcpy(new char[ strlen(valuXMLAtt(ap)) + 1], valuXMLAtt(ap));*/
850 ap
= findXMLAtt(blob
, "label");
854 kdDebug() << "Error: unable to find attribute 'label' for property " << name
<< endl
;
858 blobLabel
= valuXMLAtt(ap
);
860 if (blobLabel
.isEmpty())
861 blobLabel
= blobName
;
863 lp
= new INDI_E(this, blobName
, blobLabel
);
874 setupSetButton(i18n("Upload"));
875 QObject::connect(set_w
, SIGNAL(clicked()), this, SLOT(newBlob()));
881 void INDI_P::activateSwitch(QString name
)
886 for (element
= el
.first(); element
!= NULL
; element
= el
.next())
888 if (element
->name
== name
&& element
->push_w
)
898 #include "indiproperty.moc"