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