• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mcallegari / qlcplus / 6683238402

29 Oct 2023 12:10PM UTC coverage: 28.07%. Remained the same
6683238402

push

github

mcallegari
engine: fix build

15385 of 54809 relevant lines covered (28.07%)

20267.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/ui/src/virtualconsole/vcclock.cpp
1
/*
2
  Q Light Controller Plus
3
  vcclock.cpp
4

5
  Copyright (c) Massimo Callegari
6

7
  Licensed under the Apache License, Version 2.0 (the "License");
8
  you may not use this file except in compliance with the License.
9
  You may obtain a copy of the License at
10

11
      http://www.apache.org/licenses/LICENSE-2.0.txt
12

13
  Unless required by applicable law or agreed to in writing, software
14
  distributed under the License is distributed on an "AS IS" BASIS,
15
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
  See the License for the specific language governing permissions and
17
  limitations under the License.
18
*/
19

20
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QDateTime>
23
#include <QStyle>
24
#include <QtGui>
25

26
#include "vcclockproperties.h"
27
#include "vcclock.h"
28
#include "doc.h"
29

30
#define HYSTERESIS 3 // Hysteresis for pause/reset external input
31

32
#define KXMLQLCVCClockType      QString("Type")
33
#define KXMLQLCVCClockHours     QString("Hours")
34
#define KXMLQLCVCClockMinutes   QString("Minutes")
35
#define KXMLQLCVCClockSeconds   QString("Seconds")
36

37
#define KXMLQLCVCClockSchedule      QString("Schedule")
38
#define KXMLQLCVCClockScheduleFunc  QString("Function")
39
#define KXMLQLCVCClockScheduleTime  QString("Time")
40

41
#define KXMLQLCVCClockPlay  QString("PlayPause")
42
#define KXMLQLCVCClockReset QString("Reset")
43

44
const quint8 VCClock::playInputSourceId = 0;
45
const quint8 VCClock::resetInputSourceId = 1;
46

47
VCClock::VCClock(QWidget* parent, Doc* doc)
×
48
    : VCWidget(parent, doc)
49
    , m_clocktype(Clock)
50
    , m_scheduleIndex(-1)
51
    , m_hh(0)
52
    , m_mm(0)
53
    , m_ss(0)
54
    , m_targetTime(0)
55
    , m_currentTime(0)
56
    , m_isPaused(true)
×
57
{
58
    /* Set the class name "VCClock" as the object name as well */
59
    setObjectName(VCClock::staticMetaObject.className());
×
60

61
    setType(VCWidget::ClockWidget);
×
62
    setCaption("");
×
63
    resize(QSize(150, 50));
×
64
    QFont font = qApp->font();
×
65
    font.setBold(true);
×
66
    font.setPixelSize(28);
×
67
    setFont(font);
×
68

69
    QTimer *timer = new QTimer(this);
×
70
    connect(timer, SIGNAL(timeout()), this, SLOT(slotUpdateTime()));
×
71
    timer->start(1000);
×
72
}
×
73

74
VCClock::~VCClock()
×
75
{
76
}
×
77

78
void VCClock::slotModeChanged(Doc::Mode mode)
×
79
{
80
    qDebug() << Q_FUNC_INFO;
×
81

82
    if (mode == Doc::Operate)
×
83
    {
84
        if (m_scheduleList.count() > 0)
×
85
        {
86
            QTime currTime = QDateTime::currentDateTime().time();
×
87
            for(int i = 0; i < m_scheduleList.count(); i++)
×
88
            {
89
                VCClockSchedule sch = m_scheduleList.at(i);
×
90
                if (sch.time().time() >= currTime)
×
91
                {
92
                    m_scheduleIndex = i;
×
93
                    qDebug() << "VC Clock set to play index:" << i;
×
94
                    break;
×
95
                }
96
            }
97
        }
98
    }
99
    VCWidget::slotModeChanged(mode);
×
100
}
×
101

102
/*********************************************************************
103
 * Type
104
 *********************************************************************/
105

106
void VCClock::setClockType(VCClock::ClockType type)
×
107
{
108
    m_clocktype = type;
×
109
    updateFeedback();
×
110
    update();
×
111
}
×
112

113
VCClock::ClockType VCClock::clockType() const
×
114
{
115
    return m_clocktype;
×
116
}
117

118
QString VCClock::typeToString(VCClock::ClockType type)
×
119
{
120
    if (type == Stopwatch)
×
121
        return "Stopwatch";
×
122
    else if (type == Countdown)
×
123
        return "Countdown";
×
124
    else
125
        return "Clock";
×
126
}
127

128
VCClock::ClockType VCClock::stringToType(QString str)
×
129
{
130
    if (str == "Stopwatch")
×
131
        return Stopwatch;
×
132
    else if (str == "Countdown")
×
133
        return Countdown;
×
134
    else
135
        return Clock;
×
136
}
137

138
void VCClock::addSchedule(VCClockSchedule schedule)
×
139
{
140
    qDebug() << Q_FUNC_INFO << "--- ID:" << schedule.function() << ", time:" << schedule.time().time().toString();
×
141
    if (schedule.function() != Function::invalidId())
×
142
        m_scheduleList.append(schedule);
×
143
    std::sort(m_scheduleList.begin(), m_scheduleList.end());
×
144
}
×
145

146
void VCClock::removeSchedule(int index)
×
147
{
148
    if (index < 0 || index > m_scheduleList.count())
×
149
        return;
×
150

151
    m_scheduleList.removeAt(index);
×
152
}
153

154
void VCClock::removeAllSchedule()
×
155
{
156
    m_scheduleList.clear();
×
157
}
×
158

159
QList<VCClockSchedule> VCClock::schedules()
×
160
{
161
    return m_scheduleList;
×
162
}
163

164
FunctionParent VCClock::functionParent() const
×
165
{
166
    return FunctionParent(FunctionParent::AutoVCWidget, id());
×
167
}
168

169
void VCClock::setCountdown(int h, int m, int s)
×
170
{
171
    m_hh = h;
×
172
    m_mm = m;
×
173
    m_ss = s;
×
174
    m_targetTime = (m_hh * 3600) + (m_mm * 60) + m_ss;
×
175
    m_currentTime = m_targetTime;
×
176
}
×
177

178
void VCClock::slotUpdateTime()
×
179
{
180
    if (mode() == Doc::Operate)
×
181
    {
182
        if (m_isPaused == false)
×
183
        {
184
            if (m_clocktype == Stopwatch)
×
185
                m_currentTime++;
×
186
            else if (m_clocktype == Countdown && m_currentTime > 0)
×
187
                m_currentTime--;
×
188

189
            emit timeChanged(m_currentTime);
×
190
        }
191
        else
192
        {
193
            if (m_clocktype == Clock)
×
194
            {
195
                if (m_scheduleIndex != -1 && m_scheduleIndex < m_scheduleList.count())
×
196
                {
197
                    QTime currTime = QDateTime::currentDateTime().time();
×
198
                    VCClockSchedule sch = m_scheduleList.at(m_scheduleIndex);
×
199
                    //qDebug() << "--- > currTime:" << currTime.toString() << ", schTime:" << sch.time().time().toString();
200
                    if (sch.time().time().toString() == currTime.toString())
×
201
                    {
202
                        quint32 fid = sch.function();
×
203
                        Function *func = m_doc->function(fid);
×
204
                        if (func != NULL)
×
205
                        {
206
                            func->start(m_doc->masterTimer(), functionParent());
×
207
                            qDebug() << "VC Clock starting function:" << func->name();
×
208
                        }
209
                        m_scheduleIndex++;
×
210
                        if (m_scheduleIndex == m_scheduleList.count())
×
211
                            m_scheduleIndex = 0;
×
212
                    }
213
                }
214
            }
215
        }
216
    }
217
    updateFeedback();
×
218
    update();
×
219
}
×
220

221
void VCClock::resetTimer()
×
222
{
223
    if (clockType() == Stopwatch)
×
224
        m_currentTime = 0;
×
225
    else if (clockType() == Countdown)
×
226
        m_currentTime = m_targetTime;
×
227

228
    emit timeChanged(m_currentTime);
×
229

230
    updateFeedback();
×
231
    update();
×
232
}
×
233

234
void VCClock::playPauseTimer()
×
235
{
236
    if (clockType() == Stopwatch || clockType() == Countdown)
×
237
        m_isPaused = !m_isPaused;
×
238

239
    updateFeedback();
×
240
    update();
×
241
}
×
242

243
/*****************************************************************************
244
 * Key Sequences
245
 *****************************************************************************/
246

247
void VCClock::setPlayKeySequence(const QKeySequence& keySequence)
×
248
{
249
    m_playKeySequence = QKeySequence(keySequence);
×
250
}
×
251

252
QKeySequence VCClock::playKeySequence() const
×
253
{
254
    return m_playKeySequence;
×
255
}
256

257
void VCClock::setResetKeySequence(const QKeySequence& keySequence)
×
258
{
259
    m_resetKeySequence = QKeySequence(keySequence);
×
260
}
×
261

262
QKeySequence VCClock::resetKeySequence() const
×
263
{
264
    return m_resetKeySequence;
×
265
}
266

267
void VCClock::slotKeyPressed(const QKeySequence& keySequence)
×
268
{
269
    if (acceptsInput() == false)
×
270
        return;
×
271

272
    if (m_playKeySequence == keySequence)
×
273
        playPauseTimer();
×
274
    else if (m_resetKeySequence == keySequence)
×
275
        resetTimer();
×
276
}
277

278
void VCClock::updateFeedback()
×
279
{
280
    if (clockType() == Stopwatch)
×
281
    {
282
        sendFeedback(!m_isPaused ? UCHAR_MAX : 0, playInputSourceId);
×
283
        sendFeedback(m_currentTime == 0 ? UCHAR_MAX : 0, resetInputSourceId);
×
284
    }
285
    else if (clockType() == Countdown)
×
286
    {
287
        sendFeedback(!m_isPaused ? UCHAR_MAX : 0, playInputSourceId);
×
288
        sendFeedback(m_currentTime == m_targetTime ? UCHAR_MAX : 0, resetInputSourceId);
×
289
    }
290
    else
291
    {
292
        sendFeedback(0, playInputSourceId);
×
293
        sendFeedback(0, resetInputSourceId);
×
294
    }
295
}
×
296

297
/*****************************************************************************
298
 * External Input
299
 *****************************************************************************/
300

301
void VCClock::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
302
{
303
    /* Don't let input data through in design mode or if disabled */
304
    if (acceptsInput() == false)
×
305
        return;
×
306

307
    quint32 pagedCh = (page() << 16) | channel;
×
308

309
    if (checkInputSource(universe, pagedCh, value, sender(), playInputSourceId))
×
310
    {
311
        // Use hysteresis for values, in case the timer is being controlled
312
        // by a slider. The value has to go to zero before the next non-zero
313
        // value is accepted as input. And the non-zero values have to visit
314
        // above $HYSTERESIS before a zero is accepted again.
315
        if (m_playLatestValue == 0 && value > 0)
×
316
        {
317
            playPauseTimer();
×
318
            m_playLatestValue = value;
×
319
        }
320
        else if (m_playLatestValue > HYSTERESIS && value == 0)
×
321
        {
322
            m_playLatestValue = 0;
×
323
        }
324

325
        if (value > HYSTERESIS)
×
326
            m_playLatestValue = value;
×
327
    }
328
    else if (checkInputSource(universe, pagedCh, value, sender(), resetInputSourceId))
×
329
    {
330
        // Use hysteresis for values, in case the timer is being controlled
331
        // by a slider. The value has to go to zero before the next non-zero
332
        // value is accepted as input. And the non-zero values have to visit
333
        // above $HYSTERESIS before a zero is accepted again.
334
        if (m_resetLatestValue == 0 && value > 0)
×
335
        {
336
            resetTimer();
×
337
            m_resetLatestValue = value;
×
338
        }
339
        else if (m_resetLatestValue > HYSTERESIS && value == 0)
×
340
        {
341
            m_resetLatestValue = 0;
×
342
        }
343

344
        if (value > HYSTERESIS)
×
345
            m_resetLatestValue = value;
×
346
    }
347
}
348

349
/*****************************************************************************
350
 * Clipboard
351
 *****************************************************************************/
352

353
VCWidget* VCClock::createCopy(VCWidget* parent)
×
354
{
355
    Q_ASSERT(parent != NULL);
×
356

357
    VCClock* clock = new VCClock(parent, m_doc);
×
358
    if (clock->copyFrom(this) == false)
×
359
    {
360
        delete clock;
×
361
        clock = NULL;
×
362
    }
363

364
    return clock;
×
365
}
366

367
bool VCClock::copyFrom(const VCWidget* widget)
×
368
{
369
    const VCClock* clock = qobject_cast<const VCClock*> (widget);
×
370
    if (clock == NULL)
×
371
        return false;
×
372

373
    // TODO: copy schedules
374

375
    /* Clock type */
376
    setClockType(clock->clockType());
×
377

378
    /* Key sequence */
379
    setPlayKeySequence(clock->playKeySequence());
×
380
    setResetKeySequence(clock->resetKeySequence());
×
381

382
    /* Common stuff */
383
    return VCWidget::copyFrom(widget);
×
384
}
385

386
/*****************************************************************************
387
 * Properties
388
 *****************************************************************************/
389

390
void VCClock::editProperties()
×
391
{
392
    VCClockProperties vccp(this, m_doc);
×
393
    if (vccp.exec() == QDialog::Rejected)
×
394
        return;
×
395

396
    m_doc->setModified();
×
397
}
398

399
/*****************************************************************************
400
 * Load & Save
401
 *****************************************************************************/
402

403
bool VCClock::loadXML(QXmlStreamReader &root)
×
404
{
405
    if (root.name() != KXMLQLCVCClock)
×
406
    {
407
        qWarning() << Q_FUNC_INFO << "Clock node not found";
×
408
        return false;
×
409
    }
410

411
    QXmlStreamAttributes attrs = root.attributes();
×
412

413
    if (attrs.hasAttribute(KXMLQLCVCClockType))
×
414
    {
415
        setClockType(stringToType(attrs.value(KXMLQLCVCClockType).toString()));
×
416
        if (clockType() == Countdown)
×
417
        {
418
            int h = 0, m = 0, s = 0;
×
419
            if (attrs.hasAttribute(KXMLQLCVCClockHours))
×
420
                h = attrs.value(KXMLQLCVCClockHours).toString().toInt();
×
421
            if (attrs.hasAttribute(KXMLQLCVCClockMinutes))
×
422
                m = attrs.value(KXMLQLCVCClockMinutes).toString().toInt();
×
423
            if (attrs.hasAttribute(KXMLQLCVCClockSeconds))
×
424
                s = attrs.value(KXMLQLCVCClockSeconds).toString().toInt();
×
425
            setCountdown(h, m ,s);
×
426
        }
427
    }
428

429
    /* Widget commons */
430
    loadXMLCommon(root);
×
431

432
    /* Children */
433
    while (root.readNextStartElement())
×
434
    {
435
        if (root.name() == KXMLQLCWindowState)
×
436
        {
437
            int x = 0, y = 0, w = 0, h = 0;
×
438
            bool visible = false;
×
439
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
×
440
            setGeometry(x, y, w, h);
×
441
        }
442
        else if (root.name() == KXMLQLCVCWidgetAppearance)
×
443
        {
444
            loadXMLAppearance(root);
×
445
        }
446
        else if (root.name() == KXMLQLCVCClockSchedule)
×
447
        {
448
            VCClockSchedule sch;
×
449
            if (sch.loadXML(root) == true)
×
450
                addSchedule(sch);
×
451
        }
452
        else if (root.name() == KXMLQLCVCClockPlay)
×
453
        {
454
            QString str = loadXMLSources(root, playInputSourceId);
×
455
            if (str.isEmpty() == false)
×
456
                m_playKeySequence = stripKeySequence(QKeySequence(str));
×
457
        }else if (root.name() == KXMLQLCVCClockReset)
×
458
        {
459
            QString str = loadXMLSources(root, resetInputSourceId);
×
460
            if (str.isEmpty() == false)
×
461
                m_resetKeySequence = stripKeySequence(QKeySequence(str));
×
462
        }
463
        else
464
        {
465
            qWarning() << Q_FUNC_INFO << "Unknown clock tag:" << root.name().toString();
×
466
            root.skipCurrentElement();
×
467
        }
468
    }
469

470
    return true;
×
471
}
472

473
bool VCClock::saveXML(QXmlStreamWriter *doc)
×
474
{
475
    Q_ASSERT(doc != NULL);
×
476

477
    /* VC Clock entry */
478
    doc->writeStartElement(KXMLQLCVCClock);
×
479

480
    /* Type */
481
    ClockType type = clockType();
×
482
    doc->writeAttribute(KXMLQLCVCClockType, typeToString(type));
×
483
    if (type == Countdown)
×
484
    {
485
        doc->writeAttribute(KXMLQLCVCClockHours, QString::number(getHours()));
×
486
        doc->writeAttribute(KXMLQLCVCClockMinutes, QString::number(getMinutes()));
×
487
        doc->writeAttribute(KXMLQLCVCClockSeconds, QString::number(getSeconds()));
×
488
    }
489

490
    saveXMLCommon(doc);
×
491

492
    /* Window state */
493
    saveXMLWindowState(doc);
×
494

495
    /* Appearance */
496
    saveXMLAppearance(doc);
×
497

498
    foreach(VCClockSchedule sch, schedules())
×
499
        sch.saveXML(doc);
×
500

501
    if (type != Clock)
×
502
    {
503
        /* Play/Pause */
504
        doc->writeStartElement(KXMLQLCVCClockPlay);
×
505
        if (m_playKeySequence.toString().isEmpty() == false)
×
506
            doc->writeTextElement(KXMLQLCVCWidgetKey, m_playKeySequence.toString());
×
507
        saveXMLInput(doc, inputSource(playInputSourceId));
×
508
        doc->writeEndElement();
×
509

510
        /* Reset */
511
        doc->writeStartElement(KXMLQLCVCClockReset);
×
512
        if (m_resetKeySequence.toString().isEmpty() == false)
×
513
            doc->writeTextElement(KXMLQLCVCWidgetKey, m_resetKeySequence.toString());
×
514
        saveXMLInput(doc, inputSource(resetInputSourceId));
×
515
        doc->writeEndElement();
×
516
    }
517

518
    /* End the <Clock> tag */
519
    doc->writeEndElement();
×
520

521
    return true;
×
522
}
523

524
/****************************************************************************
525
 * Drawing
526
 ****************************************************************************/
527

528
void VCClock::paintEvent(QPaintEvent* e)
×
529
{
530
    QPainter painter(this);
×
531

532
    if (clockType() == Clock)
×
533
    {
534
        QDateTime currTime = QDateTime::currentDateTime();
×
535
        style()->drawItemText(&painter, rect(), Qt::AlignCenter | Qt::TextWordWrap, palette(),
×
536
                              true, currTime.time().toString(), foregroundRole());
×
537
    }
538
    else
539
    {
540
        quint32 secTime = m_currentTime;
×
541
        uint h, m;
542

543
        h = secTime / 3600;
×
544
        secTime -= (h * 3600);
×
545

546
        m = secTime / 60;
×
547
        secTime -= (m * 60);
×
548
        style()->drawItemText(&painter, rect(), Qt::AlignCenter | Qt::TextWordWrap, palette(),
×
549
                              true, QString("%1:%2:%3").arg(h, 2, 10, QChar('0'))
×
550
                              .arg(m, 2, 10, QChar('0')).arg(secTime, 2, 10, QChar('0')), foregroundRole());
×
551
    }
552
    painter.end();
×
553

554
    VCWidget::paintEvent(e);
×
555
}
×
556

557
void VCClock::mousePressEvent(QMouseEvent *e)
×
558
{
559
    if (mode() == Doc::Design)
×
560
    {
561
        VCWidget::mousePressEvent(e);
×
562
        return;
×
563
    }
564

565
    if (e->button() == Qt::RightButton)
×
566
    {
567
        resetTimer();
×
568
    }
569
    else if (e->button() == Qt::LeftButton)
×
570
    {
571
        playPauseTimer();
×
572
    }
573
    VCWidget::mousePressEvent(e);
×
574
}
575

576
/*********************************************************************
577
 * VCClockSchedule Class methods
578
 *********************************************************************/
579

580
bool VCClockSchedule::operator <(const VCClockSchedule &sch) const
×
581
{
582
    if (sch.time() < time())
×
583
        return false;
×
584
    return true;
×
585
}
586

587
bool VCClockSchedule::loadXML(QXmlStreamReader &root)
×
588
{
589
    if (root.name() != KXMLQLCVCClockSchedule)
×
590
    {
591
        qWarning() << Q_FUNC_INFO << "Clock Schedule node not found";
×
592
        return false;
×
593
    }
594

595
    QXmlStreamAttributes attrs = root.attributes();
×
596

597
    if (attrs.hasAttribute(KXMLQLCVCClockScheduleFunc))
×
598
    {
599
        setFunction(attrs.value(KXMLQLCVCClockScheduleFunc).toString().toUInt());
×
600
        if (attrs.hasAttribute(KXMLQLCVCClockScheduleTime))
×
601
        {
602
            QDateTime dt;
×
603
            dt.setTime(QTime::fromString(attrs.value(KXMLQLCVCClockScheduleTime).toString(), "HH:mm:ss"));
×
604
            setTime(dt);
×
605
        }
606
    }
607
    root.skipCurrentElement();
×
608

609
    return true;
×
610
}
611

612
bool VCClockSchedule::saveXML(QXmlStreamWriter *doc)
×
613
{
614
    /* Schedule tag */
615
    doc->writeStartElement(KXMLQLCVCClockSchedule);
×
616

617
    /* Schedule function */
618
    doc->writeAttribute(KXMLQLCVCClockScheduleFunc, QString::number(function()));
×
619
    /* Schedule time */
620
    doc->writeAttribute(KXMLQLCVCClockScheduleTime, time().time().toString());
×
621

622
    doc->writeEndElement();
×
623

624
    return true;
×
625
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc