]> vaikene.ee Git - evaf/blob - src/apps/ScosTime/gui.cpp
6b4b1163d1278c5ff19852b56fb57600f13c1cb1
[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 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 break;
177 }
178 case ISO:
179 {
180 // Using the ISO format yyyy-MM-ddThh:mm:ss[.zzz]
181 QString tmp = s;
182 if (tmp.length() < 19)
183 {
184 tmp += ":00";
185 }
186 QDateTime dt = QDateTime::fromString(tmp, Qt::ISODate);
187 dt.setTimeSpec(Qt::UTC);
188 return dt;
189 break;
190 }
191 case CUC:
192 {
193 // Get the CUC coarse and fine values
194 bool ok = false;
195 int coarse = s.left(8).toLong(&ok, 16);
196 if (!ok)
197 {
198 return QDateTime();
199 }
200 int fine = 0;
201 if (s.size() == 12)
202 {
203 fine = s.mid(8, 4).toLong(&ok, 16);
204 if (!ok)
205 {
206 return QDateTime();
207 }
208 }
209
210 // Get the date/time value
211 QDateTime tm = mEpoch.addSecs(coarse);
212 tm = tm.addMSecs(rint((double(fine) / 58.0 * 885.0) / 1000.0));
213 return tm;
214
215 break;
216 }
217 default:
218 {
219 return QDateTime();
220 }
221 }
222 }
223
224 QString Internal::DateTime::asISOstring() const
225 {
226 if (mDateTime.isValid())
227 {
228 return mDateTime.toString("yyyy-MM-ddThh:mm:ss.zzz");
229 }
230 return QString();
231 }
232
233 QString Internal::DateTime::asASDstring() const
234 {
235 if (mDateTime.isValid())
236 {
237 return QString("%1.%2.%3.%4.%5.%6")
238 .arg(mDateTime.date().year(), 4, 10, QChar('0'))
239 .arg(mDateTime.date().dayOfYear(), 3, 10, QChar('0'))
240 .arg(mDateTime.time().hour(), 2, 10, QChar('0'))
241 .arg(mDateTime.time().minute(), 2, 10, QChar('0'))
242 .arg(mDateTime.time().second(), 2, 10, QChar('0'))
243 .arg(mDateTime.time().msec(), 3, 10, QChar('0'));
244 }
245 return QString();
246 }
247
248 QString Internal::DateTime::asCUChexString() const
249 {
250 if (!mDateTime.isValid())
251 {
252 return QString();
253 }
254
255 // Convert to CUC coarse and fine values
256 qint64 msecs = mEpoch.msecsTo(mDateTime);
257 quint32 coarse = quint32(msecs / 1000);
258 quint32 fine = quint32(rint(1000.0 * double(msecs % 1000) * 58.0 / 885.0));
259
260 // Set the CUC hex string
261 return QString("%1%2").arg(coarse, 8, 16, QChar('0')).arg(fine, 4, 16, QChar('0'));
262 }
263
264
265 //-------------------------------------------------------------------
266
267 Module::Module()
268 : Plugins::iPlugin()
269 , mReady(false)
270 , mLastDateTimeType(Internal::DateTime::Invalid)
271 {
272 setObjectName(QString("%1.%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
273
274 EVAF_INFO("%s created", qPrintable(objectName()));
275 }
276
277 Module::~Module()
278 {
279 EVAF_INFO("%s destroyed", qPrintable(objectName()));
280 }
281
282 bool Module::init(QString const & args)
283 {
284 Q_UNUSED(args);
285
286 // Get the main window interface and fill it with the widgets
287 SdiWindow::iSdiWindow * win = evafQueryInterface<SdiWindow::iSdiWindow>("iSdiWindow");
288 EVAF_TEST_X(win, "No iSdiWindow interface");
289
290 Gui::Panel * panel = new Gui::Panel;
291 win->addPanel("PswGen", panel);
292
293 QVBoxLayout * v = new QVBoxLayout;
294 panel->setLayout(v);
295
296 QGridLayout * g = new QGridLayout;
297 v->addLayout(g);
298 g->setColumnStretch(1, 2);
299
300 QLabel * l = new QLabel(tr("&Epoch:", VER_MODULE_NAME_STR));
301 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
302 g->addWidget(l, 0, 0);
303
304 wEpoch = new QComboBox;
305 l->setBuddy(wEpoch);
306 wEpoch->setEditable(true);
307 {
308 QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$");
309 wEpoch->setValidator(new QRegExpValidator(rx, wEpoch));
310 }
311 wEpoch->addItems(QStringList() << "1970-01-01T00:00:00.000" << "1999-08-22T00:00:00.000");
312 connect(wEpoch, SIGNAL(editTextChanged(QString)), this, SLOT(epochChanged(QString)));
313 g->addWidget(wEpoch, 0, 1);
314 panel->setFocusProxy(wEpoch);
315
316 l = new QLabel(tr("&Date/time:", VER_MODULE_NAME_STR));
317 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
318 g->addWidget(l, 1, 0);
319
320 wDateTime = new QLineEdit;
321 l->setBuddy(wDateTime);
322 {
323 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})?)$");
324 wDateTime->setValidator(new QRegExpValidator(rx, wDateTime));
325 }
326 connect(wDateTime, SIGNAL(textEdited(QString)), this, SLOT(dateTimeEdited(QString)));
327 g->addWidget(wDateTime, 1, 1);
328
329 QPushButton * btn = new QPushButton();
330 btn->setDisabled(true);
331 g->addWidget(btn, 1, 2);
332 connect(btn, SIGNAL(clicked()), this, SLOT(dateTimeClicked()));
333 wConvertDateTime = btn;
334
335 l = new QLabel(tr("&CUC:", VER_MODULE_NAME_STR));
336 l->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
337 g->addWidget(l, 2, 0);
338
339 wCucHex = new QLineEdit;
340 l->setBuddy(wCucHex);
341 wCucHex->setMaxLength(12);
342 {
343 QRegExp rx("^[0-9a-f]{8}([0-9a-f]{4})?$", Qt::CaseInsensitive);
344 wCucHex->setValidator(new QRegExpValidator(rx, wCucHex));
345 }
346 connect(wCucHex, SIGNAL(textEdited(QString)), this, SLOT(cucHexEdited(QString)));
347 g->addWidget(wCucHex, 2, 1);
348
349 v->addStretch();
350
351 QHBoxLayout * h = new QHBoxLayout;
352 h->addStretch();
353 v->addLayout(h);
354
355 QAction * a = new QAction(panel);
356 a->setShortcut(Qt::Key_Escape);
357 connect(a, SIGNAL(triggered()), qApp, SLOT(quit()));
358 panel->addAction(a);
359
360 mReady = true;
361
362 EVAF_INFO("%s initialized", qPrintable(objectName()));
363
364 return true;
365 }
366
367 void Module::done()
368 {
369 mReady = false;
370
371 EVAF_INFO("%s finalized", qPrintable(objectName()));
372 }
373
374 void Module::dateTimeClicked()
375 {
376 if (!mDateTime.isValid())
377 {
378 return;
379 }
380
381 // Convert to another type
382 switch (mLastDateTimeType)
383 {
384 case Internal::DateTime::ISO:
385 {
386 mLastDateTimeType = Internal::DateTime::ASD;
387 wDateTime->setText(mDateTime.asASDstring());
388 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
389 break;
390 }
391 case Internal::DateTime::ASD:
392 {
393 mLastDateTimeType = Internal::DateTime::ISO;
394 wDateTime->setText(mDateTime.asISOstring());
395 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
396 break;
397 }
398 default:
399 break;
400 }
401 }
402
403 void Module::dateTimeEdited(QString const & s)
404 {
405 wConvertDateTime->setDisabled(true);
406 wConvertDateTime->setText(QString());
407 mLastDateTimeType = Internal::DateTime::Invalid;
408
409 if (s.isEmpty())
410 {
411 return;
412 }
413
414 mDateTime.setDateTime(s);
415 if (!mDateTime.isValid())
416 {
417 return;
418 }
419
420 mLastDateTimeType = mDateTime.type();
421
422 // Set the CUC hex string from this date/time string
423 wCucHex->setText(mDateTime.asCUChexString());
424
425 // Enable the button that converts between ISO and ASD date/time strings
426 if (mDateTime.type() == Internal::DateTime::ISO)
427 {
428 wConvertDateTime->setEnabled(true);
429 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
430 }
431 else if (mDateTime.type() == Internal::DateTime::ASD)
432 {
433 wConvertDateTime->setEnabled(true);
434 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
435 }
436 }
437
438 void Module::cucHexEdited(QString const & s)
439 {
440 if (s.isEmpty() || s.size() < 8)
441 {
442 return;
443 }
444
445 mDateTime.setDateTime(s);
446 if (!mDateTime.isValid())
447 {
448 return;
449 }
450
451 if (mLastDateTimeType == Internal::DateTime::Invalid)
452 {
453 mLastDateTimeType = Internal::DateTime::ASD;
454 }
455
456 // Set the date/time string in the last used format
457 if (mLastDateTimeType == Internal::DateTime::ASD)
458 {
459 wDateTime->setText(mDateTime.asASDstring());
460 wConvertDateTime->setEnabled(true);
461 wConvertDateTime->setText(tr("&to ISO", VER_MODULE_NAME_STR));
462 }
463 else if (mLastDateTimeType == Internal::DateTime::ISO)
464 {
465 wDateTime->setText(mDateTime.asISOstring());
466 wConvertDateTime->setEnabled(true);
467 wConvertDateTime->setText(tr("&to ASD", VER_MODULE_NAME_STR));
468 }
469 }
470
471 void Module::epochChanged(QString const & s)
472 {
473 if (s.isEmpty())
474 return;
475 QRegExp rx("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d{3})?$");
476 if (!rx.exactMatch(s))
477 return;
478
479 QDateTime dt = QDateTime::fromString(s, Qt::ISODate);
480 dt.setTimeSpec(Qt::UTC);
481 mDateTime.setEpoch(dt);
482
483 // If there is a valid entry, do the conversion
484 switch (mDateTime.type())
485 {
486 case Internal::DateTime::ISO:
487 case Internal::DateTime::ASD:
488 {
489 wCucHex->setText(mDateTime.asCUChexString());
490 break;
491 }
492 case Internal::DateTime::CUC:
493 {
494 if (mLastDateTimeType == Internal::DateTime::ASD)
495 {
496 wDateTime->setText(mDateTime.asASDstring());
497 }
498 else if (mLastDateTimeType == Internal::DateTime::ISO)
499 {
500 wDateTime->setText(mDateTime.asISOstring());
501 }
502 break;
503 }
504 default:
505 break;
506 }
507 }