summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJasem Mutlaq <mutlaqja@ikarustech.com>2016-09-24 20:18:12 (GMT)
committerJasem Mutlaq <mutlaqja@ikarustech.com>2016-09-24 20:18:12 (GMT)
commite1f76e51011e71bf0f92ee097663f0861c574e59 (patch)
treed2763ae2bdd7d5f27d09363f265b84ca14e7d810
parentc35aeefeec960297c5083dab56f48f5eb678a3fb (diff)
Moving all mount module files to their own dedicated directly
-rw-r--r--kstars/ekos/mount/mount.cpp685
-rw-r--r--kstars/ekos/mount/mount.h233
-rw-r--r--kstars/ekos/mount/mount.ui556
3 files changed, 1474 insertions, 0 deletions
diff --git a/kstars/ekos/mount/mount.cpp b/kstars/ekos/mount/mount.cpp
new file mode 100644
index 0000000..4235b75
--- /dev/null
+++ b/kstars/ekos/mount/mount.cpp
@@ -0,0 +1,685 @@
+/* Ekos Mount Module
+ Copyright (C) 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+ 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.
+ */
+
+#include <KNotifications/KNotification>
+#include "mount.h"
+#include "Options.h"
+
+#include "indi/driverinfo.h"
+#include "indi/indicommon.h"
+#include "indi/clientmanager.h"
+#include "indi/indifilter.h"
+
+#include "mountadaptor.h"
+
+#include "ekosmanager.h"
+
+#include "kstars.h"
+#include "kstarsdata.h"
+#include "ksutils.h"
+
+#include <basedevice.h>
+
+extern const char *libindi_strings_context;
+
+#define UPDATE_DELAY 1000
+#define ABORT_DISPATCH_LIMIT 3
+
+namespace Ekos
+{
+
+Mount::Mount()
+{
+ setupUi(this);
+ new MountAdaptor(this);
+ QDBusConnection::sessionBus().registerObject("/KStars/Ekos/Mount", this);
+
+ currentTelescope = NULL;
+
+ stopB->setIcon(QIcon::fromTheme("process-stop"));
+ northB->setIcon(QIcon::fromTheme("go-up"));
+ westB->setIcon(QIcon::fromTheme("go-previous"));
+ eastB->setIcon(QIcon::fromTheme("go-next"));
+ southB->setIcon(QIcon::fromTheme("go-down"));
+
+ abortDispatch = -1;
+
+ minAltLimit->setValue(Options::minimumAltLimit());
+ maxAltLimit->setValue(Options::maximumAltLimit());
+
+
+ QFile tempFile;
+
+ if (KSUtils::openDataFile( tempFile, "go-nw.png" ) )
+ {
+ northwestB->setIcon(QIcon(tempFile.fileName()));
+ tempFile.close();
+ }
+
+ if (KSUtils::openDataFile( tempFile, "go-ne.png" ) )
+ {
+ northeastB->setIcon(QIcon(tempFile.fileName()));
+ tempFile.close();
+ }
+
+ if (KSUtils::openDataFile( tempFile, "go-sw.png" ) )
+ {
+ southwestB->setIcon(QIcon(tempFile.fileName()));
+ tempFile.close();
+ }
+
+ if (KSUtils::openDataFile( tempFile, "go-se.png" ) )
+ {
+ southeastB->setIcon(QIcon(tempFile.fileName()));
+ tempFile.close();
+ }
+
+ connect(northB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(northB, SIGNAL(released()), this, SLOT(stop()));
+ connect(westB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(westB, SIGNAL(released()), this, SLOT(stop()));
+ connect(southB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(southB, SIGNAL(released()), this, SLOT(stop()));
+ connect(eastB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(eastB, SIGNAL(released()), this, SLOT(stop()));
+ connect(northeastB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(northeastB, SIGNAL(released()), this, SLOT(stop()));
+ connect(northwestB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(northwestB, SIGNAL(released()), this, SLOT(stop()));
+ connect(southeastB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(southeastB, SIGNAL(released()), this, SLOT(stop()));
+ connect(southwestB, SIGNAL(pressed()), this, SLOT(move()));
+ connect(southwestB, SIGNAL(released()), this, SLOT(stop()));
+ connect(stopB, SIGNAL(clicked()), this, SLOT(stop()));
+ connect(saveB, SIGNAL(clicked()), this, SLOT(save()));
+
+ connect(minAltLimit, SIGNAL(editingFinished()), this, SLOT(saveLimits()));
+ connect(maxAltLimit, SIGNAL(editingFinished()), this, SLOT(saveLimits()));
+
+ connect(enableLimitsCheck, SIGNAL(toggled(bool)), this, SLOT(enableAltitudeLimits(bool)));
+ enableLimitsCheck->setChecked(Options::enableAltitudeLimits());
+ altLimitEnabled = enableLimitsCheck->isChecked();
+
+ updateTimer.setInterval(UPDATE_DELAY);
+ connect(&updateTimer, SIGNAL(timeout()), this, SLOT(updateTelescopeCoords()));
+}
+
+Mount::~Mount()
+{
+}
+
+void Mount::setTelescope(ISD::GDInterface *newTelescope)
+{
+ currentTelescope = static_cast<ISD::Telescope*> (newTelescope);
+
+ connect(currentTelescope, SIGNAL(numberUpdated(INumberVectorProperty*)), this, SLOT(updateNumber(INumberVectorProperty*)), Qt::UniqueConnection);
+ connect(currentTelescope, SIGNAL(switchUpdated(ISwitchVectorProperty*)), this, SLOT(updateSwitch(ISwitchVectorProperty*)), Qt::UniqueConnection);
+ connect(currentTelescope, SIGNAL(newTarget(QString)), this, SIGNAL(newTarget(QString)), Qt::UniqueConnection);
+
+ //Disable this for now since ALL INDI drivers now log their messages to verbose output
+ //connect(currentTelescope, SIGNAL(messageUpdated(int)), this, SLOT(updateLog(int)), Qt::UniqueConnection);
+
+ if (enableLimitsCheck->isChecked())
+ currentTelescope->setAltLimits(minAltLimit->value(), maxAltLimit->value());
+
+ updateTimer.start();
+
+ syncTelescopeInfo();
+}
+
+void Mount::syncTelescopeInfo()
+{
+ INumberVectorProperty * nvp = currentTelescope->getBaseDevice()->getNumber("TELESCOPE_INFO");
+
+ if (nvp)
+ {
+
+ primaryScopeGroup->setTitle(currentTelescope->getDeviceName());
+ guideScopeGroup->setTitle(i18n("%1 guide scope", currentTelescope->getDeviceName()));
+
+ INumber *np = NULL;
+
+ np = IUFindNumber(nvp, "TELESCOPE_APERTURE");
+ if (np && np->value > 0)
+ primaryScopeApertureIN->setValue(np->value);
+
+ np = IUFindNumber(nvp, "TELESCOPE_FOCAL_LENGTH");
+ if (np && np->value > 0)
+ primaryScopeFocalIN->setValue(np->value);
+
+ np = IUFindNumber(nvp, "GUIDER_APERTURE");
+ if (np && np->value > 0)
+ guideScopeApertureIN->setValue(np->value);
+
+ np = IUFindNumber(nvp, "GUIDER_FOCAL_LENGTH");
+ if (np && np->value > 0)
+ guideScopeFocalIN->setValue(np->value);
+
+ }
+
+ ISwitchVectorProperty *svp = currentTelescope->getBaseDevice()->getSwitch("TELESCOPE_SLEW_RATE");
+
+ if (svp)
+ {
+ slewSpeedCombo->clear();
+ slewSpeedCombo->setEnabled(true);
+
+ for (int i=0; i < svp->nsp; i++)
+ slewSpeedCombo->addItem(i18nc(libindi_strings_context, svp->sp[i].label));
+
+ int index = IUFindOnSwitchIndex(svp);
+ slewSpeedCombo->setCurrentIndex(index);
+ connect(slewSpeedCombo, SIGNAL(activated(int)), currentTelescope, SLOT(setSlewRate(int)), Qt::UniqueConnection);
+ }
+ else
+ {
+ slewSpeedCombo->setEnabled(false);
+ disconnect(slewSpeedCombo, SIGNAL(activated(int)), currentTelescope, SLOT(setSlewRate(int)));
+ }
+
+ if (currentTelescope->canPark())
+ {
+ parkB->setEnabled(!currentTelescope->isParked());
+ unparkB->setEnabled(currentTelescope->isParked());
+ connect(parkB, SIGNAL(clicked()), currentTelescope, SLOT(Park()), Qt::UniqueConnection);
+ connect(unparkB, SIGNAL(clicked()), currentTelescope, SLOT(UnPark()), Qt::UniqueConnection);
+ }
+ else
+ {
+ parkB->setEnabled(false);
+ unparkB->setEnabled(false);
+ disconnect(parkB, SIGNAL(clicked()), currentTelescope, SLOT(Park()));
+ disconnect(unparkB, SIGNAL(clicked()), currentTelescope, SLOT(UnPark()));
+ }
+
+}
+
+void Mount::updateTelescopeCoords()
+{
+ double ra, dec;
+
+ if (currentTelescope && currentTelescope->getEqCoords(&ra, &dec))
+ {
+ telescopeCoord.setRA(ra);
+ telescopeCoord.setDec(dec);
+ telescopeCoord.EquatorialToHorizontal(KStarsData::Instance()->lst(), KStarsData::Instance()->geo()->lat());
+
+ raOUT->setText(telescopeCoord.ra().toHMSString());
+ decOUT->setText(telescopeCoord.dec().toDMSString());
+ azOUT->setText(telescopeCoord.az().toDMSString());
+ altOUT->setText(telescopeCoord.alt().toDMSString());
+
+ dms lst = KStarsData::Instance()->geo()->GSTtoLST( KStarsData::Instance()->clock()->utc().gst() );
+ dms ha( lst.Degrees() - telescopeCoord.ra().Degrees() );
+ QChar sgn('+');
+ if ( ha.Hours() > 12.0 ) {
+ ha.setH( 24.0 - ha.Hours() );
+ sgn = '-';
+ }
+ haOUT->setText( QString("%1%2").arg(sgn).arg( ha.toHMSString() ) );
+ lstOUT->setText(lst.toHMSString());
+
+ double currentAlt = telescopeCoord.altRefracted().Degrees();
+
+ if (minAltLimit->isEnabled()
+ && ( currentAlt < minAltLimit->value() || currentAlt > maxAltLimit->value()))
+ {
+ if (currentAlt < minAltLimit->value())
+ {
+ // Only stop if current altitude is less than last altitude indicate worse situation
+ if (currentAlt < lastAlt && (abortDispatch == -1 || (currentTelescope->isInMotion()/* && ++abortDispatch > ABORT_DISPATCH_LIMIT*/)))
+ {
+ appendLogText(i18n("Telescope altitude is below minimum altitude limit of %1. Aborting motion...", QString::number(minAltLimit->value(), 'g', 3)));
+ currentTelescope->Abort();
+ //KNotification::event( QLatin1String( "OperationFailed" ));
+ KNotification::beep();
+ abortDispatch++;
+ }
+ }
+ else
+ {
+ // Only stop if current altitude is higher than last altitude indicate worse situation
+ if (currentAlt > lastAlt && (abortDispatch == -1 || (currentTelescope->isInMotion()/* && ++abortDispatch > ABORT_DISPATCH_LIMIT*/)))
+ {
+ appendLogText(i18n("Telescope altitude is above maximum altitude limit of %1. Aborting motion...", QString::number(maxAltLimit->value(), 'g', 3)));
+ currentTelescope->Abort();
+ //KNotification::event( QLatin1String( "OperationFailed" ));
+ KNotification::beep();
+ abortDispatch++;
+ }
+ }
+ }
+ else
+ abortDispatch = -1;
+
+ lastAlt = currentAlt;
+
+ newCoords(raOUT->text(), decOUT->text(), azOUT->text(), altOUT->text());
+
+ emit newStatus(currentTelescope->getStatus());
+
+ if (currentTelescope->isConnected() == false)
+ updateTimer.stop();
+ else if (updateTimer.isActive() == false)
+ updateTimer.start();
+ }
+ else
+ updateTimer.stop();
+}
+
+void Mount::updateNumber(INumberVectorProperty *nvp)
+{
+ if (!strcmp(nvp->name, "TELESCOPE_INFO"))
+ {
+ if (nvp->s == IPS_ALERT)
+ {
+ QString newMessage;
+ if (primaryScopeApertureIN->value() == 1 || primaryScopeFocalIN->value() == 1)
+ newMessage = i18n("Error syncing telescope info. Please fill telescope aperture and focal length.");
+ else
+ newMessage = i18n("Error syncing telescope info. Check INDI control panel for more details.");
+ if (newMessage != lastNotificationMessage)
+ {
+ appendLogText(newMessage);
+ lastNotificationMessage = newMessage;
+ }
+ }
+ else
+ {
+ syncTelescopeInfo();
+ QString newMessage = i18n("Telescope info updated successfully.");
+ if (newMessage != lastNotificationMessage)
+ {
+ appendLogText(newMessage);
+ lastNotificationMessage = newMessage;
+ }
+
+ }
+ }
+}
+
+void Mount::updateSwitch(ISwitchVectorProperty *svp)
+{
+ if (!strcmp(svp->name, "TELESCOPE_SLEW_RATE"))
+ {
+ int index = IUFindOnSwitchIndex(svp);
+ slewSpeedCombo->setCurrentIndex(index);
+ }
+ else if (!strcmp(svp->name, "TELESCOPE_PARK"))
+ {
+ ISwitch *sp = IUFindSwitch(svp, "PARK");
+ if (sp)
+ {
+ parkB->setEnabled((sp->s == ISS_OFF));
+ unparkB->setEnabled((sp->s == ISS_ON));
+ }
+ }
+}
+
+void Mount::appendLogText(const QString &text)
+{
+ logText.insert(0, i18nc("log entry; %1 is the date, %2 is the text", "%1 %2", QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss"), text));
+
+ if (Options::verboseLogging())
+ qDebug() << "Mount: " << text;
+
+ emit newLog();
+}
+
+void Mount::updateLog(int messageID)
+{
+ INDI::BaseDevice *dv = currentTelescope->getBaseDevice();
+
+ QString message = QString::fromStdString(dv->messageQueue(messageID));
+
+ logText.insert(0, i18nc("Message shown in Ekos Mount module", "%1", message));
+
+ emit newLog();
+}
+
+void Mount::clearLog()
+{
+ logText.clear();
+ emit newLog();
+}
+
+void Mount::move()
+{
+ QObject* obj = sender();
+
+ if (obj == northB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == westB)
+ {
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == southB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == eastB)
+ {
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == northwestB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_START);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == northeastB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_START);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == southwestB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_START);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_START);
+ }
+ else if (obj == southeastB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_START);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_START);
+ }
+}
+
+void Mount::stop()
+{
+ QObject* obj = sender();
+
+ if (obj == stopB)
+ currentTelescope->Abort();
+ else if (obj == northB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == westB)
+ {
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == southB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == eastB)
+ {
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == northwestB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_STOP);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == northeastB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_NORTH, ISD::Telescope::MOTION_STOP);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == southwestB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_STOP);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_WEST, ISD::Telescope::MOTION_STOP);
+ }
+ else if (obj == southeastB)
+ {
+ currentTelescope->MoveNS(ISD::Telescope::MOTION_SOUTH, ISD::Telescope::MOTION_STOP);
+ currentTelescope->MoveWE(ISD::Telescope::MOTION_EAST, ISD::Telescope::MOTION_STOP);
+ }
+
+}
+
+void Mount::save()
+{
+ INumberVectorProperty * nvp = currentTelescope->getBaseDevice()->getNumber("TELESCOPE_INFO");
+
+ if (nvp)
+ {
+
+ primaryScopeGroup->setTitle(currentTelescope->getDeviceName());
+ guideScopeGroup->setTitle(i18n("%1 guide scope", currentTelescope->getDeviceName()));
+
+ INumber *np = NULL;
+
+ np = IUFindNumber(nvp, "TELESCOPE_APERTURE");
+ if (np)
+ np->value = primaryScopeApertureIN->value();
+ np = IUFindNumber(nvp, "TELESCOPE_FOCAL_LENGTH");
+ if (np)
+ np->value = primaryScopeFocalIN->value();
+ np = IUFindNumber(nvp, "GUIDER_APERTURE");
+ if (np)
+ np->value = guideScopeApertureIN->value() == 1 ? primaryScopeApertureIN->value() : guideScopeApertureIN->value();
+ np = IUFindNumber(nvp, "GUIDER_FOCAL_LENGTH");
+ if (np)
+ np->value = guideScopeFocalIN->value() == 1 ? primaryScopeFocalIN->value() : guideScopeFocalIN->value();
+
+ ClientManager *clientManager = currentTelescope->getDriverInfo()->getClientManager();
+
+ clientManager->sendNewNumber(nvp);
+
+ currentTelescope->setConfig(SAVE_CONFIG);
+
+ //appendLogText(i18n("Saving telescope information..."));
+
+ }
+ else
+ appendLogText(i18n("Failed to save telescope information."));
+}
+
+void Mount::saveLimits()
+{
+ Options::setMinimumAltLimit(minAltLimit->value());
+ Options::setMaximumAltLimit(maxAltLimit->value());
+ currentTelescope->setAltLimits(minAltLimit->value(), maxAltLimit->value());
+}
+
+void Mount::enableAltitudeLimits(bool enable)
+{
+ Options::setEnableAltitudeLimits(enable);
+
+ if (enable)
+ {
+ minAltLabel->setEnabled(true);
+ maxAltLabel->setEnabled(true);
+
+ minAltLimit->setEnabled(true);
+ maxAltLimit->setEnabled(true);
+
+ if (currentTelescope)
+ currentTelescope->setAltLimits(minAltLimit->value(), maxAltLimit->value());
+ }
+ else
+ {
+ minAltLabel->setEnabled(false);
+ maxAltLabel->setEnabled(false);
+
+ minAltLimit->setEnabled(false);
+ maxAltLimit->setEnabled(false);
+
+ if (currentTelescope)
+ currentTelescope->setAltLimits(-1, -1);
+ }
+}
+
+void Mount::enableAltLimits()
+{
+ //Only enable if it was already enabled before and the minAltLimit is currently disabled.
+ if (altLimitEnabled && minAltLimit->isEnabled() == false)
+ enableAltitudeLimits(true);
+}
+
+void Mount::disableAltLimits()
+{
+ altLimitEnabled = enableLimitsCheck->isChecked();
+
+ enableAltitudeLimits(false);
+
+}
+
+QList<double> Mount::getAltitudeLimits()
+{
+ QList<double> limits;
+
+ limits.append(minAltLimit->value());
+ limits.append(maxAltLimit->value());
+
+ return limits;
+}
+
+void Mount::setAltitudeLimits(double minAltitude, double maxAltitude, bool enabled)
+{
+ minAltLimit->setValue(minAltitude);
+ maxAltLimit->setValue(maxAltitude);
+
+ enableLimitsCheck->setChecked(enabled);
+
+}
+
+bool Mount::isLimitsEnabled()
+{
+ return enableLimitsCheck->isChecked();
+}
+
+bool Mount::slew(double RA, double DEC)
+{
+ if (currentTelescope == NULL || currentTelescope->isConnected() == false)
+ return false;
+
+ return currentTelescope->Slew(RA, DEC);
+}
+
+bool Mount::abort()
+{
+ return currentTelescope->Abort();
+}
+
+IPState Mount::getSlewStatus()
+{
+ if (currentTelescope == NULL)
+ return IPS_ALERT;
+
+ return currentTelescope->getState("EQUATORIAL_EOD_COORD");
+}
+
+QList<double> Mount::getEquatorialCoords()
+{
+ double ra,dec;
+ QList<double> coords;
+
+ currentTelescope->getEqCoords(&ra, &dec);
+ coords.append(ra);
+ coords.append(dec);
+
+ return coords;
+}
+
+QList<double> Mount::getHorizontalCoords()
+{
+ QList<double> coords;
+
+ coords.append(telescopeCoord.az().Degrees());
+ coords.append(telescopeCoord.alt().Degrees());
+
+ return coords;
+}
+
+double Mount::getHourAngle()
+{
+ dms lst = KStarsData::Instance()->geo()->GSTtoLST( KStarsData::Instance()->clock()->utc().gst() );
+ dms ha( lst.Degrees() - telescopeCoord.ra().Degrees() );
+ double HA = ha.Hours();
+
+ if ( HA > 12.0 )
+ return (24 - HA);
+ else
+ return HA;
+}
+
+QList<double> Mount::getTelescopeInfo()
+{
+ QList<double> info;
+
+ info.append(primaryScopeFocalIN->value());
+ info.append(primaryScopeApertureIN->value());
+ info.append(guideScopeFocalIN->value());
+ info.append(guideScopeApertureIN->value());
+
+ return info;
+}
+
+void Mount::setTelescopeInfo(double primaryFocalLength, double primaryAperture, double guideFocalLength, double guideAperture)
+{
+ primaryScopeFocalIN->setValue(primaryFocalLength);
+ primaryScopeApertureIN->setValue(primaryAperture);
+ guideScopeFocalIN->setValue(guideFocalLength);
+ guideScopeApertureIN->setValue(guideAperture);
+}
+
+bool Mount::canPark()
+{
+ if (currentTelescope == NULL)
+ return false;
+
+ return currentTelescope->canPark();
+}
+
+bool Mount::park()
+{
+ if (currentTelescope == NULL || currentTelescope->canPark() == false)
+ return false;
+
+ return currentTelescope->Park();
+}
+
+bool Mount::unpark()
+{
+ if (currentTelescope == NULL || currentTelescope->canPark() == false)
+ return false;
+
+ return currentTelescope->UnPark();
+}
+
+Mount::ParkingStatus Mount::getParkingStatus()
+{
+ if (currentTelescope == NULL || currentTelescope->canPark() == false)
+ return PARKING_ERROR;
+
+ ISwitchVectorProperty* parkSP = currentTelescope->getBaseDevice()->getSwitch("TELESCOPE_PARK");
+
+ if (parkSP == NULL)
+ return PARKING_ERROR;
+
+ switch (parkSP->s)
+ {
+ case IPS_IDLE:
+ return PARKING_IDLE;
+
+ case IPS_OK:
+ if (parkSP->sp[0].s == ISS_ON)
+ return PARKING_OK;
+ else
+ return UNPARKING_OK;
+ break;
+
+ case IPS_BUSY:
+ if (parkSP->sp[0].s == ISS_ON)
+ return PARKING_BUSY;
+ else
+ return UNPARKING_BUSY;
+
+ case IPS_ALERT:
+ return PARKING_ERROR;
+ }
+
+ return PARKING_ERROR;
+}
+
+}
diff --git a/kstars/ekos/mount/mount.h b/kstars/ekos/mount/mount.h
new file mode 100644
index 0000000..2c8ab3b
--- /dev/null
+++ b/kstars/ekos/mount/mount.h
@@ -0,0 +1,233 @@
+/* Ekos Mount Module
+ Copyright (C) 2015 Jasem Mutlaq <mutlaqja@ikarustech.com>
+
+ 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.
+ */
+
+#ifndef MOUNT_H
+#define MOUNT_H
+
+#include <QtDBus/QtDBus>
+#include "ui_mount.h"
+
+#include "indi/indistd.h"
+#include "indi/indifocuser.h"
+#include "indi/inditelescope.h"
+
+namespace Ekos
+{
+
+/**
+ *@class Mount
+ *@short Supports controlling INDI telescope devices including setting/retrieving mount properties, slewing, motion and speed controls, in addition to enforcing altitude limits and parking/unparking.
+ *@author Jasem Mutlaq
+ *@version 1.1
+ */
+class Mount : public QWidget, public Ui::Mount
+{
+
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.kde.kstars.Ekos.Mount")
+
+public:
+ Mount();
+ ~Mount();
+
+ typedef enum { PARKING_IDLE, PARKING_OK, UNPARKING_OK, PARKING_BUSY, UNPARKING_BUSY, PARKING_ERROR } ParkingStatus;
+
+ /**
+ * @brief setTelescope Sets the mount module telescope interface
+ * @param newTelescope pointer to telescope interface object
+ */
+ void setTelescope(ISD::GDInterface *newTelescope);
+
+ // Log functions
+ void appendLogText(const QString &);
+ void clearLog();
+ QString getLogText() { return logText.join("\n"); }
+
+ /** @defgroup MountDBusInterface Ekos Mount DBus Interface
+ * Mount interface provides advanced scripting capabilities to control INDI mounts.
+ */
+
+ /*@{*/
+
+ /** DBUS interface function.
+ * Returns the mount altitude limits.
+ * @return Returns array of doubles. First item is minimum altititde in degrees. Second item is maximum altitude limit in degrees.
+ */
+ Q_SCRIPTABLE QList<double> getAltitudeLimits();
+
+ /** DBUS interface function.
+ * Sets the mount altitude limits, and whether they are enabled or disabled.
+ */
+ Q_SCRIPTABLE Q_NOREPLY void setAltitudeLimits(double minAltitude, double maxAltitude, bool enabled);
+
+ /** DBUS interface function.
+ * Returns whether the mount limits are enabled or disabled.
+ * @return True if enabled, false otherwise.
+ */
+ Q_SCRIPTABLE bool isLimitsEnabled();
+
+ /** DBUS interface function.
+ * Slew the mount to the RA/DEC (JNow).
+ * @param RA Right ascention is hours.
+ * @param DEC Declination in degrees.
+ * @return true if the command is sent successfully, false otherwise.
+ */
+ Q_SCRIPTABLE bool slew(double RA, double DEC);
+
+ /** DBUS interface function.
+ * Get equatorial coords (JNow). An array of doubles is returned. First element is RA in hours. Second elements is DEC in degrees.
+ */
+ Q_SCRIPTABLE QList<double> getEquatorialCoords();
+
+ /** DBUS interface function.
+ * Get Horizontal coords. An array of doubles is returned. First element is Azimuth in degrees. Second elements is Altitude in degrees.
+ */
+ Q_SCRIPTABLE QList<double> getHorizontalCoords();
+
+ /** DBUS interface function.
+ * Get mount hour angle in hours (-12 to +12).
+ */
+ Q_SCRIPTABLE double getHourAngle();
+
+ /** DBUS interface function.
+ * Aborts the mount motion
+ * @return true if the command is sent successfully, false otherwise.
+ */
+ Q_SCRIPTABLE bool abort();
+
+ /** DBUS interface function.
+ * Get the mount slew status ("Idle","Complete", "Busy", "Error")
+ */
+ Q_SCRIPTABLE IPState getSlewStatus();
+
+ /** DBUS interface function.
+ * Get telescope and guide scope info. An array of doubles is returned in order.
+ * Primary Telescope Focal Length (mm), Primary Telescope Aperture (mm), Guide Telescope Focal Length (mm), Guide Telescope Aperture (mm)
+ */
+ Q_SCRIPTABLE QList<double> getTelescopeInfo();
+
+ /** DBUS interface function.
+ * Set telescope and guide scope info. All measurements is in millimeters.
+ * @param primaryFocalLength Primary Telescope Focal Length
+ * @param primaryAperture Primary Telescope Aperture
+ * @param guideFocalLength Guide Telescope Focal Length
+ * @param guideAperture Guide Telescope Aperture
+ */
+ Q_SCRIPTABLE Q_NOREPLY void setTelescopeInfo(double primaryFocalLength, double primaryAperture, double guideFocalLength, double guideAperture);
+
+ /** DBUS interface function.
+ * Can mount park?
+ */
+ Q_SCRIPTABLE bool canPark();
+
+ /** DBUS interface function.
+ * Park mount
+ */
+ Q_SCRIPTABLE bool park();
+
+ /** DBUS interface function.
+ * Unpark mount
+ */
+ Q_SCRIPTABLE bool unpark();
+
+ /** DBUS interface function.
+ * Return parking status of the mount.
+ */
+ Q_SCRIPTABLE ParkingStatus getParkingStatus();
+
+ /** @}*/
+
+public slots:
+
+ /**
+ * @brief syncTelescopeInfo Update telescope information to reflect any property changes
+ */
+ void syncTelescopeInfo();
+ /**
+ * @brief updateNumber Update number properties under watch in the mount module
+ * @param nvp pointer to number property
+ */
+ void updateNumber(INumberVectorProperty *nvp);
+
+ /**
+ * @brief updateSwitch Update switch properties under watch in the mount module
+ * @param svp pointer to switch property
+ */
+ void updateSwitch(ISwitchVectorProperty *svp);
+
+ /**
+ * @brief updateLog Update mount module log to include any messages arriving for the telescope driver
+ * @param messageID ID of the new message
+ */
+ void updateLog(int messageID);
+
+ /**
+ * @brief updateTelescopeCoords runs every UPDATE_DELAY milliseconds to update the displayed coordinates of the mount and to ensure mount is
+ * within altitude limits if the altitude limits are enabled.
+ */
+ void updateTelescopeCoords();
+
+ /**
+ * @brief move Issues command to the mount to move in a particular direction based on the pressed direcitonal buttons in the GUI
+ */
+ void move();
+
+ /**
+ * @brief stop Aborts telescope motion
+ */
+ void stop();
+
+ /**
+ * @brief save Save telescope focal length and aperture in the INDI telescope driver configuration.
+ */
+ void save();
+
+ /**
+ * @brief saveLimits Saves altitude limit to the user options and updates the INDI telescope driver limits
+ */
+ void saveLimits();
+
+ /**
+ * @brief enableAltitudeLimits Enable or disable altitude limits
+ * @param enable True to enable, false to disable.
+ */
+ void enableAltitudeLimits(bool enable);
+
+ /**
+ * @brief enableAltLimits calls enableAltitudeLimits(true). This function is mostly used to enable altitude limit after a meridian flip is complete.
+ */
+ void enableAltLimits();
+
+ /**
+ * @brief disableAltLimits calls enableAltitudeLimits(false). This function is mostly used to disable altitude limit once a meridial flip process is started.
+ */
+ void disableAltLimits();
+
+signals:
+ void newLog();
+ void newCoords(const QString &ra, const QString &dec, const QString &az, const QString &alt);
+ void newTarget(const QString &name);
+ void newStatus(ISD::Telescope::TelescopeStatus status);
+
+private:
+
+ ISD::Telescope *currentTelescope;
+ QStringList logText;
+ SkyPoint telescopeCoord;
+ QString lastNotificationMessage;
+ QTimer updateTimer;
+ double lastAlt;
+ int abortDispatch;
+ bool altLimitEnabled;
+
+};
+
+}
+
+#endif // Mount
diff --git a/kstars/ekos/mount/mount.ui b/kstars/ekos/mount/mount.ui
new file mode 100644
index 0000000..2cf7d40
--- /dev/null
+++ b/kstars/ekos/mount/mount.ui
@@ -0,0 +1,556 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Mount</class>
+ <widget class="QWidget" name="Mount">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>505</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="LeftLayout">
+ <item>
+ <widget class="QGroupBox" name="primaryScopeGroup">
+ <property name="title">
+ <string>Primary Telescope</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Aperture (mm):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QDoubleSpinBox" name="primaryScopeApertureIN">
+ <property name="minimum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>100000.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>10.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Focal Length (mm)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDoubleSpinBox" name="primaryScopeFocalIN">
+ <property name="minimum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>100000.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>10.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>RA:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="raOUT">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>DEC:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3">
+ <widget class="QLineEdit" name="decOUT">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Az:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="azOUT">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Alt:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QLineEdit" name="altOUT">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>HA:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="haOUT">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>LST</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3">
+ <widget class="QLineEdit" name="lstOUT">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="guideScopeGroup">
+ <property name="title">
+ <string>Guide Telescope</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Aperture (mm):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QDoubleSpinBox" name="guideScopeApertureIN">
+ <property name="minimum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>100000.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>10.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Focal Length (mm)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDoubleSpinBox" name="guideScopeFocalIN">
+ <property name="minimum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>100000.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>10.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="BottomLayout">
+ <item>
+ <widget class="QPushButton" name="saveB">
+ <property name="toolTip">
+ <string>Save telescope information in configuration file</string>
+ </property>
+ <property name="text">
+ <string>Save Telescope Info</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="parkB">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Park</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="unparkB">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>UnPark</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Motion</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item row="2" column="0">
+ <widget class="QPushButton" name="southwestB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="stopB">
+ <property name="minimumSize">
+ <size>
+ <width>50</width>
+ <height>50</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2">
+ <widget class="QPushButton" name="southeastB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QPushButton" name="southB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="northeastB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="eastB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QPushButton" name="northwestB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QPushButton" name="northB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="westB">
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QComboBox" name="slewSpeedCombo">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Slew speed</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="LimitGroup">
+ <property name="title">
+ <string>Limits</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="minAltLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Minimum telescope altitude limit. If the telescope is below this limit, it will be commanded to stop.</string>
+ </property>
+ <property name="text">
+ <string>Min. Alt:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QDoubleSpinBox" name="minAltLimit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimum">
+ <double>-10.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>90.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="maxAltLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum telescope altitude limit. If the telescope is above this limit, it will be commanded to stop.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Max. Alt:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDoubleSpinBox" name="maxAltLimit">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <double>90.000000000000000</double>
+ </property>
+ <property name="value">
+ <double>90.000000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QCheckBox" name="enableLimitsCheck">
+ <property name="text">
+ <string>Enable Limits</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>13</width>
+ <height>13</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="BottomSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ <zorder></zorder>
+ <zorder>BottomSpacer</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>