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

mcallegari / qlcplus / 6841397861

12 Nov 2023 02:56PM UTC coverage: 28.636% (+0.5%) from 28.089%
6841397861

push

github

mcallegari
engine/test: prefer QVERIFY for numeric comparison

15723 of 54907 relevant lines covered (28.64%)

20282.61 hits per line

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

49.57
/engine/src/show.cpp
1
/*
2
  Q Light Controller Plus
3
  show.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 <QString>
23
#include <QDebug>
24
#include <QFile>
25
#include <QList>
26

27
#include "showrunner.h"
28
#include "function.h"
29
#include "show.h"
30
#include "doc.h"
31

32
#define KXMLQLCShowTimeDivision QString("TimeDivision")
33
#define KXMLQLCShowTimeType     QString("Type")
34
#define KXMLQLCShowTimeBPM      QString("BPM")
35

36
/*****************************************************************************
37
 * Initialization
38
 *****************************************************************************/
39

40
Show::Show(Doc* doc) : Function(doc, Function::ShowType)
5✔
41
  , m_timeDivisionType(Time)
42
  , m_timeDivisionBPM(120)
43
  , m_latestTrackId(0)
44
  , m_runner(NULL)
5✔
45
{
46
    setName(tr("New Show"));
5✔
47

48
    // Clear attributes here. I want attributes to be mapped
49
    // exactly like the Show tracks
50
    unregisterAttribute(tr("Intensity"));
5✔
51
}
5✔
52

53
Show::~Show()
5✔
54
{
55
    m_tracks.clear();
5✔
56
}
5✔
57

58
QIcon Show::getIcon() const
×
59
{
60
    return QIcon(":/show.png");
×
61
}
62

63
quint32 Show::totalDuration()
×
64
{
65
    quint32 totalDuration = 0;
×
66

67
    foreach(Track *track, tracks())
×
68
    {
69
        foreach(ShowFunction *sf, track->showFunctions())
×
70
        {
71
            if (sf->startTime() + sf->duration(doc()) > totalDuration)
×
72
                totalDuration = sf->startTime() + sf->duration(doc());
×
73
        }
74
    }
75

76
    return totalDuration;
×
77
}
78

79
/*****************************************************************************
80
 * Copying
81
 *****************************************************************************/
82

83
Function* Show::createCopy(Doc* doc, bool addToDoc)
×
84
{
85
    Q_ASSERT(doc != NULL);
×
86

87
    Function* copy = new Show(doc);
×
88
    if (copy->copyFrom(this) == false)
×
89
    {
90
        delete copy;
×
91
        copy = NULL;
×
92
    }
93
    if (addToDoc == true && doc->addFunction(copy) == false)
×
94
    {
95
        delete copy;
×
96
        copy = NULL;
×
97
    }
98

99
    return copy;
×
100
}
101

102
bool Show::copyFrom(const Function* function)
×
103
{
104
    const Show* show = qobject_cast<const Show*> (function);
×
105
    if (show == NULL)
×
106
        return false;
×
107

108
    m_timeDivisionType = show->m_timeDivisionType;
×
109
    m_timeDivisionBPM = show->m_timeDivisionBPM;
×
110
    m_latestTrackId = show->m_latestTrackId;
×
111

112
    // create a copy of each track
113
    foreach(Track *track, show->tracks())
×
114
    {
115
        quint32 sceneID = track->getSceneID();
×
116
        Track* newTrack = new Track(sceneID);
×
117
        newTrack->setName(track->name());
×
118
        addTrack(newTrack);
×
119

120
        // create a copy of each sequence/audio in a track
121
        foreach(ShowFunction *sfunc, track->showFunctions())
×
122
        {
123
            Function* function = doc()->function(sfunc->functionID());
×
124
            if (function == NULL)
×
125
                continue;
×
126

127
            /* Attempt to create a copy of the function to Doc */
128
            Function* copy = function->createCopy(doc());
×
129
            if (copy != NULL)
×
130
            {
131
                copy->setName(tr("Copy of %1").arg(function->name()));
×
132
                ShowFunction *showFunc = newTrack->createShowFunction(copy->id());
×
133
                showFunc->setStartTime(sfunc->startTime());
×
134
                showFunc->setDuration(sfunc->duration());
×
135
                showFunc->setColor(sfunc->color());
×
136
                showFunc->setLocked(sfunc->isLocked());
×
137
            }
138
        }
139
    }
140

141
    return Function::copyFrom(function);
×
142
}
143

144
/*********************************************************************
145
 * Time division
146
 *********************************************************************/
147

148
void Show::setTimeDivision(Show::TimeDivision type, int BPM)
3✔
149
{
150
    qDebug() << "[setTimeDivision] type:" << type << ", BPM:" << BPM;
3✔
151
    m_timeDivisionType = type;
3✔
152
    m_timeDivisionBPM = BPM;
3✔
153
}
3✔
154

155
Show::TimeDivision Show::getTimeDivisionType()
3✔
156
{
157
    return m_timeDivisionType;
3✔
158
}
159

160
int Show::getTimeDivisionBPM()
3✔
161
{
162
    return m_timeDivisionBPM;
3✔
163
}
164

165
QString Show::tempoToString(Show::TimeDivision type)
5✔
166
{
167
    switch(type)
5✔
168
    {
169
        case Time: return QString("Time"); break;
1✔
170
        case BPM_4_4: return QString("BPM_4_4"); break;
1✔
171
        case BPM_3_4: return QString("BPM_3_4"); break;
2✔
172
        case BPM_2_4: return QString("BPM_2_4"); break;
1✔
173
        case Invalid:
×
174
        default:
175
            return QString("Invalid"); break;
×
176
    }
177
    return QString();
178
}
179

180
Show::TimeDivision Show::stringToTempo(QString tempo)
5✔
181
{
182
    if (tempo == "Time")
5✔
183
        return Time;
1✔
184
    else if (tempo == "BPM_4_4")
4✔
185
        return BPM_4_4;
1✔
186
    else if (tempo == "BPM_3_4")
3✔
187
        return BPM_3_4;
1✔
188
    else if (tempo == "BPM_2_4")
2✔
189
        return BPM_2_4;
2✔
190
    else
191
        return Invalid;
×
192
}
193

194
/*****************************************************************************
195
 * Tracks
196
 *****************************************************************************/
197

198
bool Show::addTrack(Track *track, quint32 id)
6✔
199
{
200
    Q_ASSERT(track != NULL);
6✔
201

202
    // No ID given, this method can assign one
203
    if (id == Track::invalidId())
6✔
204
        id = createTrackId();
4✔
205

206
     track->setId(id);
6✔
207
     track->setShowId(this->id());
6✔
208
     m_tracks[id] = track;
6✔
209

210
     registerAttribute(track->name());
6✔
211

212
     return true;
6✔
213
}
214

215
bool Show::removeTrack(quint32 id)
3✔
216
{
217
    if (m_tracks.contains(id) == true)
3✔
218
    {
219
        Track* trk = m_tracks.take(id);
2✔
220
        Q_ASSERT(trk != NULL);
2✔
221

222
        unregisterAttribute(trk->name());
2✔
223

224
        //emit trackRemoved(id);
225
        delete trk;
2✔
226

227
        return true;
2✔
228
    }
229
    else
230
    {
231
        qWarning() << Q_FUNC_INFO << "No track found with id" << id;
1✔
232
        return false;
1✔
233
    }
234
}
235

236
Track* Show::track(quint32 id) const
5✔
237
{
238
    if (m_tracks.contains(id) == true)
5✔
239
        return m_tracks[id];
3✔
240
    else
241
        return NULL;
2✔
242
}
243

244
Track* Show::getTrackFromSceneID(quint32 id)
2✔
245
{
246
    foreach(Track *track, m_tracks)
4✔
247
    {
248
        if (track->getSceneID() == id)
2✔
249
            return track;
1✔
250
    }
251
    return NULL;
1✔
252
}
253

254
int Show::getTracksCount()
3✔
255
{
256
    return m_tracks.size();
3✔
257
}
258

259
void Show::moveTrack(Track *track, int direction)
3✔
260
{
261
    if (track == NULL)
3✔
262
        return;
×
263

264
    qint32 trkID = track->id();
3✔
265
    if (trkID == 0 && direction == -1)
3✔
266
        return;
1✔
267
    qint32 maxID = -1;
2✔
268
    Track *swapTrack = NULL;
2✔
269
    qint32 swapID = -1;
2✔
270
    if (direction > 0) swapID = INT_MAX;
2✔
271

272
    foreach(quint32 id, m_tracks.keys())
12✔
273
    {
274
        qint32 signedID = (qint32)id;
4✔
275
        if (signedID > maxID) maxID = signedID;
4✔
276
        if (direction == -1 && signedID > swapID && signedID < trkID)
4✔
277
            swapID = signedID;
2✔
278
        else if (direction == 1 && signedID < swapID && signedID > trkID)
2✔
279
            swapID = signedID;
×
280
    }
281

282
    qDebug() << Q_FUNC_INFO << "Direction:" << direction << ", trackID:" << trkID << ", swapID:" << swapID;
2✔
283
    if (swapID == trkID || (direction > 0 && trkID == maxID))
2✔
284
        return;
×
285

286
    swapTrack = m_tracks[swapID];
2✔
287
    m_tracks[swapID] = track;
2✔
288
    m_tracks[trkID] = swapTrack;
2✔
289
    track->setId(swapID);
2✔
290
    swapTrack->setId(trkID);
2✔
291
}
292

293
QList <Track*> Show::tracks() const
11✔
294
{
295
    return m_tracks.values();
11✔
296
}
297

298
quint32 Show::createTrackId()
6✔
299
{
300
    while (m_tracks.contains(m_latestTrackId) == true ||
10✔
301
           m_latestTrackId == Track::invalidId())
4✔
302
    {
303
        m_latestTrackId++;
2✔
304
    }
305

306
    return m_latestTrackId;
4✔
307
}
308

309
/*****************************************************************************
310
 * Load & Save
311
 *****************************************************************************/
312

313
bool Show::saveXML(QXmlStreamWriter *doc)
1✔
314
{
315
    Q_ASSERT(doc != NULL);
1✔
316

317
    /* Function tag */
318
    doc->writeStartElement(KXMLQLCFunction);
1✔
319

320
    /* Common attributes */
321
    saveXMLCommon(doc);
1✔
322

323
    doc->writeStartElement(KXMLQLCShowTimeDivision);
1✔
324
    doc->writeAttribute(KXMLQLCShowTimeType, tempoToString(m_timeDivisionType));
1✔
325
    doc->writeAttribute(KXMLQLCShowTimeBPM, QString::number(m_timeDivisionBPM));
1✔
326
    doc->writeEndElement();
1✔
327

328
    foreach(Track *track, m_tracks)
5✔
329
        track->saveXML(doc);
2✔
330

331
    /* End the <Function> tag */
332
    doc->writeEndElement();
1✔
333

334
    return true;
1✔
335
}
336

337
bool Show::loadXML(QXmlStreamReader &root)
1✔
338
{
339
    if (root.name() != KXMLQLCFunction)
1✔
340
    {
341
        qWarning() << Q_FUNC_INFO << "Function node not found";
×
342
        return false;
×
343
    }
344

345
    if (root.attributes().value(KXMLQLCFunctionType).toString() != typeToString(Function::ShowType))
1✔
346
    {
347
        qWarning() << Q_FUNC_INFO << root.attributes().value(KXMLQLCFunctionType).toString()
×
348
                   << "is not a show";
×
349
        return false;
×
350
    }
351

352
    while (root.readNextStartElement())
4✔
353
    {
354
        if (root.name() == KXMLQLCShowTimeDivision)
3✔
355
        {
356
            QString type = root.attributes().value(KXMLQLCShowTimeType).toString();
3✔
357
            int bpm = root.attributes().value(KXMLQLCShowTimeBPM).toString().toInt();
1✔
358
            setTimeDivision(stringToTempo(type), bpm);
1✔
359
            root.skipCurrentElement();
1✔
360
        }
361
        else if (root.name() == KXMLQLCTrack)
2✔
362
        {
363
            Track *trk = new Track();
2✔
364
            if (trk->loadXML(root) == true)
2✔
365
                addTrack(trk, trk->id());
2✔
366
        }
367
        else
368
        {
369
            qWarning() << Q_FUNC_INFO << "Unknown Show tag:" << root.name();
×
370
            root.skipCurrentElement();
×
371
        }
372
    }
373

374
    return true;
1✔
375
}
376

377
void Show::postLoad()
×
378
{
379
    foreach (Track* track, m_tracks)
×
380
    {
381
        if (track->postLoad(doc()))
×
382
            doc()->setModified();
×
383
    }
384
}
×
385

386
bool Show::contains(quint32 functionId)
×
387
{
388
    Doc *doc = this->doc();
×
389
    Q_ASSERT(doc != NULL);
×
390

391
    if (functionId == id())
×
392
        return true;
×
393

394
    foreach (Track* track, m_tracks)
×
395
    {
396
        if (track->contains(doc, functionId))
×
397
            return true;
×
398
    }
399

400
    return false;
×
401
}
402

403
QList<quint32> Show::components()
×
404
{
405
    QList<quint32> ids;
×
406

407
    foreach (Track* track, m_tracks)
×
408
        ids.append(track->components());
×
409

410
    return ids;
×
411
}
412

413
/*****************************************************************************
414
 * Running
415
 *****************************************************************************/
416

417
void Show::preRun(MasterTimer* timer)
×
418
{
419
    Function::preRun(timer);
×
420
    m_runningChildren.clear();
×
421
    if (m_runner != NULL)
×
422
    {
423
        m_runner->stop();
×
424
        delete m_runner;
×
425
    }
426

427
    m_runner = new ShowRunner(doc(), this->id(), elapsed());
×
428
    int i = 0;
×
429
    foreach(Track *track, m_tracks.values())
×
430
        m_runner->adjustIntensity(getAttributeValue(i++), track);
×
431

432
    connect(m_runner, SIGNAL(timeChanged(quint32)), this, SIGNAL(timeChanged(quint32)));
×
433
    connect(m_runner, SIGNAL(showFinished()), this, SIGNAL(showFinished()));
×
434
    m_runner->start();
×
435
}
×
436

437
void Show::setPause(bool enable)
×
438
{
439
    if (m_runner != NULL)
×
440
        m_runner->setPause(enable);
×
441
    Function::setPause(enable);
×
442
}
×
443

444
void Show::write(MasterTimer* timer, QList<Universe *> universes)
×
445
{
446
    Q_UNUSED(universes);
447
    Q_UNUSED(timer);
448

449
    if (isPaused())
×
450
        return;
×
451

452
    m_runner->write();
×
453
}
454

455
void Show::postRun(MasterTimer* timer, QList<Universe *> universes)
×
456
{
457
    if (m_runner != NULL)
×
458
    {
459
        m_runner->stop();
×
460
        delete m_runner;
×
461
        m_runner = NULL;
×
462
    }
463
    Function::postRun(timer, universes);
×
464
}
×
465

466
void Show::slotChildStopped(quint32 fid)
×
467
{
468
    Q_UNUSED(fid);
469
}
×
470

471
/*****************************************************************************
472
 * Attributes
473
 *****************************************************************************/
474

475
int Show::adjustAttribute(qreal fraction, int attributeId)
×
476
{
477
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
×
478

479
    if (m_runner != NULL)
×
480
    {
481
        QList<Track*> trkList = m_tracks.values();
×
482
        if (trkList.isEmpty() == false &&
×
483
            attrIndex >= 0 && attrIndex < trkList.count())
×
484
        {
485
            Track *track = trkList.at(attrIndex);
×
486
            if (track != NULL)
×
487
                m_runner->adjustIntensity(getAttributeValue(attrIndex), track);
×
488
        }
489
    }
490

491
    return attrIndex;
×
492
}
493

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