• 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

95.65
/engine/src/fixturegroup.cpp
1
/*
2
  Q Light Controller Plus
3
  fixturegroup.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 <QXmlStreamWriter>
23
#include <QDebug>
24

25
#include "fixturegroup.h"
26
#include "qlcpoint.h"
27
#include "fixture.h"
28
#include "doc.h"
29

30
#define KXMLQLCFixtureGroupHead QStringLiteral("Head")
31
#define KXMLQLCFixtureGroupSize QStringLiteral("Size")
32
#define KXMLQLCFixtureGroupName QStringLiteral("Name")
33

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

38
FixtureGroup::FixtureGroup(Doc* parent)
30✔
39
    : QObject(parent)
40
    , m_id(FixtureGroup::invalidId())
30✔
41
{
42
    Q_ASSERT(parent != NULL);
30✔
43

44
    // Listen to fixture removals
45
    connect(parent, SIGNAL(fixtureRemoved(quint32)),
30✔
46
            this, SLOT(slotFixtureRemoved(quint32)));
47
}
30✔
48

49
FixtureGroup::~FixtureGroup()
44✔
50
{
51
}
44✔
52

53
void FixtureGroup::copyFrom(const FixtureGroup* grp)
1✔
54
{
55
    // Don't copy ID
56
    m_name = grp->name();
1✔
57
    m_size = grp->size();
1✔
58
    m_heads = grp->headsMap();
1✔
59
}
1✔
60

61
Doc* FixtureGroup::doc() const
188✔
62
{
63
    return qobject_cast<Doc*> (parent());
188✔
64
}
65

66
/****************************************************************************
67
 * ID
68
 ****************************************************************************/
69

70
void FixtureGroup::setId(quint32 id)
18✔
71
{
72
    m_id = id;
18✔
73
}
18✔
74

75
quint32 FixtureGroup::id() const
269✔
76
{
77
    return m_id;
269✔
78
}
79

80
quint32 FixtureGroup::invalidId()
89✔
81
{
82
    return UINT_MAX;
89✔
83
}
84

85
/****************************************************************************
86
 * Name
87
 ****************************************************************************/
88

89
void FixtureGroup::setName(const QString& name)
8✔
90
{
91
    if (m_name == name)
8✔
92
        return;
×
93

94
    m_name = name;
8✔
95
    emit nameChanged();
8✔
96
    emit changed(this->id());
8✔
97
}
98

99
QString FixtureGroup::name() const
11✔
100
{
101
    return m_name;
11✔
102
}
103

104
/****************************************************************************
105
 * Fixtures
106
 ****************************************************************************/
107

108
bool FixtureGroup::assignFixture(quint32 id, const QLCPoint& pt)
188✔
109
{
110
    Fixture* fxi = doc()->fixture(id);
188✔
111
    Q_ASSERT(fxi != NULL);
188✔
112
    QLCPoint tmp = pt;
188✔
113
    int headAddedcount = 0;
188✔
114

115
    for (int i = 0; i < fxi->heads(); i++)
627✔
116
    {
117
        if (pt.isNull())
439✔
118
        {
119
            if (assignHead(pt, GroupHead(fxi->id(), i)) == true)
432✔
120
                headAddedcount++;
192✔
121
        }
122
        else
123
        {
124
            if (assignHead(tmp, GroupHead(fxi->id(), i)) == true)
7✔
125
                headAddedcount++;
5✔
126

127
            tmp.setX(tmp.x() + 1);
7✔
128
            if (tmp.x() >= size().width())
7✔
129
            {
130
                tmp.setX(0);
4✔
131
                tmp.setY(tmp.y() + 1);
4✔
132
            }
133
        }
134
    }
135

136
    return headAddedcount ? true : false;
188✔
137
}
138

139
bool FixtureGroup::assignHead(const QLCPoint& pt, const GroupHead& head)
440✔
140
{
141
    if (m_heads.values().contains(head) == true)
440✔
142
        return false;
242✔
143

144
    if (size().isValid() == false)
198✔
145
        setSize(QSize(1, 1));
1✔
146

147
    if (pt.isNull() == false)
198✔
148
    {
149
        m_heads[pt] = head;
5✔
150
    }
151
    else
152
    {
153
        int y = 0;
193✔
154
        int x = 0;
193✔
155
        int xmax = size().width();
193✔
156
        int ymax = size().height();
193✔
157

158
        while (1)
159
        {
160
            for (; y < ymax; y++)
704✔
161
            {
162
                for (x = 0; x < xmax; x++)
2,610✔
163
                {
164
                    QLCPoint tmp(x, y);
2,177✔
165
                    if (m_heads.contains(tmp) == false)
2,177✔
166
                    {
167
                        m_heads[tmp] = head;
193✔
168
                        emit changed(this->id());
193✔
169
                        return true;
193✔
170
                    }
171
                }
172
            }
173

174
            ymax++;
78✔
175
        }
78✔
176
    }
177

178
    emit changed(this->id());
5✔
179
    return true;
5✔
180
}
181

182
void FixtureGroup::resignFixture(quint32 id)
4✔
183
{
184
    QMap <QLCPoint,GroupHead>::iterator it = m_heads.begin();
4✔
185
    while(it != m_heads.end())
66✔
186
    {
187
        if (it.value().fxi == id)
62✔
188
            it = m_heads.erase(it);
2✔
189
        else
190
            it++;
60✔
191
    }
192

193
    emit changed(this->id());
4✔
194
}
4✔
195

196
bool FixtureGroup::resignHead(const QLCPoint& pt)
19✔
197
{
198
    const int removed = m_heads.remove(pt);
19✔
199
    if (removed)
19✔
200
        emit changed(this->id());
17✔
201

202
    return removed;
19✔
203
}
204

205
void FixtureGroup::swap(const QLCPoint& a, const QLCPoint& b)
3✔
206
{
207
    GroupHead ah = m_heads.value(a);
3✔
208
    GroupHead bh = m_heads.value(b);
3✔
209

210
    if (ah.isValid() == true)
3✔
211
        m_heads[b] = ah;
2✔
212
    else
213
        m_heads.remove(b);
1✔
214

215
    if (bh.isValid() == true)
3✔
216
        m_heads[a] = bh;
2✔
217
    else
218
        m_heads.remove(a);
1✔
219

220
    emit changed(this->id());
3✔
221
}
3✔
222

223
void FixtureGroup::reset()
×
224
{
225
    m_heads.clear();
×
226
    emit changed(this->id());
×
227
}
×
228

229
GroupHead FixtureGroup::head(const QLCPoint& pt) const
96✔
230
{
231
    return m_heads.value(pt);
96✔
232
}
233

234
QList <GroupHead> FixtureGroup::headList() const
34✔
235
{
236
    return m_heads.values();
34✔
237
}
238

239
QMap<QLCPoint, GroupHead> FixtureGroup::headsMap() const
51✔
240
{
241
    return m_heads;
51✔
242
}
243

244
QList <quint32> FixtureGroup::fixtureList() const
35✔
245
{
246
    QList <quint32> list;
35✔
247

248
    foreach (GroupHead head, m_heads)
468✔
249
    {
250
        if (list.contains(head.fxi) == false)
433✔
251
            list << head.fxi;
328✔
252
    }
468✔
253
    return list;
35✔
254
}
×
255

256
void FixtureGroup::slotFixtureRemoved(quint32 id)
2✔
257
{
258
    // Remove the fixture from group records since it's no longer there
259
    resignFixture(id);
2✔
260
}
2✔
261

262
/****************************************************************************
263
 * Size
264
 ****************************************************************************/
265

266
void FixtureGroup::setSize(const QSize& sz)
13✔
267
{
268
    m_size = sz;
13✔
269
    emit changed(this->id());
13✔
270
}
13✔
271

272
QSize FixtureGroup::size() const
637✔
273
{
274
    return m_size;
637✔
275
}
276

277
/****************************************************************************
278
 * Load & Save
279
 ****************************************************************************/
280

281
bool FixtureGroup::loader(QXmlStreamReader &xmlDoc, Doc* doc)
5✔
282
{
283
    bool result = false;
5✔
284

285
    FixtureGroup* grp = new FixtureGroup(doc);
5✔
286
    Q_ASSERT(grp != NULL);
5✔
287

288
    if (grp->loadXML(xmlDoc) == true)
5✔
289
    {
290
        doc->addFixtureGroup(grp, grp->id());
4✔
291
        result = true;
4✔
292
    }
293
    else
294
    {
295
        qWarning() << Q_FUNC_INFO << "FixtureGroup" << grp->name() << "cannot be loaded.";
1✔
296
        delete grp;
1✔
297
        result = false;
1✔
298
    }
299

300
    return result;
5✔
301
}
302

303
bool FixtureGroup::loadXML(QXmlStreamReader &xmlDoc)
11✔
304
{
305
    if (xmlDoc.name() != KXMLQLCFixtureGroup)
11✔
306
    {
307
        qWarning() << Q_FUNC_INFO << "Fixture group node not found";
1✔
308
        return false;
1✔
309
    }
310

311
    bool ok = false;
10✔
312
    quint32 id = xmlDoc.attributes().value(KXMLQLCFixtureGroupID).toString().toUInt(&ok);
20✔
313
    if (ok == false)
10✔
314
    {
315
        qWarning() << "Invalid FixtureGroup ID:" << xmlDoc.attributes().value(KXMLQLCFixtureGroupID).toString();
2✔
316
        return false;
1✔
317
    }
318

319
    // Assign the ID to myself
320
    m_id = id;
9✔
321

322
    while (xmlDoc.readNextStartElement())
51✔
323
    {
324
        QXmlStreamAttributes attrs = xmlDoc.attributes();
42✔
325
        if (xmlDoc.name() == KXMLQLCFixtureGroupHead)
42✔
326
        {
327
            bool xok = false, yok = false, idok = false, headok = false;
37✔
328
            int x = attrs.value("X").toString().toInt(&xok);
37✔
329
            int y = attrs.value("Y").toString().toInt(&yok);
37✔
330
            quint32 id = attrs.value("Fixture").toString().toUInt(&idok);
37✔
331
            int head = xmlDoc.readElementText().toInt(&headok);
37✔
332

333
            // Don't use assignFixture() here because it assigns complete fixtures at once
334
            if (xok == true && yok == true && idok == true && headok == true)
37✔
335
                m_heads[QLCPoint(x, y)] = GroupHead(id, head);
33✔
336
        }
337
        else if (xmlDoc.name() == KXMLQLCFixtureGroupSize)
5✔
338
        {
339
            bool xok = false, yok = false;
1✔
340
            int x = attrs.value("X").toString().toInt(&xok);
1✔
341
            int y = attrs.value("Y").toString().toInt(&yok);
1✔
342

343
            if (xok == true && yok == true)
1✔
344
                m_size = QSize(x, y);
1✔
345
            xmlDoc.skipCurrentElement();
1✔
346
        }
347
        else if (xmlDoc.name() == KXMLQLCFixtureGroupName)
4✔
348
        {
349
            m_name = xmlDoc.readElementText();
4✔
350
        }
351
        else
352
        {
353
            qWarning() << Q_FUNC_INFO << "Unknown fixture group tag:" << xmlDoc.name();
×
354
            xmlDoc.skipCurrentElement();
×
355
        }
356
    }
42✔
357

358
    return true;
9✔
359
}
360

361
bool FixtureGroup::saveXML(QXmlStreamWriter *doc)
4✔
362
{
363
    Q_ASSERT(doc != NULL);
4✔
364

365
    /* Fixture Group entry */
366
    doc->writeStartElement(KXMLQLCFixtureGroup);
8✔
367
    doc->writeAttribute(KXMLQLCFixtureGroupID, QString::number(this->id()));
8✔
368

369
    /* Name */
370
    doc->writeTextElement(KXMLQLCFixtureGroupName, name());
8✔
371

372
    /* Matrix size */
373
    doc->writeStartElement(KXMLQLCFixtureGroupSize);
8✔
374
    doc->writeAttribute("X", QString::number(size().width()));
8✔
375
    doc->writeAttribute("Y", QString::number(size().height()));
8✔
376
    doc->writeEndElement();
4✔
377

378
    /* Fixture heads */
379
    QMap <QLCPoint,GroupHead>::iterator it = m_heads.begin();
4✔
380
    for (; it != m_heads.end(); it++)
68✔
381
    {
382
        QLCPoint pt = it.key();
64✔
383
        GroupHead head = it.value();
64✔
384
        doc->writeStartElement(KXMLQLCFixtureGroupHead);
128✔
385
        doc->writeAttribute("X", QString::number(pt.x()));
128✔
386
        doc->writeAttribute("Y", QString::number(pt.y()));
128✔
387
        doc->writeAttribute("Fixture", QString::number(head.fxi));
128✔
388
        doc->writeCharacters(QString::number(head.head));
64✔
389
        doc->writeEndElement();
64✔
390
    }
64✔
391

392
    doc->writeEndElement();
4✔
393

394
    return true;
4✔
395
}
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