diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2 (patch) | |
tree | d3bb9f5d25a2dc09ca81adecf39621d871534297 /kstars/kstars/indidevice.cpp | |
download | tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.tar.gz tdeedu-ce599e4f9f94b4eb00c1b5edb85bce5431ab3df2.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdeedu@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kstars/kstars/indidevice.cpp')
-rw-r--r-- | kstars/kstars/indidevice.cpp | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/kstars/kstars/indidevice.cpp b/kstars/kstars/indidevice.cpp new file mode 100644 index 00000000..44e77bb0 --- /dev/null +++ b/kstars/kstars/indidevice.cpp @@ -0,0 +1,999 @@ +/* INDI frontend for KStars + Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) + Elwood C. Downey. + + This application is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + JM Changelog: + 2003-04-28 Used indimenu.c as a template. C --> C++, Xm --> KDE/Qt + 2003-05-01 Added tab for devices and a group feature + 2003-05-02 Added scrolling area. Most things are rewritten + 2003-05-05 Device/Group seperation + 2003-05-29 Replaced raw INDI time with KStars's timedialog + 2003-08-02 Upgrading to INDI v 1.11 + 2003-08-09 Initial support for non-sidereal tracking + 2004-01-15 redesigning the GUI to support INDI v1.2 and fix previous GUI bugs + and problems. The new GUI can easily incoperate extensions to the INDI + protocol as required. + + */ + +#include "indiproperty.h" +#include "indigroup.h" +#include "indidevice.h" +#include "devicemanager.h" +#include "indimenu.h" +#include "indidriver.h" +#include "indistd.h" +#include "indi/indicom.h" +#include "kstars.h" +#include "skyobject.h" +#include "timedialog.h" +#include "geolocation.h" +#include "indi/base64.h" + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <stdlib.h> +#include <unistd.h> +#include <termios.h> +#include <zlib.h> + +#include <qlineedit.h> +#include <qtextedit.h> +#include <qframe.h> +#include <qtabwidget.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qtooltip.h> +#include <qwhatsthis.h> +#include <qbuttongroup.h> +#include <qscrollview.h> +#include <qsocketnotifier.h> +#include <qvbox.h> +#include <qdatetime.h> +#include <qtable.h> +#include <qstring.h> +#include <qptrlist.h> + +#include <kled.h> +#include <klineedit.h> +#include <kpushbutton.h> +#include <kapplication.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <klistview.h> +#include <kdebug.h> +#include <kcombobox.h> +#include <knuminput.h> +#include <kdialogbase.h> +#include <kstatusbar.h> +#include <kpopupmenu.h> + +#define NINDI_STD 26 +/* INDI standard property used across all clients to enable interoperability. */ + +const char * indi_std[NINDI_STD] = + {"CONNECTION", "DEVICE_PORT", "TIME", "SDTIME", "GEOGRAPHIC_COORD", "EQUATORIAL_COORD", "EQUATORIAL_EOD_COORD", "HORIZONTAL_COORD", "ABORT_MOTION", "ON_COORD_SET", "SOLAR_SYSTEM", "MOVEMENT", "PARK", "CCD_EXPOSE_DURATION", "CCD_TEMPERATURE", "CCD_FRAME", "CCD_FRAME_TYPE", "CCD_BINNING", "CCD_INFO", "CCDPREVIEW_STREAM", "CCDPREVIEW_CTRL", "VIDEO_STREAM", "FOCUS_SPEED", "FOCUS_MOTION", "FOCUS_TIMER", "FILTER_SLOT" }; + +/******************************************************************* +** INDI Device: The work-horse. Responsible for handling its +** child properties and managing signal and changes. +*******************************************************************/ +INDI_D::INDI_D(INDIMenu *menuParent, DeviceManager *parentManager, QString inName, QString inLabel) +{ + name = inName; + label = inLabel; + parent = menuParent; + parentMgr = parentManager; + + gl.setAutoDelete(true); + + deviceVBox = menuParent->addVBoxPage(inLabel); + groupContainer = new QTabWidget(deviceVBox); + + msgST_w = new QTextEdit(deviceVBox); + msgST_w->setReadOnly(true); + msgST_w->setMaximumHeight(100); + + dataBuffer = (unsigned char *) malloc (1); + + stdDev = new INDIStdDevice(this, parent->ksw); + + curGroup = NULL; + + INDIStdSupport = false; + +} + +INDI_D::~INDI_D() +{ + gl.clear(); + delete(deviceVBox); + delete (stdDev); + free (dataBuffer); + dataBuffer = NULL; + deviceVBox = NULL; + stdDev = NULL; +} + +void INDI_D::registerProperty(INDI_P *pp) +{ + + if (isINDIStd(pp)) + pp->pg->dp->INDIStdSupport = true; + + stdDev->registerProperty(pp); + +} + +bool INDI_D::isINDIStd(INDI_P *pp) +{ + for (uint i=0; i < NINDI_STD; i++) + if (!strcmp(pp->name.ascii(), indi_std[i])) + { + pp->stdID = i; + return true; + } + + return false; +} + +/* Remove a property from a group, if there are no more properties + * left in the group, then delete the group as well */ +int INDI_D::removeProperty(INDI_P *pp) +{ + for (unsigned int i=0; i < gl.count(); i++) + if (gl.at(i)->removeProperty(pp)) + { + if (gl.at(i)->pl.count() == 0) + gl.remove(i); + return 0; + } + + + kdDebug() << "INDI: Device " << name << " has no property named " << pp->name << endl; + return (-1); +} + +/* implement any <set???> received from the device. + * return 0 if ok, else -1 with reason in errmsg[] + */ +int INDI_D::setAnyCmd (XMLEle *root, char errmsg[]) +{ + XMLAtt *ap; + INDI_P *pp; + + ap = findAtt (root, "name", errmsg); + if (!ap) + return (-1); + + pp = findProp (valuXMLAtt(ap)); + if (!pp) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.32s> device %.32s has no property named %.64s", + tagXMLEle(root), name.ascii(), valuXMLAtt(ap)); + return (-1); + } + + parentMgr->checkMsg (root, this); + + return (setValue (pp, root, errmsg)); +} + +/* set the given GUI property according to the XML command. + * return 0 if ok else -1 with reason in errmsg + */ +int INDI_D::setValue (INDI_P *pp, XMLEle *root, char errmsg[]) +{ + XMLAtt *ap; + + /* set overall property state, if any */ + ap = findXMLAtt (root, "state"); + if (ap) + { + if (crackLightState (valuXMLAtt(ap), &pp->state) == 0) + pp->drawLt (pp->state); + else + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> bogus state %.64s for %.64s %.64s", + tagXMLEle(root), valuXMLAtt(ap), name.ascii(), pp->name.ascii()); + return (-1); + } + } + + /* allow changing the timeout */ + ap = findXMLAtt (root, "timeout"); + if (ap) + pp->timeout = atof(valuXMLAtt(ap)); + + /* process specific GUI features */ + switch (pp->guitype) + { + case PG_NONE: + break; + + case PG_NUMERIC: /* FALLTHRU */ + case PG_TEXT: + return (setTextValue (pp, root, errmsg)); + break; + + case PG_BUTTONS: + case PG_LIGHTS: + case PG_RADIO: + case PG_MENU: + return (setLabelState (pp, root, errmsg)); + break; + + case PG_BLOB: + return (setBLOB(pp, root, errmsg)); + break; + + default: + break; + } + + return (0); +} + + +/* set the given TEXT or NUMERIC property from the given element. + * root should have <text> or <number> child. + * return 0 if ok else -1 with reason in errmsg + */ +int INDI_D::setTextValue (INDI_P *pp, XMLEle *root, char errmsg[]) +{ + XMLEle *ep; + XMLAtt *ap; + INDI_E *lp; + QString elementName; + char iNumber[32]; + double min, max; + + for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) + { + if (strcmp (tagXMLEle(ep), "oneText") && strcmp(tagXMLEle(ep), "oneNumber")) + continue; + + ap = findXMLAtt(ep, "name"); + if (!ap) + { + kdDebug() << "Error: unable to find attribute 'name' for property " << pp->name << endl; + return (-1); + } + + elementName = valuXMLAtt(ap); + + lp = pp->findElement(elementName); + + if (!lp) + { + snprintf(errmsg, ERRMSG_SIZE, "Error: unable to find element '%.64s' in property '%.64s'", elementName.ascii(), pp->name.ascii()); + return (-1); + } + + //fprintf(stderr, "tag okay, getting perm\n"); + switch (pp->perm) + { + case PP_RW: // FALLTHRU + case PP_RO: + if (pp->guitype == PG_TEXT) + { + lp->text = QString(pcdataXMLEle(ep)); + lp->read_w->setText(lp->text); + } + else if (pp->guitype == PG_NUMERIC) + { + lp->value = atof(pcdataXMLEle(ep)); + numberFormat(iNumber, lp->format.ascii(), lp->value); + lp->text = iNumber; + lp->read_w->setText(lp->text); + + ap = findXMLAtt (ep, "min"); + if (ap) { min = atof(valuXMLAtt(ap)); lp->setMin(min); } + ap = findXMLAtt (ep, "max"); + if (ap) { max = atof(valuXMLAtt(ap)); lp->setMax(max); } + + /*if (lp->spin_w) + { + lp->spin_w->setValue(lp->value); + lp->spinChanged(lp->value); + }*/ + + } + break; + + case PP_WO: + if (pp->guitype == PG_TEXT) + lp->write_w->setText(QString(pcdataXMLEle(ep))); + else if (pp->guitype == PG_NUMERIC) + { + lp->value = atof(pcdataXMLEle(ep)); + numberFormat(iNumber, lp->format.ascii(), lp->value); + lp->text = iNumber; + + if (lp->spin_w) + lp->spin_w->setValue(lp->value); + else + lp->write_w->setText(lp->text); + + ap = findXMLAtt (ep, "min"); + if (ap) { min = (int) atof(valuXMLAtt(ap)); lp->setMin(min); } + ap = findXMLAtt (ep, "max"); + if (ap) { max = (int) atof(valuXMLAtt(ap)); lp->setMax(max); } + } + break; + + } + } + + /* handle standard cases if needed */ + stdDev->setTextValue(pp); + + // suppress warning + errmsg = errmsg; + + return (0); +} + +/* set the given BUTTONS or LIGHTS property from the given element. + * root should have some <switch> or <light> children. + * return 0 if ok else -1 with reason in errmsg + */ +int INDI_D::setLabelState (INDI_P *pp, XMLEle *root, char errmsg[]) +{ + int menuChoice=0; + unsigned i=0; + XMLEle *ep; + XMLAtt *ap; + INDI_E *lp = NULL; + int islight; + PState state; + + /* for each child element */ + for (ep = nextXMLEle (root, 1), i=0; ep != NULL; ep = nextXMLEle (root, 0), i++) + { + + /* only using light and switch */ + islight = !strcmp (tagXMLEle(ep), "oneLight"); + if (!islight && strcmp (tagXMLEle(ep), "oneSwitch")) + continue; + + ap = findXMLAtt (ep, "name"); + /* no name */ + if (!ap) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s %.64s requires name", + tagXMLEle(root), name.ascii(), pp->name.ascii(), tagXMLEle(ep)); + return (-1); + } + + if ((islight && crackLightState (pcdataXMLEle(ep), &state) < 0) + || (!islight && crackSwitchState (pcdataXMLEle(ep), &state) < 0)) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown state %.64s for %.64s %.64s %.64s", + tagXMLEle(root), pcdataXMLEle(ep), name.ascii(), pp->name.ascii(), tagXMLEle(ep)); + return (-1); + } + + /* find matching label */ + //fprintf(stderr, "Find matching label. Name from XML is %s\n", valuXMLAtt(ap)); + lp = pp->findElement(QString(valuXMLAtt(ap))); + + if (!lp) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s has no choice named %.64s", + tagXMLEle(root), name.ascii(), pp->name.ascii(), valuXMLAtt(ap)); + return (-1); + } + + QFont buttonFont; + /* engage new state */ + lp->state = state; + + switch (pp->guitype) + { + case PG_BUTTONS: + if (islight) + break; + + lp->push_w->setDown(state == PS_ON ? true : false); + buttonFont = lp->push_w->font(); + buttonFont.setBold(state == PS_ON ? TRUE : FALSE); + lp->push_w->setFont(buttonFont); + + break; + + case PG_RADIO: + lp->check_w->setChecked(state == PS_ON ? true : false); + break; + case PG_MENU: + if (state == PS_ON) + { + if (menuChoice) + { + snprintf(errmsg, ERRMSG_SIZE, "INDI: <%.64s> %.64s %.64s has multiple ON states", tagXMLEle(root), name.ascii(), pp->name.ascii()); + return (-1); + } + menuChoice = 1; + pp->om_w->setCurrentItem(i); + } + break; + + case PG_LIGHTS: + lp->drawLt(); + break; + + default: + break; + } + + } + + stdDev->setLabelState(pp); + + return (0); +} + +/* Set BLOB vector. Process incoming data stream + * Return 0 if okay, -1 if error +*/ +int INDI_D::setBLOB(INDI_P *pp, XMLEle * root, char errmsg[]) +{ + + XMLEle *ep; + INDI_E *blobEL; + + for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) + { + + if (strcmp(tagXMLEle(ep), "oneBLOB") == 0) + { + + blobEL = pp->findElement(QString(findXMLAttValu (ep, "name"))); + + if (blobEL) + return processBlob(blobEL, ep, errmsg); + else + { + sprintf (errmsg, "INDI: set %64s.%64s.%64s not found", name.ascii(), pp->name.ascii(), findXMLAttValu(ep, "name")); + return (-1); + } + } + } + + return (0); + +} + +/* Process incoming data stream + * Return 0 if okay, -1 if error +*/ +int INDI_D::processBlob(INDI_E *blobEL, XMLEle *ep, char errmsg[]) +{ + XMLAtt *ap; + int blobSize=0, r=0, dataType=0; + uLongf dataSize=0; + QString dataFormat; + char *baseBuffer; + unsigned char *blobBuffer(NULL); + bool iscomp(false); + + ap = findXMLAtt(ep, "size"); + if (!ap) + { + sprintf (errmsg, "INDI: set %64s size not found", blobEL->name.ascii()); + return (-1); + } + + dataSize = atoi(valuXMLAtt(ap)); + + ap = findXMLAtt(ep, "format"); + if (!ap) + { + sprintf (errmsg, "INDI: set %64s format not found", blobEL->name.ascii()); + return (-1); + } + + dataFormat = QString(valuXMLAtt(ap)); + + baseBuffer = (char *) malloc ( (3*pcdatalenXMLEle(ep)/4) * sizeof (char)); + blobSize = from64tobits (baseBuffer, pcdataXMLEle(ep)); + blobBuffer = (unsigned char *) baseBuffer; + + /* Blob size = 0 when only state changes */ + if (dataSize == 0) + { + free (blobBuffer); + return (0); + } + else if (blobSize < 0) + { + free (blobBuffer); + sprintf (errmsg, "INDI: %64s.%64s.%64s bad base64", name.ascii(), blobEL->pp->name.ascii(), blobEL->name.ascii()); + return (-1); + } + + iscomp = (dataFormat.find(".z") != -1); + + dataFormat.remove(".z"); + + if (dataFormat == ".fits") dataType = DATA_FITS; + else if (dataFormat == ".stream") dataType = DATA_STREAM; + else if (dataFormat == ".ccdpreview") dataType = DATA_CCDPREVIEW; + else dataType = DATA_OTHER; + + //kdDebug() << "We're getting data with size " << dataSize << endl; + //kdDebug() << "data format " << dataFormat << endl; + + if (iscomp) + { + + dataBuffer = (unsigned char *) realloc (dataBuffer, (dataSize * sizeof(unsigned char))); + r = uncompress(dataBuffer, &dataSize, blobBuffer, (uLong) blobSize); + if (r != Z_OK) + { + sprintf(errmsg, "INDI: %64s.%64s.%64s compression error: %d", name.ascii(), blobEL->pp->name.ascii(), blobEL->name.ascii(), r); + free (blobBuffer); + return -1; + } + + //kdDebug() << "compressed" << endl; + } + else + { + //kdDebug() << "uncompressed!!" << endl; + dataBuffer = (unsigned char *) realloc (dataBuffer, (dataSize * sizeof(unsigned char))); + memcpy(dataBuffer, blobBuffer, dataSize); + } + + stdDev->handleBLOB(dataBuffer, dataSize, dataFormat); + + free (blobBuffer); + + return (0); + +} + +bool INDI_D::isOn() +{ + + INDI_P *prop; + + prop = findProp(QString("CONNECTION")); + if (!prop) + return false; + + return (prop->isOn(QString("CONNECT"))); +} + +INDI_P * INDI_D::addProperty (XMLEle *root, char errmsg[]) +{ + INDI_P *pp = NULL; + INDI_G *pg = NULL; + XMLAtt *ap = NULL; + + // Search for group tag + ap = findAtt (root, "group", errmsg); + if (!ap) + { + kdDebug() << QString(errmsg) << endl; + return NULL; + } + // Find an existing group, if none found, create one + pg = findGroup(QString(valuXMLAtt(ap)), 1, errmsg); + + if (!pg) + return NULL; + + /* get property name and add new property to dp */ + ap = findAtt (root, "name", errmsg); + if (ap == NULL) + return NULL; + + if (findProp (valuXMLAtt(ap))) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s %.64s %.64s> already exists.\n", tagXMLEle(root), + name.ascii(), valuXMLAtt(ap)); + return NULL; + } + + /* Remove Vertical spacer from group layout, this is done everytime + * a new property arrives. The spacer is then appended to the end of the + * properties */ + pg->propertyLayout->removeItem(pg->VerticalSpacer); + + pp = new INDI_P(pg, QString(valuXMLAtt(ap))); + + /* init state */ + ap = findAtt (root, "state", errmsg); + if (!ap) + { + delete(pp); + return (NULL); + } + + if (crackLightState (valuXMLAtt(ap), &pp->state) < 0) + { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> bogus state %.64s for %.64s %.64s", + tagXMLEle(root), valuXMLAtt(ap), pp->pg->dp->name.ascii(), pp->name.ascii()); + delete(pp); + return (NULL); + } + + /* init timeout */ + ap = findAtt (root, "timeout", NULL); + /* default */ + pp->timeout = ap ? atof(valuXMLAtt(ap)) : 0; + + /* log any messages */ + parentMgr->checkMsg (root, this); + + pp->addGUI(root); + + /* ok! */ + return (pp); +} + +INDI_P * INDI_D::findProp (QString name) +{ + for (unsigned int i = 0; i < gl.count(); i++) + for (unsigned int j = 0; j < gl.at(i)->pl.count(); j++) + if (name == gl.at(i)->pl.at(j)->name) + return (gl.at(i)->pl.at(j)); + + return NULL; +} + +INDI_G * INDI_D::findGroup (QString grouptag, int create, char errmsg[]) +{ + INDI_G *ig; + + for (ig = gl.first(); ig != NULL; ig = gl.next() ) + if (ig->name == grouptag) + { + curGroup = ig; + return ig; + } + + /* couldn't find an existing group, create a new one if create is 1*/ + if (create) + { + if (grouptag.isEmpty()) + grouptag = "Group_1"; + + curGroup = new INDI_G(this, grouptag); + gl.append(curGroup); + return curGroup; + } + + snprintf (errmsg, ERRMSG_SIZE, "INDI: group %.64s not found in %.64s", grouptag.ascii(), name.ascii()); + return NULL; +} + + +/* find "perm" attribute in root, crack and set *pp. + * return 0 if ok else -1 with excuse in errmsg[] + */ + + int INDI_D::findPerm (INDI_P *pp, XMLEle *root, PPerm *permp, char errmsg[]) +{ + XMLAtt *ap; + + ap = findXMLAtt(root, "perm"); + if (!ap) { + snprintf (errmsg, ERRMSG_SIZE,"INDI: <%.64s %.64s %.64s> missing attribute 'perm'", + tagXMLEle(root), pp->pg->dp->name.ascii(), pp->name.ascii()); + return (-1); + } + if (!strcmp(valuXMLAtt(ap), "ro") || !strcmp(valuXMLAtt(ap), "r")) + *permp = PP_RO; + else if (!strcmp(valuXMLAtt(ap), "wo")) + *permp = PP_WO; + else if (!strcmp(valuXMLAtt(ap), "rw") || !strcmp(valuXMLAtt(ap), "w")) + *permp = PP_RW; + else { + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown perm %.64s for %.64s %.64s", + tagXMLEle(root), valuXMLAtt(ap), pp->pg->dp->name.ascii(), pp->name.ascii()); + return (-1); + } + + return (0); +} + +/* convert the given light/property state string to the PState at psp. + * return 0 if successful, else -1 and leave *psp unchanged. + */ +int INDI_D::crackLightState (char *name, PState *psp) +{ + typedef struct + { + PState s; + const char *name; + } PSMap; + + PSMap psmap[] = + { + {PS_IDLE, "Idle"}, + {PS_OK, "Ok"}, + {PS_BUSY, "Busy"}, + {PS_ALERT, "Alert"}, + }; + + for (int i = 0; i < 4; i++) + if (!strcmp (psmap[i].name, name)) { + *psp = psmap[i].s; + return (0); + } + + return (-1); +} + +/* convert the given switch state string to the PState at psp. + * return 0 if successful, else -1 and leave *psp unchanged. + */ +int INDI_D::crackSwitchState (char *name, PState *psp) +{ + typedef struct + { + PState s; + const char *name; + } PSMap; + + PSMap psmap[] = + { + {PS_ON, "On"}, + {PS_OFF, "Off"}, + }; + + + for (int i = 0; i < 2; i++) + if (!strcmp (psmap[i].name, name)) + { + *psp = psmap[i].s; + return (0); + } + + return (-1); +} + +int INDI_D::buildTextGUI(XMLEle *root, char errmsg[]) +{ + INDI_P *pp = NULL; + PPerm p; + + /* build a new property */ + pp = addProperty (root, errmsg); + + if (pp == NULL) + return (-1); + + /* get the permission, it will determine layout issues */ + if (findPerm (pp, root, &p, errmsg)) + { + delete(pp); + return (-1); + } + + /* we know it will be a general text GUI */ + pp->guitype = PG_TEXT; + pp->perm = p; + + if (pp->buildTextGUI(root, errmsg) < 0) + { + delete (pp); + return (-1); + } + + pp->pg->addProperty(pp); + + return (0); +} + +/* build GUI for a number property. + * return 0 if ok, else -1 with reason in errmsg[] + */ +int INDI_D::buildNumberGUI (XMLEle *root, char *errmsg) +{ + INDI_P *pp = NULL; + PPerm p; + + /* build a new property */ + pp = addProperty (root, errmsg); + + if (pp == NULL) + return (-1); + + /* get the permission, it will determine layout issues */ + if (findPerm (pp, root, &p, errmsg)) + { + delete(pp); + return (-1); + } + + /* we know it will be a number GUI */ + pp->guitype = PG_NUMERIC; + pp->perm = p; + + if (pp->buildNumberGUI(root, errmsg) < 0) + { + delete (pp); + return (-1); + } + + pp->pg->addProperty(pp); + + return (0); +} + +/* build GUI for switches property. + * rule and number of will determine exactly how the GUI is built. + * return 0 if ok, else -1 with reason in errmsg[] + */ +int INDI_D::buildSwitchesGUI (XMLEle *root, char errmsg[]) +{ + INDI_P *pp; + XMLAtt *ap; + XMLEle *ep; + int n, err; + + /* build a new property */ + pp = addProperty (root, errmsg); + if (!pp) + return (-1); + + ap = findAtt (root, "rule", errmsg); + if (!ap) + { + delete(pp); + return (-1); + } + + /* decide GUI. might use MENU if OneOf but too many for button array */ + if (!strcmp (valuXMLAtt(ap), "OneOfMany") || !strcmp (valuXMLAtt(ap), "AtMostOne")) + { + /* count number of switches -- make menu if too many */ + for ( ep = nextXMLEle(root, 1) , n = 0 ; ep != NULL; ep = nextXMLEle(root, 0)) + if (!strcmp (tagXMLEle(ep), "defSwitch")) + n++; + + if (n > MAXRADIO) + { + pp->guitype = PG_MENU; + err = pp->buildMenuGUI (root, errmsg); + if (err < 0) + { + delete(pp); + pp=0; + return err; + } + + pp->pg->addProperty(pp); + return (err); + } + + /* otherwise, build 1-4 button layout */ + pp->guitype = PG_BUTTONS; + + err = pp->buildSwitchesGUI(root, errmsg); + if (err < 0) + { + delete (pp); + pp=0; + return err; + } + + pp->pg->addProperty(pp); + return (err); + + } + else if (!strcmp (valuXMLAtt(ap), "AnyOfMany")) + { + /* 1-4 checkboxes layout */ + pp->guitype = PG_RADIO; + + err = pp->buildSwitchesGUI(root, errmsg); + if (err < 0) + { + delete (pp); + pp=0; + return err; + } + + pp->pg->addProperty(pp); + return (err); + } + + snprintf (errmsg, ERRMSG_SIZE, "INDI: <%.64s> unknown rule %.64s for %.64s %.64s", + tagXMLEle(root), valuXMLAtt(ap), name.ascii(), pp->name.ascii()); + + delete(pp); + return (-1); +} + + + +/* build GUI for a lights GUI. + * return 0 if ok, else -1 with reason in errmsg[] */ +int INDI_D::buildLightsGUI (XMLEle *root, char errmsg[]) +{ + INDI_P *pp; + + // build a new property + pp = addProperty (root, errmsg); + if (!pp) + return (-1); + + pp->guitype = PG_LIGHTS; + + if (pp->buildLightsGUI(root, errmsg) < 0) + { + delete (pp); + return (-1); + } + + pp->pg->addProperty(pp); + return (0); +} + +/* build GUI for a BLOB GUI. + * return 0 if ok, else -1 with reason in errmsg[] */ +int INDI_D::buildBLOBGUI (XMLEle *root, char errmsg[]) +{ + INDI_P *pp; + PPerm p; + + // build a new property + pp = addProperty (root, errmsg); + if (!pp) + return (-1); + + /* get the permission, it will determine layout issues */ + if (findPerm (pp, root, &p, errmsg)) + { + delete(pp); + return (-1); + } + + /* we know it will be a number GUI */ + pp->perm = p; + pp->guitype = PG_BLOB; + + if (pp->buildBLOBGUI(root, errmsg) < 0) + { + delete (pp); + return (-1); + } + + pp->pg->addProperty(pp); + return (0); +} + +INDI_E * INDI_D::findElem(QString name) +{ + INDI_G *grp; + INDI_P *prop; + INDI_E *el; + + for (grp = gl.first(); grp != NULL; grp = gl.next()) + { + for (prop = grp->pl.first(); prop != NULL; prop = grp->pl.next()) + { + el = prop->findElement(name); + if (el != NULL) return el; + } + } + + return NULL; + +} + + +#include "indidevice.moc" |