/** * @file ScosTime/gui.cpp * @brief GUI for the ScosTime application * @author Enar Vaikene * * Copyright (c) 2012-2019 Enar Vaikene * * This file is part of the eVaf C++ cross-platform application development framework. * * This file can be used under the terms of the GNU General Public License * version 3.0 as published by the Free Software Foundation and appearing in * the file LICENSE included in the packaging of this file. Please review the * the following information to ensure the GNU General Public License version * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html. * * Alternatively, this file may be used in accordance with the Commercial License * Agreement provided with the Software. */ #include "gui.h" #include #include #include #include #include #include VER_EXPORT_VERSION_INFO() //------------------------------------------------------------------- using namespace eVaf; using namespace eVaf::ScosTime; //------------------------------------------------------------------- Internal::DateTime::DateTime() : mType(Invalid) , mEpoch(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)) , mRxIso(new QRegExp("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{3})?)?$")) , mRxAsd(new QRegExp("^\\d{4}\\.\\d{3}\\.\\d{2}\\.\\d{2}(\\.\\d{2}(\\.\\d{3})?)?$")) , mRxCUC(new QRegExp("^[0-9a-f]{8}([0-9a-f]{4})?$", Qt::CaseInsensitive)) {} Internal::DateTime::~DateTime() { delete mRxCUC; delete mRxAsd; delete mRxIso; } Internal::DateTime::Type Internal::DateTime::setDateTime(QString const & s, QDateTime const & epoch) { mEpoch = epoch; return setDateTime(s); } Internal::DateTime::Type Internal::DateTime::setDateTime(QString const & s) { // Detect the type of the date/time string mType = getDateTimeType(s); if (mType == Invalid) { return mType; } // Convert the string to a date/time value mDateTime = strToDateTime(s, mType); if (!mDateTime.isValid()) { mType = Invalid; } return mType; } void Internal::DateTime::setEpoch(QDateTime const & epoch) { if (!epoch.isValid()) { return; } if (epoch != mEpoch) { // Adjust the date/time if the value was set from a CUC HEX string if (mType == CUC && mDateTime.isValid()) { qint64 diff = mEpoch.msecsTo(epoch); mDateTime = mDateTime.addMSecs(diff); } mEpoch = epoch; } } Internal::DateTime::Type Internal::DateTime::getDateTimeType(QString const & s) const { if (mRxIso->exactMatch(s)) { return ISO; } else if (mRxAsd->exactMatch(s)) { return ASD; } else if (mRxCUC->exactMatch(s)) { return CUC; } return Invalid; } QDateTime Internal::DateTime::strToDateTime(QString const & s, Type type) const { switch (type) { case ASD: { // Using the yyyy.ddd.hh.mm.ss[.zzz] format QStringList tok = s.split(QChar('.')); if (tok.size() < 4) { return QDateTime(); } bool ok = false; int year = tok.at(0).toInt(&ok); if (!ok) { return QDateTime(); } int days = tok.at(1).toInt(&ok); if (!ok) { return QDateTime(); } int hours = tok.at(2).toInt(&ok); if (!ok) { return QDateTime(); } int minutes = tok.at(3).toInt(&ok); if (!ok) { return QDateTime(); } int secs = 0; int msecs = 0; if (tok.size() > 4) { secs = tok.at(4).toInt(&ok); if (!ok) { return QDateTime(); } if (tok.size() > 5) { msecs = tok.at(5).toInt(&ok); if (!ok) { return QDateTime(); } } } QDate dt(year, 1, 1); dt = dt.addDays(days - 1); return QDateTime(dt, QTime(hours, minutes, secs, msecs), Qt::UTC); } case ISO: { // Using the ISO format yyyy-MM-ddThh:mm:ss[.zzz] QString tmp = s; if (tmp.length() < 19) { tmp += ":00"; } QDateTime dt = QDateTime::fromString(tmp, Qt::ISODate); dt.setTimeSpec(Qt::UTC); return dt; } case CUC: { // Get the CUC coarse and fine values bool ok = false; int const coarse = static_cast(s.left(8).toLong(&ok, 16)); if (!ok) { return QDateTime(); } int fine = 0; if (s.size() == 12) { fine = static_cast(s.mid(8, 4).toLong(&ok, 16)); if (!ok) { return QDateTime(); } } // Get the date/time value QDateTime tm = mEpoch.addSecs(coarse); tm = tm.addMSecs(static_cast(rint((double(fine) / 58.0 * 885.0) / 1000.0))); return tm; } default: { return QDateTime(); } } } QString Internal::DateTime::asISOstring() const { if (mDateTime.isValid()) { return mDateTime.toString("yyyy-MM-ddThh:mm:ss.zzz"); } return QString(); } QString Internal::DateTime::asASDstring() const { if (mDateTime.isValid()) { return QString("%1.%2.%3.%4.%5.%6") .arg(mDateTime.date().year(), 4, 10, QChar('0')) .arg(mDateTime.date().dayOfYear(), 3, 10, QChar('0')) .arg(mDateTime.time().hour(), 2, 10, QChar('0')) .arg(mDateTime.time().minute(), 2, 10, QChar('0')) .arg(mDateTime.time().second(), 2, 10, QChar('0')) .arg(mDateTime.time().msec(), 3, 10, QChar('0')); } return QString(); } QString Internal::DateTime::asCUChexString() const { if (!mDateTime.isValid()) { return QString(); } // Convert to CUC coarse and fine values qint64 msecs = mEpoch.msecsTo(mDateTime); quint32 coarse = quint32(msecs / 1000); quint32 fine = quint32(rint(1000.0 * double(msecs % 1000) * 58.0 / 885.0)); // Set the CUC hex string return QString("%1%2").arg(coarse, 8, 16, QChar('0')).arg(fine, 4, 16, QChar('0')); } //------------------------------------------------------------------- Module::Module() : Plugins::iPlugin() , mReady(false) , mLastDateTimeType(Internal::DateTime::Invalid) { setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__)); EVAF_INFO("%s created", qPrintable(objectName())); } Module::~Module() { EVAF_INFO("%s destroyed", qPrintable(objectName())); } bool Module::init(QString const & args) { Q_UNUSED(args) // Get the main window interface and fill it with the widgets SdiWindow::iSdiWindow * win = evafQueryInterface("iSdiWindow"); EVAF_TEST_X(win, "No iSdiWindow interface") Gui::Panel * panel = new Gui::Panel; win->addPanel("PswGen", panel); QVBoxLayout * v = new QVBoxLayout; panel->setLayout(v); QGridLayout * g = new QGridLayout; v->addLayout(g); g->setColumnStretch(1, 2); QLabel * l = new QLabel(tr("&Epoch:", VER_MODULE_NAME_STR)); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); g->addWidget(l, 0, 0); wEpoch = new QComboBox; l->setBuddy(wEpoch); wEpoch->setEditable(true); { QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$"); wEpoch->setValidator(new QRegExpValidator(rx, wEpoch)); } wEpoch->addItems(QStringList() << "1970-01-01T00:00:00.000" << "1999-08-22T00:00:00.000"); connect(wEpoch, SIGNAL(editTextChanged(QString)), this, SLOT(epochChanged(QString))); g->addWidget(wEpoch, 0, 1); panel->setFocusProxy(wEpoch); l = new QLabel(tr("&Date/time:", VER_MODULE_NAME_STR)); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); g->addWidget(l, 1, 0); wDateTime = new QLineEdit; l->setBuddy(wDateTime); { QRegExp rx("^(\\d{4}\\.\\d{3}\\.\\d{2}\\.\\d{2}\\.\\d{2}(\\.\\d{3})?)|(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(.\\d{3})?)$"); wDateTime->setValidator(new QRegExpValidator(rx, wDateTime)); } connect(wDateTime, SIGNAL(textEdited(QString)), this, SLOT(dateTimeEdited(QString))); g->addWidget(wDateTime, 1, 1); QPushButton * btn = new QPushButton(); btn->setDisabled(true); g->addWidget(btn, 1, 2); connect(btn, SIGNAL(clicked()), this, SLOT(dateTimeClicked())); wConvertDateTime = btn; l = new QLabel(tr("&CUC:", VER_MODULE_NAME_STR)); l->setAlignment(Qt::AlignRight | Qt::AlignVCenter); g->addWidget(l, 2, 0); wCucHex = new QLineEdit; l->setBuddy(wCucHex); wCucHex->setMaxLength(12); { QRegExp rx("^[0-9a-f]{8}([0-9a-f]{4})?$", Qt::CaseInsensitive); wCucHex->setValidator(new QRegExpValidator(rx, wCucHex)); } connect(wCucHex, SIGNAL(textEdited(QString)), this, SLOT(cucHexEdited(QString))); g->addWidget(wCucHex, 2, 1); v->addStretch(); QHBoxLayout * h = new QHBoxLayout; h->addStretch(); v->addLayout(h); QAction * a = new QAction(panel); a->setShortcut(Qt::Key_Escape); connect(a, SIGNAL(triggered()), qApp, SLOT(quit())); panel->addAction(a); mReady = true; EVAF_INFO("%s initialized", qPrintable(objectName())); return true; } void Module::done() { mReady = false; EVAF_INFO("%s finalized", qPrintable(objectName())); } void Module::dateTimeClicked() { if (!mDateTime.isValid()) { return; } // Convert to another type switch (mLastDateTimeType) { case Internal::DateTime::ISO: { mLastDateTimeType = Internal::DateTime::ASD; wDateTime->setText(mDateTime.asASDstring()); wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); break; } case Internal::DateTime::ASD: { mLastDateTimeType = Internal::DateTime::ISO; wDateTime->setText(mDateTime.asISOstring()); wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR)); break; } default: break; } } void Module::dateTimeEdited(QString const & s) { wConvertDateTime->setDisabled(true); wConvertDateTime->setText(QString()); mLastDateTimeType = Internal::DateTime::Invalid; if (s.isEmpty()) { return; } mDateTime.setDateTime(s); if (!mDateTime.isValid()) { return; } mLastDateTimeType = mDateTime.type(); // Set the CUC hex string from this date/time string wCucHex->setText(mDateTime.asCUChexString()); // Enable the button that converts between ISO and ASD date/time strings if (mDateTime.type() == Internal::DateTime::ISO) { wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR)); } else if (mDateTime.type() == Internal::DateTime::ASD) { wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); } } void Module::cucHexEdited(QString const & s) { if (s.isEmpty() || s.size() < 8) { return; } mDateTime.setDateTime(s); if (!mDateTime.isValid()) { return; } if (mLastDateTimeType == Internal::DateTime::Invalid) { mLastDateTimeType = Internal::DateTime::ASD; } // Set the date/time string in the last used format if (mLastDateTimeType == Internal::DateTime::ASD) { wDateTime->setText(mDateTime.asASDstring()); wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); } else if (mLastDateTimeType == Internal::DateTime::ISO) { wDateTime->setText(mDateTime.asISOstring()); wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR)); } } void Module::epochChanged(QString const & s) { if (s.isEmpty()) return; QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$"); if (!rx.exactMatch(s)) return; QDateTime dt = QDateTime::fromString(s, Qt::ISODate); dt.setTimeSpec(Qt::UTC); mDateTime.setEpoch(dt); // If there is a valid entry, do the conversion switch (mDateTime.type()) { case Internal::DateTime::ISO: case Internal::DateTime::ASD: { wCucHex->setText(mDateTime.asCUChexString()); break; } case Internal::DateTime::CUC: { if (mLastDateTimeType == Internal::DateTime::ASD) { wDateTime->setText(mDateTime.asASDstring()); } else if (mLastDateTimeType == Internal::DateTime::ISO) { wDateTime->setText(mDateTime.asISOstring()); } break; } default: break; } }