]> vaikene.ee Git - evaf/blob - src/apps/ScosTime/gui.cpp
Warning fixes and copyright update.
[evaf] / src / apps / ScosTime / gui.cpp
1 /**
2 * @file ScosTime/gui.cpp
3 * @brief GUI for the ScosTime application
4 * @author Enar Vaikene
5 *
6 * Copyright (c) 2012-2019 Enar Vaikene
7 *
8 * This file is part of the eVaf C++ cross-platform application development framework.
9 *
10 * This file can be used under the terms of the GNU General Public License
11 * version 3.0 as published by the Free Software Foundation and appearing in
12 * the file LICENSE included in the packaging of this file. Please review the
13 * the following information to ensure the GNU General Public License version
14 * 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
15 *
16 * Alternatively, this file may be used in accordance with the Commercial License
17 * Agreement provided with the Software.
18 */
19
20 #include "gui.h"
21
22 #include <Common/Globals>
23 #include <Common/iLogger>
24 #include <Common/iRegistry>
25 #include <SdiWindow/iSdiWindow>
26 #include <Gui/Panel>
27
28 #include <QtWidgets>
29
30
31 VER_EXPORT_VERSION_INFO()
32
33
34 //-------------------------------------------------------------------
35
36 using namespace eVaf;
37 using namespace eVaf::ScosTime;
38
39
40 //-------------------------------------------------------------------
41
42 Internal::DateTime::DateTime()
43 : mType(Invalid)
44 , mEpoch(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC))
45 , mRxIso(new QRegExp("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(:\\d{2}(\\.\\d{3})?)?$"))
46 , mRxAsd(new QRegExp("^\\d{4}\\.\\d{3}\\.\\d{2}\\.\\d{2}(\\.\\d{2}(\\.\\d{3})?)?$"))
47 , mRxCUC(new QRegExp("^[0-9a-f]{8}([0-9a-f]{4})?$", Qt::CaseInsensitive))
48 {}
49
50 Internal::DateTime::~DateTime()
51 {
52 delete mRxCUC;
53 delete mRxAsd;
54 delete mRxIso;
55 }
56
57 Internal::DateTime::Type Internal::DateTime::setDateTime(QString const & s, QDateTime const & epoch)
58 {
59 mEpoch = epoch;
60 return setDateTime(s);
61 }
62
63 Internal::DateTime::Type Internal::DateTime::setDateTime(QString const & s)
64 {
65 // Detect the type of the date/time string
66 mType = getDateTimeType(s);
67 if (mType == Invalid)
68 {
69 return mType;
70 }
71
72 // Convert the string to a date/time value
73 mDateTime = strToDateTime(s, mType);
74 if (!mDateTime.isValid())
75 {
76 mType = Invalid;
77 }
78
79
80 return mType;
81 }
82
83 void Internal::DateTime::setEpoch(QDateTime const & epoch)
84 {
85 if (!epoch.isValid())
86 {
87 return;
88 }
89
90 if (epoch != mEpoch)
91 {
92 // Adjust the date/time if the value was set from a CUC HEX string
93 if (mType == CUC && mDateTime.isValid())
94 {
95 qint64 diff = mEpoch.msecsTo(epoch);
96 mDateTime = mDateTime.addMSecs(diff);
97 }
98 mEpoch = epoch;
99 }
100 }
101
102 Internal::DateTime::Type Internal::DateTime::getDateTimeType(QString const & s) const
103 {
104 if (mRxIso->exactMatch(s))
105 {
106 return ISO;
107 }
108 else if (mRxAsd->exactMatch(s))
109 {
110 return ASD;
111 }
112 else if (mRxCUC->exactMatch(s))
113 {
114 return CUC;
115 }
116 return Invalid;
117 }
118
119 QDateTime Internal::DateTime::strToDateTime(QString const & s, Type type) const
120 {
121 switch (type)
122 {
123 case ASD:
124 {
125 // Using the yyyy.ddd.hh.mm.ss[.zzz] format
126 QStringList tok = s.split(QChar('.'));
127 if (tok.size() < 4)
128 {
129 return QDateTime();
130 }
131
132 bool ok = false;
133 int year = tok.at(0).toInt(&ok);
134 if (!ok)
135 {
136 return QDateTime();
137 }
138 int days = tok.at(1).toInt(&ok);
139 if (!ok)
140 {
141 return QDateTime();
142 }
143 int hours = tok.at(2).toInt(&ok);
144 if (!ok)
145 {
146 return QDateTime();
147 }
148 int minutes = tok.at(3).toInt(&ok);
149 if (!ok)
150 {
151 return QDateTime();
152 }
153 int secs = 0;
154 int msecs = 0;
155 if (tok.size() > 4)
156 {
157 secs = tok.at(4).toInt(&ok);
158 if (!ok)
159 {
160 return QDateTime();
161 }
162 if (tok.size() > 5)
163 {
164 msecs = tok.at(5).toInt(&ok);
165 if (!ok)
166 {
167 return QDateTime();
168 }
169 }
170 }
171
172 QDate dt(year, 1, 1);
173 dt = dt.addDays(days - 1);
174
175 return QDateTime(dt, QTime(hours, minutes, secs, msecs), Qt::UTC);
176 }
177 case ISO:
178 {
179 // Using the ISO format yyyy-MM-ddThh:mm:ss[.zzz]
180 QString tmp = s;
181 if (tmp.length() < 19)
182 {
183 tmp += ":00";
184 }
185 QDateTime dt = QDateTime::fromString(tmp, Qt::ISODate);
186 dt.setTimeSpec(Qt::UTC);
187 return dt;
188 }
189 case CUC:
190 {
191 // Get the CUC coarse and fine values
192 bool ok = false;
193 int const coarse = static_cast<int>(s.left(8).toLong(&ok, 16));
194 if (!ok)
195 {
196 return QDateTime();
197 }
198 int fine = 0;
199 if (s.size() == 12)
200 {
201 fine = static_cast<int>(s.mid(8, 4).toLong(&ok, 16));
202 if (!ok)
203 {
204 return QDateTime();
205 }
206 }
207
208 // Get the date/time value
209 QDateTime tm = mEpoch.addSecs(coarse);
210 tm = tm.addMSecs(static_cast<int>(rint((double(fine) / 58.0 * 885.0) / 1000.0)));
211 return tm;
212 }
213 default:
214 {
215 return QDateTime();
216 }
217 }
218 }
219
220 QString Internal::DateTime::asISOstring() const
221 {
222 if (mDateTime.isValid())
223 {
224 return mDateTime.toString("yyyy-MM-ddThh:mm:ss.zzz");
225 }
226 return QString();
227 }
228
229 QString Internal::DateTime::asASDstring() const
230 {
231 if (mDateTime.isValid())
232 {
233 return QString("%1.%2.%3.%4.%5.%6")
234 .arg(mDateTime.date().year(), 4, 10, QChar('0'))
235 .arg(mDateTime.date().dayOfYear(), 3, 10, QChar('0'))
236 .arg(mDateTime.time().hour(), 2, 10, QChar('0'))
237 .arg(mDateTime.time().minute(), 2, 10, QChar('0'))
238 .arg(mDateTime.time().second(), 2, 10, QChar('0'))
239 .arg(mDateTime.time().msec(), 3, 10, QChar('0'));
240 }
241 return QString();
242 }
243
244 QString Internal::DateTime::asCUChexString() const
245 {
246 if (!mDateTime.isValid())
247 {
248 return QString();
249 }
250
251 // Convert to CUC coarse and fine values
252 qint64 msecs = mEpoch.msecsTo(mDateTime);
253 quint32 coarse = quint32(msecs / 1000);
254 quint32 fine = quint32(rint(1000.0 * double(msecs % 1000) * 58.0 / 885.0));
255
256 // Set the CUC hex string
257 return QString("%1%2").arg(coarse, 8, 16, QChar('0')).arg(fine, 4, 16, QChar('0'));
258 }
259
260
261 //-------------------------------------------------------------------
262
263 Module::Module()
264 : Plugins::iPlugin()
265 , mReady(false)
266 , mLastDateTimeType(Internal::DateTime::Invalid)
267 {
268 setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
269
270 EVAF_INFO("%s created", qPrintable(objectName()));
271 }
272
273 Module::~Module()
274 {
275 EVAF_INFO("%s destroyed", qPrintable(objectName()));
276 }
277
278 bool Module::init(QString const & args)
279 {
280 Q_UNUSED(args)
281
282 // Get the main window interface and fill it with the widgets
283 SdiWindow::iSdiWindow * win = evafQueryInterface<SdiWindow::iSdiWindow>("iSdiWindow");
284 EVAF_TEST_X(win, "No iSdiWindow interface")
285
286 Gui::Panel * panel = new Gui::Panel;
287 win->addPanel("PswGen", panel);
288
289 QVBoxLayout * v = new QVBoxLayout;
290 panel->setLayout(v);
291
292 QGridLayout * g = new QGridLayout;
293 v->addLayout(g);
294 g->setColumnStretch(1, 2);
295
296 QLabel * l = new QLabel(tr("&Epoch:", VER_MODULE_NAME_STR));
297 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
298 g->addWidget(l, 0, 0);
299
300 wEpoch = new QComboBox;
301 l->setBuddy(wEpoch);
302 wEpoch->setEditable(true);
303 {
304 QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$");
305 wEpoch->setValidator(new QRegExpValidator(rx, wEpoch));
306 }
307 wEpoch->addItems(QStringList() << "1970-01-01T00:00:00.000" << "1999-08-22T00:00:00.000");
308 connect(wEpoch, SIGNAL(editTextChanged(QString)), this, SLOT(epochChanged(QString)));
309 g->addWidget(wEpoch, 0, 1);
310 panel->setFocusProxy(wEpoch);
311
312 l = new QLabel(tr("&Date/time:", VER_MODULE_NAME_STR));
313 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
314 g->addWidget(l, 1, 0);
315
316 wDateTime = new QLineEdit;
317 l->setBuddy(wDateTime);
318 {
319 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})?)$");
320 wDateTime->setValidator(new QRegExpValidator(rx, wDateTime));
321 }
322 connect(wDateTime, SIGNAL(textEdited(QString)), this, SLOT(dateTimeEdited(QString)));
323 g->addWidget(wDateTime, 1, 1);
324
325 QPushButton * btn = new QPushButton();
326 btn->setDisabled(true);
327 g->addWidget(btn, 1, 2);
328 connect(btn, SIGNAL(clicked()), this, SLOT(dateTimeClicked()));
329 wConvertDateTime = btn;
330
331 l = new QLabel(tr("&CUC:", VER_MODULE_NAME_STR));
332 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
333 g->addWidget(l, 2, 0);
334
335 wCucHex = new QLineEdit;
336 l->setBuddy(wCucHex);
337 wCucHex->setMaxLength(12);
338 {
339 QRegExp rx("^[0-9a-f]{8}([0-9a-f]{4})?$", Qt::CaseInsensitive);
340 wCucHex->setValidator(new QRegExpValidator(rx, wCucHex));
341 }
342 connect(wCucHex, SIGNAL(textEdited(QString)), this, SLOT(cucHexEdited(QString)));
343 g->addWidget(wCucHex, 2, 1);
344
345 v->addStretch();
346
347 QHBoxLayout * h = new QHBoxLayout;
348 h->addStretch();
349 v->addLayout(h);
350
351 QAction * a = new QAction(panel);
352 a->setShortcut(Qt::Key_Escape);
353 connect(a, SIGNAL(triggered()), qApp, SLOT(quit()));
354 panel->addAction(a);
355
356 mReady = true;
357
358 EVAF_INFO("%s initialized", qPrintable(objectName()));
359
360 return true;
361 }
362
363 void Module::done()
364 {
365 mReady = false;
366
367 EVAF_INFO("%s finalized", qPrintable(objectName()));
368 }
369
370 void Module::dateTimeClicked()
371 {
372 if (!mDateTime.isValid())
373 {
374 return;
375 }
376
377 // Convert to another type
378 switch (mLastDateTimeType)
379 {
380 case Internal::DateTime::ISO:
381 {
382 mLastDateTimeType = Internal::DateTime::ASD;
383 wDateTime->setText(mDateTime.asASDstring());
384 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
385 break;
386 }
387 case Internal::DateTime::ASD:
388 {
389 mLastDateTimeType = Internal::DateTime::ISO;
390 wDateTime->setText(mDateTime.asISOstring());
391 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
392 break;
393 }
394 default:
395 break;
396 }
397 }
398
399 void Module::dateTimeEdited(QString const & s)
400 {
401 wConvertDateTime->setDisabled(true);
402 wConvertDateTime->setText(QString());
403 mLastDateTimeType = Internal::DateTime::Invalid;
404
405 if (s.isEmpty())
406 {
407 return;
408 }
409
410 mDateTime.setDateTime(s);
411 if (!mDateTime.isValid())
412 {
413 return;
414 }
415
416 mLastDateTimeType = mDateTime.type();
417
418 // Set the CUC hex string from this date/time string
419 wCucHex->setText(mDateTime.asCUChexString());
420
421 // Enable the button that converts between ISO and ASD date/time strings
422 if (mDateTime.type() == Internal::DateTime::ISO)
423 {
424 wConvertDateTime->setEnabled(true);
425 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
426 }
427 else if (mDateTime.type() == Internal::DateTime::ASD)
428 {
429 wConvertDateTime->setEnabled(true);
430 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
431 }
432 }
433
434 void Module::cucHexEdited(QString const & s)
435 {
436 if (s.isEmpty() || s.size() < 8)
437 {
438 return;
439 }
440
441 mDateTime.setDateTime(s);
442 if (!mDateTime.isValid())
443 {
444 return;
445 }
446
447 if (mLastDateTimeType == Internal::DateTime::Invalid)
448 {
449 mLastDateTimeType = Internal::DateTime::ASD;
450 }
451
452 // Set the date/time string in the last used format
453 if (mLastDateTimeType == Internal::DateTime::ASD)
454 {
455 wDateTime->setText(mDateTime.asASDstring());
456 wConvertDateTime->setEnabled(true);
457 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
458 }
459 else if (mLastDateTimeType == Internal::DateTime::ISO)
460 {
461 wDateTime->setText(mDateTime.asISOstring());
462 wConvertDateTime->setEnabled(true);
463 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
464 }
465 }
466
467 void Module::epochChanged(QString const & s)
468 {
469 if (s.isEmpty())
470 return;
471 QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$");
472 if (!rx.exactMatch(s))
473 return;
474
475 QDateTime dt = QDateTime::fromString(s, Qt::ISODate);
476 dt.setTimeSpec(Qt::UTC);
477 mDateTime.setEpoch(dt);
478
479 // If there is a valid entry, do the conversion
480 switch (mDateTime.type())
481 {
482 case Internal::DateTime::ISO:
483 case Internal::DateTime::ASD:
484 {
485 wCucHex->setText(mDateTime.asCUChexString());
486 break;
487 }
488 case Internal::DateTime::CUC:
489 {
490 if (mLastDateTimeType == Internal::DateTime::ASD)
491 {
492 wDateTime->setText(mDateTime.asASDstring());
493 }
494 else if (mLastDateTimeType == Internal::DateTime::ISO)
495 {
496 wDateTime->setText(mDateTime.asISOstring());
497 }
498 break;
499 }
500 default:
501 break;
502 }
503 }