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

mcallegari / qlcplus / 14547220756

19 Apr 2025 08:04AM UTC coverage: 31.866% (+0.01%) from 31.854%
14547220756

Pull #1720

github

web-flow
Merge e5637eaa5 into 2603830c2
Pull Request #1720: Update Eurolite-LED-KLS-2500.qxf

14684 of 46080 relevant lines covered (31.87%)

26448.78 hits per line

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

95.71
/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 QString("Head")
31
#define KXMLQLCFixtureGroupSize QString("Size")
32
#define KXMLQLCFixtureGroupName QString("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);
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();
2✔
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);
112
    QLCPoint tmp = pt;
188✔
113
    int headAddedcount = 0;
114

115
    for (int i = 0; i < fxi->heads(); i++)
627✔
116
    {
117
        if (pt.isNull())
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);
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)
880✔
142
        return false;
143

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

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

158
        while (1)
159
        {
160
            for (; y < ymax; y++)
1,137✔
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
    foreach (QLCPoint pt, m_heads.keys())
70✔
185
    {
186
        if (m_heads[pt].fxi == id)
62✔
187
            m_heads.remove(pt);
2✔
188
    }
189

190
    emit changed(this->id());
4✔
191
}
4✔
192

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

199
    return removed;
19✔
200
}
201

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

207
    if (ah.isValid() == true)
3✔
208
        m_heads[b] = ah;
2✔
209
    else
210
        m_heads.remove(b);
1✔
211

212
    if (bh.isValid() == true)
3✔
213
        m_heads[a] = bh;
2✔
214
    else
215
        m_heads.remove(a);
1✔
216

217
    emit changed(this->id());
3✔
218
}
3✔
219

220
void FixtureGroup::reset()
×
221
{
222
    m_heads.clear();
×
223
    emit changed(this->id());
×
224
}
×
225

226
GroupHead FixtureGroup::head(const QLCPoint& pt) const
96✔
227
{
228
    return m_heads.value(pt);
96✔
229
}
230

231
QList <GroupHead> FixtureGroup::headList() const
34✔
232
{
233
    return m_heads.values();
34✔
234
}
235

236
QMap<QLCPoint, GroupHead> FixtureGroup::headsMap() const
51✔
237
{
238
    return m_heads;
51✔
239
}
240

241
QList <quint32> FixtureGroup::fixtureList() const
35✔
242
{
243
    QList <quint32> list;
244

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

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

259
/****************************************************************************
260
 * Size
261
 ****************************************************************************/
262

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

269
QSize FixtureGroup::size() const
637✔
270
{
271
    return m_size;
637✔
272
}
273

274
/****************************************************************************
275
 * Load & Save
276
 ****************************************************************************/
277

278
bool FixtureGroup::loader(QXmlStreamReader &xmlDoc, Doc* doc)
5✔
279
{
280
    bool result = false;
281

282
    FixtureGroup* grp = new FixtureGroup(doc);
5✔
283
    Q_ASSERT(grp != NULL);
284

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

297
    return result;
5✔
298
}
299

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

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

316
    // Assign the ID to myself
317
    m_id = id;
9✔
318

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

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

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

355
    return true;
356
}
357

358
bool FixtureGroup::saveXML(QXmlStreamWriter *doc)
4✔
359
{
360
    Q_ASSERT(doc != NULL);
361

362
    /* Fixture Group entry */
363
    doc->writeStartElement(KXMLQLCFixtureGroup);
4✔
364
    doc->writeAttribute(KXMLQLCFixtureGroupID, QString::number(this->id()));
4✔
365

366
    /* Name */
367
    doc->writeTextElement(KXMLQLCFixtureGroupName, name());
4✔
368

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

375
    /* Fixture heads */
376
    QList<QLCPoint> pointsList = m_heads.keys();
4✔
377

378
    foreach (QLCPoint pt, pointsList)
68✔
379
    {
380
        GroupHead head = m_heads[pt];
64✔
381
        doc->writeStartElement(KXMLQLCFixtureGroupHead);
64✔
382
        doc->writeAttribute("X", QString::number(pt.x()));
64✔
383
        doc->writeAttribute("Y", QString::number(pt.y()));
64✔
384
        doc->writeAttribute("Fixture", QString::number(head.fxi));
64✔
385
        doc->writeCharacters(QString::number(head.head));
64✔
386
        doc->writeEndElement();
64✔
387
    }
64✔
388

389
    doc->writeEndElement();
4✔
390

391
    return true;
4✔
392
}
4✔
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