• 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

95.02
/engine/src/collection.cpp
1
/*
2
  Q Light Controller Plus
3
  collection.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

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

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

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

21
#include <QString>
22
#include <QDebug>
23
#include <QFile>
24
#include <QList>
25
#include <QMutexLocker>
26
#include <QXmlStreamReader>
27
#include <QXmlStreamWriter>
28

29
#include "mastertimer.h"
30
#include "collection.h"
31
#include "function.h"
32
#include "doc.h"
33

34
/*****************************************************************************
35
 * Initialization
36
 *****************************************************************************/
37

38
Collection::Collection(Doc* doc)
28✔
39
    : Function(doc, Function::CollectionType)
28✔
40
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
41
    , m_functionListMutex(QMutex::Recursive)
42
#endif
43
{
44
    setName(tr("New Collection"));
28✔
45

46
    // Listen to member Function removals
47
    connect(doc, SIGNAL(functionRemoved(quint32)),
28✔
48
            this, SLOT(slotFunctionRemoved(quint32)));
49
}
28✔
50

51
Collection::~Collection()
43✔
52
{
53
}
43✔
54

55
QIcon Collection::getIcon() const
×
56
{
57
    return QIcon(":/collection.png");
×
58
}
59

60
quint32 Collection::totalDuration()
1✔
61
{
62
    quint32 totalDuration = 0;
1✔
63

64
    foreach(QVariant fid, functions())
6✔
65
    {
66
        Function* function = doc()->function(fid.toUInt());
2✔
67
        totalDuration += function->totalDuration();
2✔
68
    }
69

70
    return totalDuration;
1✔
71
}
72

73
/*****************************************************************************
74
 * Copying
75
 *****************************************************************************/
76

77
Function* Collection::createCopy(Doc* doc, bool addToDoc)
1✔
78
{
79
    Q_ASSERT(doc != NULL);
1✔
80

81
    Function* copy = new Collection(doc);
1✔
82
    if (copy->copyFrom(this) == false)
1✔
83
    {
84
        delete copy;
×
85
        copy = NULL;
×
86
    }
87
    if (addToDoc == true && doc->addFunction(copy) == false)
1✔
88
    {
89
        delete copy;
×
90
        copy = NULL;
×
91
    }
92

93
    return copy;
1✔
94
}
95

96
bool Collection::copyFrom(const Function* function)
4✔
97
{
98
    const Collection* coll = qobject_cast<const Collection*> (function);
4✔
99
    if (coll == NULL)
4✔
100
        return false;
1✔
101

102
    m_functions.clear();
3✔
103
    m_functions = coll->m_functions;
3✔
104

105
    return Function::copyFrom(function);
3✔
106
}
107

108
/*****************************************************************************
109
 * Contents
110
 *****************************************************************************/
111

112
bool Collection::addFunction(quint32 fid, int insertIndex)
49✔
113
{
114
    if (fid != this->id() && m_functions.contains(fid) == false)
49✔
115
    {
116
        {
117
            QMutexLocker locker(&m_functionListMutex);
94✔
118
            if (insertIndex == -1)
47✔
119
                m_functions.append(fid);
47✔
120
            else
121
                m_functions.insert(insertIndex, fid);
×
122
        }
123

124
        emit changed(this->id());
47✔
125
        emit functionsChanged();
47✔
126
        return true;
47✔
127
    }
128
    else
129
    {
130
        return false;
2✔
131
    }
132
}
133

134
bool Collection::removeFunction(quint32 fid)
51✔
135
{
136
    int num = 0;
51✔
137
    {
138
        QMutexLocker locker(&m_functionListMutex);
51✔
139
        num = m_functions.removeAll(fid);
51✔
140
    }
141

142
    if (num > 0)
51✔
143
    {
144
        emit changed(this->id());
10✔
145
        emit functionsChanged();
10✔
146
        return true;
10✔
147
    }
148
    else
149
    {
150
        return false;
41✔
151
    }
152
}
153

154
QList<quint32> Collection::functions() const
60✔
155
{
156
    QMutexLocker locker(&m_functionListMutex);
120✔
157
    return m_functions;
120✔
158
}
159

160
void Collection::slotFunctionRemoved(quint32 fid)
48✔
161
{
162
    removeFunction(fid);
48✔
163
}
48✔
164

165
/*****************************************************************************
166
 * Load & Save
167
 *****************************************************************************/
168

169
bool Collection::saveXML(QXmlStreamWriter *doc)
2✔
170
{
171
    int i = 0;
2✔
172

173
    Q_ASSERT(doc != NULL);
2✔
174

175
    /* Function tag */
176
    doc->writeStartElement(KXMLQLCFunction);
2✔
177

178
    /* Common attributes */
179
    saveXMLCommon(doc);
2✔
180

181
    /* Steps */
182
    QListIterator <quint32> it(m_functions);
2✔
183
    while (it.hasNext() == true)
6✔
184
    {
185
        /* Step tag */
186
        doc->writeStartElement(KXMLQLCFunctionStep);
4✔
187

188
        /* Step number */
189
        doc->writeAttribute(KXMLQLCFunctionNumber, QString::number(i++));
4✔
190

191
        /* Step Function ID */
192
        doc->writeCharacters(QString::number(it.next()));
4✔
193
        doc->writeEndElement();
4✔
194
    }
195

196
    /* End the <Function> tag */
197
    doc->writeEndElement();
2✔
198

199
    return true;
4✔
200
}
201

202
bool Collection::loadXML(QXmlStreamReader &root)
10✔
203
{
204
    if (root.name() != KXMLQLCFunction)
10✔
205
    {
206
        qWarning() << Q_FUNC_INFO << "Function node not found";
1✔
207
        return false;
1✔
208
    }
209

210
    if (root.attributes().value(KXMLQLCFunctionType).toString() != typeToString(Function::CollectionType))
9✔
211
    {
212
        qWarning() << Q_FUNC_INFO << root.attributes().value(KXMLQLCFunctionType).toString()
2✔
213
                   << "is not a collection";
1✔
214
        return false;
1✔
215
    }
216

217
    /* Load collection contents */
218
    while (root.readNextStartElement())
28✔
219
    {
220
        if (root.name() == KXMLQLCFunctionStep)
20✔
221
            addFunction(root.readElementText().toUInt());
18✔
222
        else
223
        {
224
            qWarning() << Q_FUNC_INFO << "Unknown collection tag:" << root.name();
2✔
225
            root.skipCurrentElement();
2✔
226
        }
227
    }
228

229
    return true;
8✔
230
}
231

232
void Collection::postLoad()
5✔
233
{
234
    Doc* doc = qobject_cast <Doc*> (parent());
5✔
235
    Q_ASSERT(doc != NULL);
5✔
236

237
    /* Check that all member functions exist (nonexistent functions can
238
       be present only when a corrupted file has been loaded) */
239
    QMutableListIterator<quint32> it(m_functions);
5✔
240
    while (it.hasNext() == true)
18✔
241
    {
242
        /* Remove any nonexistent member functions */
243
        Function* function = doc->function(it.next());
13✔
244

245
        if (function == NULL || function->contains(id())) // forbid self-containment
13✔
246
            it.remove();
13✔
247
    }
248
}
5✔
249

250
bool Collection::contains(quint32 functionId)
7✔
251
{
252
    Doc* doc = qobject_cast <Doc*> (parent());
7✔
253
    Q_ASSERT(doc != NULL);
7✔
254

255
    foreach (quint32 fid, m_functions)
23✔
256
    {
257
        Function* function = doc->function(fid);
12✔
258
        // contains() can be called during init, function may be NULL
259
        if (function == NULL)
12✔
260
            continue;
×
261

262
        if (function->id() == functionId)
12✔
263
            return true;
3✔
264
        if (function->contains(functionId))
9✔
265
            return true;
1✔
266
    }
267

268
    return false;
3✔
269
}
270

271
QList<quint32> Collection::components()
1✔
272
{
273
    return m_functions;
1✔
274
}
275

276
/*****************************************************************************
277
 * Running
278
 *****************************************************************************/
279

280
FunctionParent Collection::functionParent() const
6✔
281
{
282
    return FunctionParent(FunctionParent::Function, id());
6✔
283
}
284

285
void Collection::preRun(MasterTimer *timer)
2✔
286
{
287
    Doc *doc = this->doc();
2✔
288
    Q_ASSERT(doc != NULL);
2✔
289
    {
290
        QMutexLocker locker(&m_functionListMutex);
2✔
291
        m_runningChildren.clear();
2✔
292
        foreach (quint32 fid, m_functions)
10✔
293
        {
294
            Function *function = doc->function(fid);
4✔
295
            Q_ASSERT(function != NULL);
4✔
296

297
            m_intensityOverrideIds << function->requestAttributeOverride(Function::Intensity, getAttributeValue(Function::Intensity));
4✔
298

299
            // Append the IDs of all functions started by this collection
300
            // to a set so that we can track which of them are still controlled
301
            // by this collection which are not.
302
            m_runningChildren << function->id();
4✔
303

304
            // Listen to the children's stopped signals so that this Collection
305
            // can give up its rights to stop the function later.
306
            connect(function, SIGNAL(stopped(quint32)),
4✔
307
                    this, SLOT(slotChildStopped(quint32)));
308

309
            // Listen to the children's stopped signals so that this collection
310
            // can give up its rights to stop the function later.
311
            connect(function, SIGNAL(running(quint32)),
4✔
312
                    this, SLOT(slotChildStarted(quint32)));
313

314
            //function->adjustAttribute(getAttributeValue(Function::Intensity), Function::Intensity);
315
            function->start(timer, functionParent(), 0, overrideFadeInSpeed(), overrideFadeOutSpeed(), overrideDuration());
4✔
316
        }
317
        m_tick = 1;
2✔
318
    }
319
    Function::preRun(timer);
2✔
320
}
2✔
321

322
void Collection::setPause(bool enable)
2✔
323
{
324
    Doc *doc = this->doc();
2✔
325
    Q_ASSERT(doc != NULL);
2✔
326
    foreach (quint32 fid, m_runningChildren)
10✔
327
    {
328
        Function *function = doc->function(fid);
4✔
329
        Q_ASSERT(function != NULL);
4✔
330
        function->setPause(enable);
4✔
331
    }
332
    Function::setPause(enable);
2✔
333
}
2✔
334

335
void Collection::write(MasterTimer *timer, QList<Universe *> universes)
8✔
336
{
337
    Q_UNUSED(timer);
338
    Q_UNUSED(universes);
339

340
    if (isPaused())
8✔
341
        return;
×
342

343
    // During first tick, children may be stopped & started.
344
    if (m_tick == 1)
8✔
345
        m_tick = 2;
2✔
346
    else if (m_tick == 2)
6✔
347
    {
348
        m_tick = 0;
2✔
349
        Doc *doc = this->doc();
2✔
350
        Q_ASSERT(doc != NULL);
2✔
351

352
        QMutexLocker locker(&m_functionListMutex);
4✔
353
        foreach (quint32 fid, m_runningChildren)
10✔
354
        {
355
            Function *function = doc->function(fid);
4✔
356
            Q_ASSERT(function != NULL);
4✔
357

358
            // First tick may correspond to this collection starting the function
359
            // Now that first tick is over, stop listening to running signal
360
            disconnect(function, SIGNAL(running(quint32)),
4✔
361
                    this, SLOT(slotChildStarted(quint32)));
362
        }
363
    }
364

365
    incrementElapsed();
8✔
366

367
    {
368
        QMutexLocker locker(&m_functionListMutex);
8✔
369
        if (m_runningChildren.size() > 0)
8✔
370
            return;
7✔
371
    }
372

373
    stop(functionParent());
1✔
374
}
375

376
void Collection::postRun(MasterTimer* timer, QList<Universe *> universes)
1✔
377
{
378
    Doc* doc = qobject_cast <Doc*> (parent());
1✔
379
    Q_ASSERT(doc != NULL);
1✔
380

381
    {
382
        QMutexLocker locker(&m_functionListMutex);
2✔
383
        /** Stop the member functions only if they have been started by this
384
            collection. */
385
        QSetIterator <quint32> it(m_runningChildren);
2✔
386
        while (it.hasNext() == true)
2✔
387
        {
388
            Function* function = doc->function(it.next());
1✔
389
            Q_ASSERT(function != NULL);
1✔
390
            function->stop(functionParent());
1✔
391
        }
392

393
        m_runningChildren.clear();
1✔
394

395
        for (int i = 0; i < m_functions.count(); i++)
3✔
396
        {
397
            Function* function = doc->function(m_functions.at(i));
2✔
398
            Q_ASSERT(function != NULL);
2✔
399

400
            disconnect(function, SIGNAL(stopped(quint32)),
2✔
401
                    this, SLOT(slotChildStopped(quint32)));
402
            if (m_tick == 2)
2✔
403
            {
404
                disconnect(function, SIGNAL(running(quint32)),
×
405
                        this, SLOT(slotChildStarted(quint32)));
406
            }
407
        }
408

409
        m_intensityOverrideIds.clear();
1✔
410
    }
411

412
    Function::postRun(timer, universes);
1✔
413
}
1✔
414

415
void Collection::slotChildStopped(quint32 fid)
3✔
416
{
417
    QMutexLocker locker(&m_functionListMutex);
6✔
418
    m_runningChildren.remove(fid);
3✔
419
}
3✔
420

421
void Collection::slotChildStarted(quint32 fid)
4✔
422
{
423
    QMutexLocker locker(&m_functionListMutex);
8✔
424
    m_runningChildren << fid;
4✔
425
}
4✔
426

427
int Collection::adjustAttribute(qreal fraction, int attributeId)
1✔
428
{
429
    int attrIndex = Function::adjustAttribute(fraction, attributeId);
1✔
430

431
    if (isRunning() && attrIndex == Intensity)
1✔
432
    {
433
        Doc* document = doc();
1✔
434
        Q_ASSERT(document != NULL);
1✔
435

436
        QMutexLocker locker(&m_functionListMutex);
2✔
437

438
        for (int i = 0; i < m_functions.count(); i++)
3✔
439
        {
440
            Function* function = document->function(m_functions.at(i));
2✔
441
            Q_ASSERT(function != NULL);
2✔
442
            function->adjustAttribute(getAttributeValue(Function::Intensity), m_intensityOverrideIds.at(i));
2✔
443
        }
444
    }
445

446
    return attrIndex;
1✔
447
}
448

449
void Collection::setBlendMode(Universe::BlendMode mode)
6✔
450
{
451
    if (mode == blendMode())
6✔
452
        return;
5✔
453

454
    qDebug() << "Collection" << name() << "blend mode set to" << Universe::blendModeToString(mode);
1✔
455

456
    if (isRunning())
1✔
457
    {
458
        for (int i = 0; i < m_functions.count(); i++)
3✔
459
        {
460
            Function* function = doc()->function(m_functions.at(i));
2✔
461
            Q_ASSERT(function != NULL);
2✔
462
            function->setBlendMode(mode);
2✔
463
        }
464
    }
465

466
    Function::setBlendMode(mode);
1✔
467
}
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