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

mcallegari / qlcplus / 19144422256

06 Nov 2025 05:33PM UTC coverage: 34.256% (-0.1%) from 34.358%
19144422256

push

github

mcallegari
Back to 5.1.0 debug

17718 of 51723 relevant lines covered (34.26%)

19528.23 hits per line

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

89.57
/engine/src/qlcfixturemode.cpp
1
/*
2
  Q Light Controller Plus
3
  qlcfixturemode.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 <QXmlStreamReader>
22
#include <iostream>
23
#include <QString>
24
#include <QDebug>
25
#include <QVector>
26

27
#include "qlcfixturemode.h"
28
#include "qlcfixturehead.h"
29
#include "qlcfixturedef.h"
30
#include "qlcchannel.h"
31
#include "qlcphysical.h"
32

33
QLCFixtureMode::QLCFixtureMode(QLCFixtureDef *fixtureDef)
414✔
34
    : m_fixtureDef(fixtureDef)
414✔
35
    , m_masterIntensityChannel(QLCChannel::invalid())
414✔
36
    , m_useGlobalPhysical(true)
828✔
37
{
38
    Q_ASSERT(fixtureDef != NULL);
414✔
39
}
414✔
40

41
QLCFixtureMode::QLCFixtureMode(QLCFixtureDef *fixtureDef, const QLCFixtureMode *mode)
3✔
42
    : m_fixtureDef(fixtureDef)
3✔
43
    , m_masterIntensityChannel(QLCChannel::invalid())
3✔
44
    , m_useGlobalPhysical(true)
6✔
45
{
46
    Q_ASSERT(fixtureDef != NULL);
3✔
47
    Q_ASSERT(mode != NULL);
3✔
48

49
    if (mode != NULL)
3✔
50
        *this = *mode;
3✔
51
}
3✔
52

53
QLCFixtureMode::~QLCFixtureMode()
342✔
54
{
55
}
342✔
56

57
QLCFixtureMode& QLCFixtureMode::operator=(const QLCFixtureMode& mode)
3✔
58
{
59
    if (this != &mode)
3✔
60
    {
61
        m_name = mode.m_name;
3✔
62
        m_useGlobalPhysical = mode.m_useGlobalPhysical;
3✔
63
        m_physical = mode.m_physical;
3✔
64
        m_heads = mode.m_heads;
3✔
65
        m_masterIntensityChannel = QLCChannel::invalid();
3✔
66

67
        m_actsOnMap = mode.m_actsOnMap;
3✔
68

69
        /* Clear the existing list of channels */
70
        m_channels.clear();
3✔
71

72
        Q_ASSERT(m_fixtureDef != NULL);
3✔
73

74
        quint32 i = 0;
3✔
75
        QVectorIterator <QLCChannel*> it(mode.m_channels);
3✔
76
        while (it.hasNext() == true)
12✔
77
        {
78
            /* Since m_fixtureDef might not be the same as
79
               mode.m_fixtureDef, we need to search for a
80
               channel with the same name from m_fixtureDef and
81
               not from mode.m_fixtureDef. If the channel in the
82
               other mode is deleted, the one in this copied mode
83
               will be invalid and we end up in a crash. */
84
            QLCChannel* ch = it.next();
9✔
85
            QLCChannel* actual = m_fixtureDef->channel(ch->name());
9✔
86
            if (actual != NULL)
9✔
87
                insertChannel(actual, i++);
7✔
88
            else
89
                qWarning() << Q_FUNC_INFO << "Unable to find channel"
4✔
90
                           << ch->name() << "for mode"
4✔
91
                           << m_name << "from its fixture definition";
2✔
92
        }
93
    }
3✔
94

95
    return *this;
3✔
96
}
97

98
/****************************************************************************
99
 * Name
100
 ****************************************************************************/
101

102
void QLCFixtureMode::setName(const QString &name)
391✔
103
{
104
    m_name = name;
391✔
105
}
391✔
106

107
QString QLCFixtureMode::name() const
109✔
108
{
109
    return m_name;
109✔
110
}
111

112
/*****************************************************************************
113
 * Fixture definition
114
 *****************************************************************************/
115

116
QLCFixtureDef* QLCFixtureMode::fixtureDef() const
56✔
117
{
118
    return m_fixtureDef;
56✔
119
}
120

121
/****************************************************************************
122
 * Channels
123
 ****************************************************************************/
124

125
bool QLCFixtureMode::insertChannel(QLCChannel* channel, quint32 index)
2,523✔
126
{
127
    if (channel == NULL)
2,523✔
128
    {
129
        qWarning() << Q_FUNC_INFO << "Will not add a NULL channel to mode"
2✔
130
                   << m_name;
1✔
131
        return false;
1✔
132
    }
133

134
    Q_ASSERT(m_fixtureDef != NULL);
2,522✔
135

136
    if (m_fixtureDef->channels().contains(channel) == true)
2,522✔
137
    {
138
        if (m_channels.contains(channel) == false)
2,521✔
139
        {
140
            if (index >= quint32(m_channels.size()))
2,520✔
141
                m_channels.append(channel);
2,518✔
142
            else
143
                m_channels.insert(index, channel);
2✔
144
            return true;
2,520✔
145
        }
146
        else
147
        {
148
            qWarning() << Q_FUNC_INFO << "Channel" << channel->name()
2✔
149
                       << "is already a member of mode" << m_name;
1✔
150
            return false;
1✔
151
        }
152
    }
153
    else
154
    {
155
        qWarning() << Q_FUNC_INFO << "Will not add channel" << channel->name()
2✔
156
                   << "to mode" << m_name
1✔
157
                   << "because the channel does not belong to mode's"
1✔
158
                   << "parent fixture definition.";
1✔
159
        return false;
1✔
160
    }
161
}
162

163
bool QLCFixtureMode::removeChannel(const QLCChannel* channel)
7✔
164
{
165
    QMutableVectorIterator <QLCChannel*> it(m_channels);
7✔
166
    while (it.hasNext() == true)
17✔
167
    {
168
        if (it.next() == channel)
15✔
169
        {
170
            /* Don't delete the channel since QLCFixtureModes
171
               don't own them. QLCFixtureDefs do. */
172
            it.remove();
5✔
173
            return true;
5✔
174
        }
175
    }
176

177
    return false;
2✔
178
}
179

180
bool QLCFixtureMode::replaceChannel(QLCChannel *currChannel, QLCChannel *newChannel)
×
181
{
182
    if (currChannel == NULL || newChannel == NULL)
×
183
        return false;
×
184

185
    int chIndex = m_channels.indexOf(currChannel);
×
186
    if (chIndex == -1)
×
187
        return false;
×
188

189
    m_channels.replace(chIndex, newChannel);
×
190

191
    return true;
×
192
}
193

194
void QLCFixtureMode::removeAllChannels()
×
195
{
196
    m_channels.clear();
×
197
}
×
198

199
QLCChannel* QLCFixtureMode::channel(const QString& name) const
6✔
200
{
201
    QVectorIterator <QLCChannel*> it(m_channels);
6✔
202
    while (it.hasNext() == true)
20✔
203
    {
204
        QLCChannel* ch = it.next();
18✔
205
        Q_ASSERT(ch != NULL);
18✔
206
        if (ch->name() == name)
18✔
207
            return ch;
4✔
208
    }
209

210
    return NULL;
2✔
211
}
6✔
212

213
QLCChannel* QLCFixtureMode::channel(quint32 ch) const
801,579✔
214
{
215
    return m_channels.value(ch, NULL);
801,579✔
216
}
217

218
QVector <QLCChannel*> QLCFixtureMode::channels() const
15,132✔
219
{
220
    return m_channels;
15,132✔
221
}
222

223
quint32 QLCFixtureMode::channelNumber(QLCChannel *channel) const
6✔
224
{
225
    if (channel == NULL)
6✔
226
        return QLCChannel::invalid();
1✔
227

228
    int idx = m_channels.indexOf(channel);
5✔
229
    return idx == -1 ? QLCChannel::invalid() : idx;
5✔
230
}
231

232
quint32 QLCFixtureMode::channelNumber(QLCChannel::Group group, QLCChannel::ControlByte cByte) const
3,984✔
233
{
234
    for (int i = 0; i < m_channels.size(); i++)
51,532✔
235
    {
236
        if (m_channels.at(i)->group() == group &&
47,907✔
237
            m_channels.at(i)->controlByte() == cByte)
308✔
238
            return i;
51✔
239
    }
240

241
    return QLCChannel::invalid();
3,933✔
242
}
243

244
quint32 QLCFixtureMode::masterIntensityChannel() const
40✔
245
{
246
    return m_masterIntensityChannel;
40✔
247
}
248

249
quint32 QLCFixtureMode::primaryChannel(quint32 chIndex)
795,216✔
250
{
251
    return m_secondaryMap.value(chIndex, QLCChannel::invalid());
795,216✔
252
}
253

254
quint32 QLCFixtureMode::channelActsOn(quint32 chIndex)
×
255
{
256
    return m_actsOnMap.value(chIndex, QLCChannel::invalid());
×
257
}
258

259
void QLCFixtureMode::setChannelActsOn(quint32 chIndex, quint32 actsOnIndex)
×
260
{
261
    if (actsOnIndex != QLCChannel::invalid())
×
262
        m_actsOnMap[chIndex] = actsOnIndex;
×
263
    else
264
        m_actsOnMap.remove(chIndex);
×
265
}
×
266

267
/*****************************************************************************
268
 * Heads
269
 *****************************************************************************/
270

271
void QLCFixtureMode::insertHead(int index, const QLCFixtureHead& head)
1,033✔
272
{
273
    if (index < 0 || index >= m_heads.size())
1,033✔
274
        m_heads.append(head);
1,032✔
275
    else
276
        m_heads.insert(index, head);
1✔
277
}
1,033✔
278

279
void QLCFixtureMode::removeHead(int index)
4✔
280
{
281
    if (index >= 0 && index < m_heads.size())
4✔
282
        m_heads.remove(index);
3✔
283
}
4✔
284

285
void QLCFixtureMode::replaceHead(int index, const QLCFixtureHead& head)
2✔
286
{
287
    if (index >= 0 && index < m_heads.size())
2✔
288
        m_heads[index] = head;
1✔
289
}
2✔
290

291
QVector <QLCFixtureHead> const& QLCFixtureMode::heads() const
2,018✔
292
{
293
    return m_heads;
2,018✔
294
}
295

296
int QLCFixtureMode::headForChannel(quint32 chnum) const
887✔
297
{
298
    for (int i = 0; i < m_heads.size(); i++)
3,570✔
299
    {
300
        if (m_heads[i].channels().contains(chnum) == true)
3,480✔
301
            return i;
797✔
302
    }
303

304
    return -1;
90✔
305
}
306

307
void QLCFixtureMode::cacheHeads()
600✔
308
{
309
    QLCChannel *lastChannel = NULL;
600✔
310

311
    for (int i = 0; i < m_heads.size(); i++)
1,984✔
312
    {
313
        QLCFixtureHead& head(m_heads[i]);
1,384✔
314
        head.cacheChannels(this);
1,384✔
315
    }
316

317
    for (quint32 i = 0; i < quint32(m_channels.size()); i++)
5,361✔
318
    {
319
        QLCChannel *channel = m_channels.at(i);
4,761✔
320

321
        /** Auto-detect master intensity channel */
322
        if (m_masterIntensityChannel == QLCChannel::invalid() &&
4,761✔
323
            channel->group() == QLCChannel::Intensity &&
2,245✔
324
            channel->controlByte() == QLCChannel::MSB &&
1,740✔
325
            channel->colour() == QLCChannel::NoColour &&
7,893✔
326
            headForChannel(i) == -1)
887✔
327
        {
328
            m_masterIntensityChannel = i;
90✔
329
        }
330

331
        /** Map secondary channels */
332
        if (lastChannel != NULL &&
8,922✔
333
            channel->group() == lastChannel->group() &&
4,161✔
334
            lastChannel->controlByte() == QLCChannel::MSB &&
11,224✔
335
            channel->controlByte() == QLCChannel::LSB)
2,302✔
336
        {
337
            //qDebug() << "Channel" << lastChannel->name() << "is primary and" << channel->name() << "is secondary";
338
            m_secondaryMap[i] = i - 1;
264✔
339
        }
340

341
        lastChannel = channel;
4,761✔
342
    }
343
}
600✔
344

345
/****************************************************************************
346
 * Physical
347
 ****************************************************************************/
348

349
void QLCFixtureMode::setPhysical(const QLCPhysical& physical)
245✔
350
{
351
    m_useGlobalPhysical = false;
245✔
352
    m_physical = physical;
245✔
353
}
245✔
354

355
void QLCFixtureMode::resetPhysical()
×
356
{
357
    m_useGlobalPhysical = true;
×
358
}
×
359

360
bool QLCFixtureMode::useGlobalPhysical()
2✔
361
{
362
    return m_useGlobalPhysical;
2✔
363
}
364

365
QLCPhysical QLCFixtureMode::physical() const
66✔
366
{
367
    if (m_useGlobalPhysical)
66✔
368
        return fixtureDef()->physical();
55✔
369

370
    return m_physical;
11✔
371
}
372

373
/****************************************************************************
374
 * Load & Save
375
 ****************************************************************************/
376

377
bool QLCFixtureMode::loadXML(QXmlStreamReader &doc)
141✔
378
{
379
    if (doc.name() != KXMLQLCFixtureMode)
141✔
380
    {
381
        qWarning() << Q_FUNC_INFO << "Mode tag not found";
1✔
382
        return false;
1✔
383
    }
384

385
    /* Mode name */
386
    QString str = doc.attributes().value(KXMLQLCFixtureModeName).toString();
280✔
387
    if (str.isEmpty() == true)
140✔
388
    {
389
        qWarning() << Q_FUNC_INFO << "Mode has no name";
1✔
390
        return false;
1✔
391
    }
392
    else
393
    {
394
        setName(str);
139✔
395
    }
396

397
    /* Subtags */
398
    while (doc.readNextStartElement())
1,780✔
399
    {
400
        if (doc.name() == KXMLQLCFixtureModeChannel)
1,641✔
401
        {
402
            /* Channel */
403
            Q_ASSERT(m_fixtureDef != NULL);
1,455✔
404
            str = doc.attributes().value(KXMLQLCFixtureModeChannelNumber).toString();
2,910✔
405

406
            quint32 actsOnChannelIndex = QLCChannel::invalid();
1,455✔
407

408
            if (doc.attributes().hasAttribute(KXMLQLCFixtureModeChannelActsOn))
2,910✔
409
                actsOnChannelIndex = doc.attributes().value(KXMLQLCFixtureModeChannelActsOn).toUInt();
×
410

411
            QLCChannel *currentChannel = m_fixtureDef->channel(doc.readElementText());
1,455✔
412

413
            if (actsOnChannelIndex != QLCChannel::invalid())
1,455✔
414
                m_actsOnMap[str.toInt()] = actsOnChannelIndex;
×
415

416
            insertChannel(currentChannel, str.toInt());
1,455✔
417
        }
418
        else if (doc.name() == KXMLQLCFixtureHead)
186✔
419
        {
420
            /* Head */
421
            QLCFixtureHead head;
184✔
422
            if (head.loadXML(doc) == true)
184✔
423
                insertHead(-1, head);
184✔
424
        }
184✔
425
        else if (doc.name() == KXMLQLCPhysical)
2✔
426
        {
427
            /* Physical */
428
            QLCPhysical physical;
1✔
429
            physical.loadXML(doc);
1✔
430
            setPhysical(physical);
1✔
431
        }
1✔
432
        else
433
        {
434
            qWarning() << Q_FUNC_INFO << "Unknown Fixture Mode tag:" << doc.name();
1✔
435
            doc.skipCurrentElement();
1✔
436
        }
437
    }
438

439
    // Cache all head channels
440
    cacheHeads();
139✔
441

442
    return true;
139✔
443
}
140✔
444

445
bool QLCFixtureMode::saveXML(QXmlStreamWriter *doc)
3✔
446
{
447
    int i = 0;
3✔
448

449
    Q_ASSERT(doc != NULL);
3✔
450

451
    /* Mode entry */
452
    doc->writeStartElement(KXMLQLCFixtureMode);
6✔
453
    doc->writeAttribute(KXMLQLCFixtureModeName, m_name);
6✔
454

455
    if (m_useGlobalPhysical == false)
3✔
456
        m_physical.saveXML(doc);
1✔
457

458
    /* Channels */
459
    QVectorIterator <QLCChannel*> it(m_channels);
3✔
460
    while (it.hasNext() == true)
8✔
461
    {
462
        QLCChannel *channel = it.next();
5✔
463
        quint32 actsOnIndex = m_actsOnMap.value(i, QLCChannel::invalid());
5✔
464

465
        doc->writeStartElement(KXMLQLCFixtureModeChannel);
10✔
466
        doc->writeAttribute(KXMLQLCFixtureModeChannelNumber, QString::number(i++));
10✔
467
        if (actsOnIndex != QLCChannel::invalid())
5✔
468
            doc->writeAttribute(KXMLQLCFixtureModeChannelActsOn, QString::number(actsOnIndex));
×
469

470
        doc->writeCharacters(channel->name());
5✔
471
        doc->writeEndElement();
5✔
472
    }
473

474
    /* Heads */
475
    QVectorIterator <QLCFixtureHead> hit(m_heads);
3✔
476
    while (hit.hasNext() == true)
6✔
477
        hit.next().saveXML(doc);
3✔
478

479
    doc->writeEndElement();
3✔
480

481
    return true;
3✔
482
}
3✔
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