From 125303c933569fe238a087e5f24128ff2cb30e0a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Enar=20V=C3=A4ikene?= Date: Tue, 10 Sep 2013 14:49:04 +0300 Subject: [PATCH] The ScosTime application now more user friendly. --- src/apps/ScosTime/gui.cpp | 467 +++++++++++++++++++++++++------------- src/apps/ScosTime/gui.h | 117 +++++++--- 2 files changed, 388 insertions(+), 196 deletions(-) diff --git a/src/apps/ScosTime/gui.cpp b/src/apps/ScosTime/gui.cpp index 6efd962..ed7f098 100644 --- a/src/apps/ScosTime/gui.cpp +++ b/src/apps/ScosTime/gui.cpp @@ -41,9 +41,225 @@ using namespace eVaf::ScosTime; //------------------------------------------------------------------- -Internal::DateTime::DateTime(QString const & s, QString const & epoch) +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) + { + if (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); + break; + } + 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; + break; + } + case CUC: + { + // Get the CUC coarse and fine values + bool ok = false; + int coarse = s.left(8).toLong(&ok, 16); + if (!ok) + { + return QDateTime(); + } + int fine = 0; + if (s.size() == 12) + { + fine = s.mid(8, 4).toLong(&ok, 16); + if (!ok) + { + return QDateTime(); + } + } + + // Get the date/time value + QDateTime tm = mEpoch.addSecs(coarse); + tm = tm.addMSecs(rint((double(fine) / 58.0 * 885.0) / 1000.0)); + return tm; + + break; + } + 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')); } @@ -52,20 +268,15 @@ Internal::DateTime::DateTime(QString const & s, QString const & epoch) Module::Module() : Plugins::iPlugin() , mReady(false) - , mLastValidEntry(NoValidEntry) + , mLastDateTimeType(Internal::DateTime::Invalid) { setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__)); - rxIsoDateTime = new QRegExp("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(.\\d{3})?)?$"); - rxAsdDateTime = new QRegExp("^\\d{4}\\.\\d{3}\\.\\d{2}\\.\\d{2}(\\.\\d{2}(\\.\\d{3})?)?$"); - EVAF_INFO("%s created", qPrintable(objectName())); } Module::~Module() { - delete rxIsoDateTime; - delete rxAsdDateTime; EVAF_INFO("%s destroyed", qPrintable(objectName())); } @@ -94,7 +305,10 @@ bool Module::init(QString const & args) wEpoch = new QComboBox; l->setBuddy(wEpoch); wEpoch->setEditable(true); - wEpoch->setValidator(new QRegExpValidator(*rxIsoDateTime, wEpoch)); + { + 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); @@ -106,8 +320,10 @@ bool Module::init(QString const & args) wDateTime = new QLineEdit; l->setBuddy(wDateTime); - QRegExp rxDateTime("^(\\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(rxDateTime, 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); @@ -124,7 +340,10 @@ bool Module::init(QString const & args) wCucHex = new QLineEdit; l->setBuddy(wCucHex); wCucHex->setMaxLength(12); - wCucHex->setInputMask(">HHHHHHHHhhhh"); + { + 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); @@ -153,125 +372,27 @@ void Module::done() EVAF_INFO("%s finalized", qPrintable(objectName())); } -Module::DateTimeType Module::getDateTimeType(QString const & s) const -{ - if (rxIsoDateTime->exactMatch(s)) - return IsoDateTime; - else if (rxAsdDateTime->exactMatch(s)) - return AsdDateTime; - else - return InvalidDateTime; -} - -QDateTime Module::strToDateTime(QString const & s, DateTimeType type) const +void Module::dateTimeClicked() { - switch (type) + if (!mDateTime.isValid()) { - case AsdDateTime: - { - // 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); - break; - } - case IsoDateTime: - { - // Using the ISO format yyyy-MM-ddThh:mm:ss[.zzz] - QDateTime dt = QDateTime::fromString(s, Qt::ISODate); - dt.setTimeSpec(Qt::UTC); - return dt; - break; - } - default: - return QDateTime(); + return; } -} - -QString Module::dateTimeToAsdStr(QDateTime const & tm) const -{ - return QString("%1.%2.%3.%4.%5.%6") - .arg(tm.date().year(), 4, 10, QChar('0')) - .arg(tm.date().dayOfYear(), 3, 10, QChar('0')) - .arg(tm.time().hour(), 2, 10, QChar('0')) - .arg(tm.time().minute(), 2, 10, QChar('0')) - .arg(tm.time().second(), 2, 10, QChar('0')) - .arg(tm.time().msec(), 3, 10, QChar('0')); -} - -void Module::setDateTimeFromCucHex(QString const & s) -{ - -} - -void Module::setCucHexFromDateTime(QString const & s, DateTimeType type) -{ - // Get the epoch - QDateTime epoch = QDateTime::fromString(wEpoch->currentText(), Qt::ISODate); - epoch.setTimeSpec(Qt::UTC); - - // Convert the date/time string to a QDateTime type - QDateTime tm = strToDateTime(s, type); - - // Convert to CUC coarse and fine values - qint64 msecs = epoch.msecsTo(tm); - quint32 coarse = quint32(msecs / 1000); - quint32 fine = quint32(rint(1000.0 * double(msecs % 1000) * 58.0 / 885.0)); - - // Set the CUC hex string - wCucHex->setText(QString("%1%2").arg(coarse, 8, 16, QChar('0')).arg(fine, 4, 16, QChar('0'))); -} - -void Module::dateTimeClicked() -{ - // Get the date/time string, type and QDateTime value - QString s = wDateTime->text(); - DateTimeType type = getDateTimeType(s); - QDateTime tm = strToDateTime(s, type); // Convert to another type - switch (type) + switch (mLastDateTimeType) { - case IsoDateTime: + case Internal::DateTime::ISO: { - wDateTime->setText(dateTimeToAsdStr(tm)); + mLastDateTimeType = Internal::DateTime::ASD; + wDateTime->setText(mDateTime.asASDstring()); wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); break; } - case AsdDateTime: + case Internal::DateTime::ASD: { - wDateTime->setText(tm.toString("yyyy-MM-ddThh:mm:ss.zzz")); + mLastDateTimeType = Internal::DateTime::ISO; + wDateTime->setText(mDateTime.asISOstring()); wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR)); break; } @@ -282,31 +403,34 @@ void Module::dateTimeClicked() void Module::dateTimeEdited(QString const & s) { - if (mLastValidEntry == DateTimeEntry) - mLastValidEntry = NoValidEntry; wConvertDateTime->setDisabled(true); wConvertDateTime->setText(QString()); + mLastDateTimeType = Internal::DateTime::Invalid; if (s.isEmpty()) + { return; + } - // Detect the type of the date/time string - DateTimeType type = getDateTimeType(s); - if (type == InvalidDateTime) + mDateTime.setDateTime(s); + if (!mDateTime.isValid()) + { return; + } - // Set the date/time field as the last valid entry done by the user - mLastValidEntry = DateTimeEntry; + mLastDateTimeType = mDateTime.type(); // Set the CUC hex string from this date/time string - setCucHexFromDateTime(s); + wCucHex->setText(mDateTime.asCUChexString()); // Enable the button that converts between ISO and ASD date/time strings - if (type == IsoDateTime) { + if (mDateTime.type() == Internal::DateTime::ISO) + { wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR)); } - else if (type == AsdDateTime) { + else if (mDateTime.type() == Internal::DateTime::ISO) + { wConvertDateTime->setEnabled(true); wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); } @@ -314,56 +438,71 @@ void Module::dateTimeEdited(QString const & s) void Module::cucHexEdited(QString const & s) { - if (mLastValidEntry == CUCEntry) - mLastValidEntry = NoValidEntry; if (s.isEmpty() || s.size() < 8) + { return; + } - // Get the CUC coarse and fine values - bool ok = false; - int coarse = s.left(8).toLong(&ok, 16); - if (!ok) - return; - int fine = 0; - if (s.size() == 12) - fine = s.mid(8, 4).toLong(&ok, 16); - if (!ok) + mDateTime.setDateTime(s); + if (!mDateTime.isValid()) + { return; + } - // Set the CUC field as the last valid entry done by the user - mLastValidEntry = CUCEntry; - - // Get the epoch - QDateTime epoch = QDateTime::fromString(wEpoch->currentText(), Qt::ISODate); - epoch.setTimeSpec(Qt::UTC); - - // Get the date/time value - QDateTime tm = epoch.addSecs(coarse); - tm = tm.addMSecs(rint((double(fine) / 58.0 * 885.0) / 1000.0)); - - // Set the date/time string in ASD format - wDateTime->setText(dateTimeToAsdStr(tm)); + if (mLastDateTimeType == Internal::DateTime::Invalid) + { + mLastDateTimeType = Internal::DateTime::ASD; + } - // Enable conversion to ISO format - wConvertDateTime->setEnabled(true); - wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR)); + // 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; - if (!rxIsoDateTime->exactMatch(s)) + 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 (mLastValidEntry) + switch (mDateTime.type()) { - case DateTimeEntry: - break; - case CUCEntry: - break; - default: - break; + 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; } } diff --git a/src/apps/ScosTime/gui.h b/src/apps/ScosTime/gui.h index 90f33c2..1ce7972 100644 --- a/src/apps/ScosTime/gui.h +++ b/src/apps/ScosTime/gui.h @@ -43,15 +43,30 @@ class DateTime { public: + /// Type of the date/time entry + enum Type + { + Invalid, + ASD, + ISO, + CUC + }; + /** - * Creates an invalid date/time value + * Creates an invalid date/time value with the default epoch */ - DateTime() {} + DateTime(); /** - * Creates a date/time value from the string. + * Dtor + */ + ~DateTime(); + + /** + * Sets the date/time value from a string. * @param s Input string * @param epoch Epoch + * @return Type of the input string * * The input string can be: * @li Date/time in ISO format yyyy-MM-ddThh:mm[:ss[.zzz]] @@ -60,37 +75,93 @@ public: * * If the string is invalid, creates an invalid date/time value. */ - DateTime(String const & s, String const & epoch); + Type setDateTime(QString const & s, QDateTime const & epoch); + + /** + * Sets the date/time value from a string using the previously set epoch. + * @param s Input string + * @return Type of the input string + * + * The input string can be: + * @li Date/time in ISO format yyyy-MM-ddThh:mm[:ss[.zzz]] + * @li Date/time in ASD format yyyy.ddd.hh.mm[.ss[.zzz]] + * @li CUC hex string cccccccc[ffff] + * + * If the input string is invalid or no epoch is set, creates an invalid + * date/time value. + */ + Type setDateTime(QString const & s); + + /** + * Sets the epoch + * @param epoch Epoch + */ + void setEpoch(QDateTime const & epoch); + + /** + * Returns the current epoch + */ + QDateTime const & epoch() const { return mEpoch; } /** * Returns true if the date/time value is valid. */ bool isValid() const { return mDateTime.isValid(); } + /** + * Returns the type of the date/time string from which the date/time + * value was created. + */ + Type type() const { return mType; } + + /** + * Returns the current date/time value + */ + QDateTime const & dateTime() const { return mDateTime; } + /** * Returns the date/time value a string in the ISO format yyyy-MM-ddThh:mm:ss.zzz */ - QString asIsoString() const; + QString asISOstring() const; /** * Returns the date/time value as a string in the ASD format yyyy.ddd.hh.mm.ss.zzz */ - QString asAsdString() const; + QString asASDstring() const; /** * Returns the date/time value as a CUC hex string in the format ccccccccffff */ - QString asCucHexString() const; + QString asCUChexString() const; -private: +private: // methods - /// Date/time value - QDateTime mDateTime; + Type getDateTimeType(QString const & s) const; + + QDateTime strToDateTime(QString const & s, Type t) const; + + +private: // members + + /// Type of the input string + Type mType; /// Epoch QDateTime mEpoch; + /// Date/time value + QDateTime mDateTime; + + /// Regular expression for ISO date/time strings + QRegExp * mRxIso; + + /// Regular expression for ASD date/time strings + QRegExp * mRxAsd; + + /// Regular expression for CUC date/time strings + QRegExp * mRxCUC; + }; } // namespace eVaf::ScosTime::Internal @@ -105,13 +176,6 @@ class Module : public Plugins::iPlugin Q_OBJECT Q_INTERFACES(eVaf::Plugins::iPlugin) - enum DateTimeType - { - InvalidDateTime, - AsdDateTime, - IsoDateTime - }; - enum ValidEntry { NoValidEntry, @@ -145,28 +209,17 @@ private slots: private: // Methods - DateTimeType getDateTimeType(QString const & s) const; - - QDateTime strToDateTime(QString const & s, DateTimeType type) const; - - QString dateTimeToAsdStr(QDateTime const & tm) const; - - void setDateTimeFromCucHex(QString const & s); - - void setCucHexFromDateTime(QString const & s, DateTimeType type); - private: // Members /// Flag indicating that the module is ready bool mReady; - /// Last valid entry (field modified by the user) - ValidEntry mLastValidEntry; + /// Current date/time value + Internal::DateTime mDateTime; - /// Regular expressions - QRegExp * rxIsoDateTime; - QRegExp * rxAsdDateTime; + /// Last date/time format type used in the date/time entry field + Internal::DateTime::Type mLastDateTimeType; /// Widgets on the screen QComboBox * wEpoch; -- 2.47.0