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

mcallegari / qlcplus / 20794594664

07 Jan 2026 07:52PM UTC coverage: 34.17% (-0.1%) from 34.276%
20794594664

push

github

mcallegari
Back to 5.1.1 debug

17716 of 51846 relevant lines covered (34.17%)

19821.52 hits per line

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

80.54
/engine/src/qlcfixturedefcache.cpp
1
/*
2
  Q Light Controller
3
  qlcfixturedefcache.cpp
4

5
  Copyright (c) Heikki Junnila
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 <QCoreApplication>
21
#include <QXmlStreamReader>
22
#include <QDebug>
23
#include <QList>
24
#include <QSet>
25

26
#if defined(WIN32) || defined(Q_OS_WIN)
27
#   include <windows.h>
28
#else
29
#   include <unistd.h>
30
#endif
31

32
#include "qlcfixturedefcache.h"
33
#include "avolitesd4parser.h"
34
#include "qlcfixturedef.h"
35
#include "qlcconfig.h"
36
#include "qlcfile.h"
37

38
#define FIXTURES_MAP_NAME QStringLiteral("FixturesMap.xml")
39
#define KXMLQLCFixtureMap QStringLiteral("FixturesMap")
40

41
QLCFixtureDefCache::QLCFixtureDefCache()
198✔
42
{
43
}
198✔
44

45
QLCFixtureDefCache::~QLCFixtureDefCache()
198✔
46
{
47
    clear();
198✔
48
}
198✔
49

50
QLCFixtureDef* QLCFixtureDefCache::fixtureDef(
215✔
51
    const QString& manufacturer, const QString& model) const
52
{
53
    QListIterator <QLCFixtureDef*> it(m_defs);
215✔
54
    while (it.hasNext() == true)
171,547✔
55
    {
56
        QLCFixtureDef* def = it.next();
171,529✔
57
        if (def->manufacturer() == manufacturer && def->model() == model)
171,529✔
58
        {
59
            def->checkLoaded(m_mapAbsolutePath);
197✔
60
            return def;
197✔
61
        }
62
    }
63

64
    return NULL;
18✔
65
}
215✔
66

67
QStringList QLCFixtureDefCache::manufacturers() const
38✔
68
{
69
    QSet <QString> makers;
38✔
70

71
    // Gather a list of manufacturers
72
    QListIterator <QLCFixtureDef*> it(m_defs);
38✔
73
    while (it.hasNext() == true)
34,081✔
74
        makers << it.next()->manufacturer();
34,043✔
75

76
    // Bounce the QSet into a QStringList
77
    QStringList list;
38✔
78
    foreach (QString manuf, makers)
2,909✔
79
        list << manuf;
2,909✔
80

81
    return list;
76✔
82
}
38✔
83

84
QStringList QLCFixtureDefCache::models(const QString& manufacturer) const
83,039✔
85
{
86
    QSet <QString> models;
83,039✔
87
    QListIterator <QLCFixtureDef*> it(m_defs);
83,039✔
88
    while (it.hasNext() == true)
71,819,669✔
89
    {
90
        QLCFixtureDef* def = it.next();
71,736,630✔
91
        if (def->manufacturer() == manufacturer)
71,736,630✔
92
            models << def->model();
2,759,381✔
93
    }
94

95
    // Bounce the QSet into a QStringList
96
    QStringList list;
83,039✔
97
    foreach (QString model, models)
2,842,420✔
98
        list << model;
2,842,420✔
99

100
    return list;
166,078✔
101
}
83,039✔
102

103
QMap<QString, QMap<QString, bool> > QLCFixtureDefCache::fixtureCache() const
2✔
104
{
105
    QMap<QString, QMap<QString, bool> > map;
2✔
106

107
    QListIterator <QLCFixtureDef*> it(m_defs);
2✔
108
    while (it.hasNext() == true)
3,402✔
109
    {
110
        QLCFixtureDef *def = it.next();
3,400✔
111
        map[def->manufacturer()][def->model()] = def->isUser();
3,400✔
112
    }
113

114
    return map;
4✔
115
}
2✔
116

117
bool QLCFixtureDefCache::addFixtureDef(QLCFixtureDef* fixtureDef)
81,612✔
118
{
119
    if (fixtureDef == NULL)
81,612✔
120
        return false;
1✔
121

122
    if (models(fixtureDef->manufacturer()).contains(fixtureDef->model()) == false)
81,611✔
123
    {
124
        m_defs << fixtureDef;
81,608✔
125
        return true;
81,608✔
126
    }
127
    else
128
    {
129
        qWarning() << Q_FUNC_INFO << "Cache already contains"
3✔
130
                   << fixtureDef->name();
3✔
131
        return false;
3✔
132
    }
133
}
134

135
bool QLCFixtureDefCache::storeFixtureDef(QString filename, QString data)
1✔
136
{
137
    QDir userFolder = userDefinitionDirectory();
1✔
138

139
    QFile file(userFolder.absoluteFilePath(filename));
1✔
140
    if (file.open(QIODevice::WriteOnly | QIODevice::Text) == false)
1✔
141
        return false;
×
142

143
    file.write(data.toUtf8());
1✔
144
    file.close();
1✔
145
#ifdef Q_OS_UNIX
146
    sync();
1✔
147
#endif
148

149
    // reload user definitions
150
    load(userDefinitionDirectory());
1✔
151

152
    return true;
1✔
153
}
1✔
154

155
bool QLCFixtureDefCache::reloadFixtureDef(QLCFixtureDef *fixtureDef)
1✔
156
{
157
    int idx = m_defs.indexOf(fixtureDef);
1✔
158
    if (idx == -1)
1✔
159
        return false;
×
160

161
    QLCFixtureDef *def = m_defs.takeAt(idx);
1✔
162
    QString absPath = def->definitionSourceFile();
1✔
163
    delete def;
1✔
164

165
    QLCFixtureDef *origDef = new QLCFixtureDef();
1✔
166
    origDef->loadXML(absPath);
1✔
167
    m_defs << origDef;
1✔
168

169
    return true;
1✔
170
}
1✔
171

172
bool QLCFixtureDefCache::reloadOrAddFixtureDef(QLCFixtureDef *fixtureDef)
×
173
{
174
    QListIterator <QLCFixtureDef*> it(m_defs);
×
175
    while (it.hasNext() == true)
×
176
    {
177
        QLCFixtureDef *def = it.next();
×
178
        if (def->manufacturer() == fixtureDef->manufacturer() &&
×
179
            def->model() == fixtureDef->model())
×
180
        {
181
            def->setIsUser(true);
×
182
            def = fixtureDef;
×
183
            return true;
×
184
        }
185
    }
186

187
    addFixtureDef(fixtureDef);
×
188

189
    return true;
×
190
}
×
191

192
bool QLCFixtureDefCache::load(const QDir& dir)
9✔
193
{
194
    qDebug() << Q_FUNC_INFO << dir.path();
9✔
195

196
    if (dir.exists() == false || dir.isReadable() == false)
9✔
197
        return false;
7✔
198

199
    /* Attempt to read all specified files from the given directory */
200
    QStringListIterator it(dir.entryList());
2✔
201
    while (it.hasNext() == true)
3✔
202
    {
203
        QString path(dir.absoluteFilePath(it.next()));
1✔
204

205
        if (path.toLower().endsWith(KExtFixture) == true)
2✔
206
            loadQXF(path, true);
1✔
207
        else if (path.toLower().endsWith(KExtAvolitesFixture) == true)
×
208
            loadD4(path);
×
209
        else
210
            qWarning() << Q_FUNC_INFO << "Unrecognized fixture extension:" << path;
×
211
    }
1✔
212

213
    return true;
2✔
214
}
2✔
215

216
int QLCFixtureDefCache::loadMapManufacturer(QXmlStreamReader *doc, QString manufacturer)
6,816✔
217
{
218
    int count = 0;
6,816✔
219
    QString spacedManufacturer = manufacturer;
6,816✔
220
    spacedManufacturer.replace("_", " ");
6,816✔
221

222
    while (doc->readNextStartElement())
88,416✔
223
    {
224
        if (doc->name() == QString("F"))
81,600✔
225
        {
226
            QString defFile = "";
81,600✔
227
            QString model = "";
81,600✔
228

229
            if (doc->attributes().hasAttribute("n"))
163,200✔
230
            {
231
                defFile = QString("%1%2%3%4")
163,200✔
232
                            .arg(manufacturer).arg(QDir::separator())
163,200✔
233
                            .arg(doc->attributes().value("n").toString()).arg(KExtFixture);
244,800✔
234
                //qDebug() << "Manufacturer" << spacedManufacturer << "file" << defFile;
235
            }
236

237
            if (doc->attributes().hasAttribute("m"))
163,200✔
238
                model = doc->attributes().value("m").toString();
163,200✔
239

240
            if (defFile.isEmpty() == false &&
81,600✔
241
                spacedManufacturer.isEmpty() == false &&
163,200✔
242
                model.isEmpty() == false)
81,600✔
243
            {
244
                QLCFixtureDef *fxi = new QLCFixtureDef();
81,600✔
245
                Q_ASSERT(fxi != NULL);
81,600✔
246

247
                fxi->setDefinitionSourceFile(defFile);
81,600✔
248
                fxi->setManufacturer(spacedManufacturer);
81,600✔
249
                fxi->setModel(model);
81,600✔
250

251
                /* Delete the def if it's a duplicate. */
252
                if (addFixtureDef(fxi) == false)
81,600✔
253
                    delete fxi;
×
254
                fxi = NULL;
81,600✔
255
                count++;
81,600✔
256
            }
257
        }
81,600✔
258
        else
259
        {
260
            qWarning() << Q_FUNC_INFO << "Unknown manufacturer tag: " << doc->name();
×
261
        }
262
        doc->skipCurrentElement();
81,600✔
263
    }
264

265
    return count;
6,816✔
266
}
6,816✔
267

268
bool QLCFixtureDefCache::loadMap(const QDir &dir)
48✔
269
{
270
    qDebug() << Q_FUNC_INFO << dir.path();
48✔
271

272
    if (dir.exists() == false || dir.isReadable() == false)
48✔
273
        return false;
×
274

275
    QString mapPath(dir.absoluteFilePath(FIXTURES_MAP_NAME));
96✔
276

277
    if (mapPath.isEmpty() == true)
48✔
278
        return false;
×
279

280
    // cache the map path to be used when composing the fixture
281
    // definition absolute path
282
    m_mapAbsolutePath = dir.absolutePath();
48✔
283

284
    QXmlStreamReader *doc = QLCFile::getXMLReader(mapPath);
48✔
285
    if (doc == NULL || doc->device() == NULL || doc->hasError())
48✔
286
    {
287
        qWarning() << Q_FUNC_INFO << "Unable to read from" << mapPath;
×
288
        return false;
×
289
    }
290

291
    while (!doc->atEnd())
96✔
292
    {
293
        if (doc->readNext() == QXmlStreamReader::DTD)
96✔
294
            break;
48✔
295
    }
296

297
    if (doc->hasError())
48✔
298
    {
299
        QLCFile::releaseXMLReader(doc);
×
300
        return false;
×
301
    }
302

303
    // make sure the doc type is FixtureMap
304
    if (doc->dtdName() != KXMLQLCFixtureMap)
48✔
305
    {
306
        qWarning() << Q_FUNC_INFO << mapPath << "is not a fixture map file";
×
307
        QLCFile::releaseXMLReader(doc);
×
308
        return false;
×
309
    }
310

311
    if (doc->readNextStartElement() == false)
48✔
312
    {
313
        QLCFile::releaseXMLReader(doc);
×
314
        return false;
×
315
    }
316

317
    // make sure the root tag is FixtureMap
318
    if (doc->name() != KXMLQLCFixtureMap)
48✔
319
    {
320
        qWarning() << Q_FUNC_INFO << mapPath << "is not a fixture map file";
×
321
        QLCFile::releaseXMLReader(doc);
×
322
        return false;
×
323
    }
324

325
    int fxCount = 0;
48✔
326
    QString manufacturer = "";
48✔
327

328
    while (doc->readNextStartElement())
6,864✔
329
    {
330
        if (doc->name() == QString("M"))
6,816✔
331
        {
332
            if (doc->attributes().hasAttribute("n"))
13,632✔
333
            {
334
                manufacturer = doc->attributes().value("n").toString();
13,632✔
335
                fxCount += loadMapManufacturer(doc, manufacturer);
6,816✔
336
            }
337
        }
338
        else
339
        {
340
            qWarning() << Q_FUNC_INFO << "Unknown Fixture Map tag: " << doc->name();
×
341
            doc->skipCurrentElement();
×
342
        }
343
    }
344
    qDebug() << fxCount << "fixtures found in map";
48✔
345

346
#if 0
347
    /* Attempt to read all files not in FixtureMap */
348
    QStringList definitionPaths;
349

350
    // Gather a list of manufacturers
351
    QListIterator <QLCFixtureDef*> mfit(m_defs);
352
    while (mfit.hasNext() == true)
353
        definitionPaths << mfit.next()->definitionSourceFile();
354

355
    QStringListIterator it(dir.entryList());
356
    while (it.hasNext() == true)
357
    {
358
        QString path(dir.absoluteFilePath(it.next()));
359
        if (definitionPaths.contains(path))
360
            continue;
361

362
        qWarning() << path << "not in" << FIXTURES_MAP_NAME;
363

364
        if (path.toLower().endsWith(KExtFixture) == true)
365
            loadQXF(path);
366
        else if (path.toLower().endsWith(KExtAvolitesFixture) == true)
367
            loadD4(path);
368
        else
369
            qWarning() << Q_FUNC_INFO << "Unrecognized fixture extension:" << path;
370
    }
371
#endif
372
    return true;
48✔
373
}
48✔
374

375
void QLCFixtureDefCache::clear()
207✔
376
{
377
    while (m_defs.isEmpty() == false)
81,815✔
378
        delete m_defs.takeFirst();
81,608✔
379
}
207✔
380

381
QDir QLCFixtureDefCache::systemDefinitionDirectory()
1✔
382
{
383
    return QLCFile::systemDirectory(QString(FIXTUREDIR), QString(KExtFixture));
2✔
384
}
385

386
QDir QLCFixtureDefCache::userDefinitionDirectory()
4✔
387
{
388
    QStringList filters;
4✔
389
    filters << QString("*%1").arg(KExtFixture);
8✔
390
    filters << QString("*%1").arg(KExtAvolitesFixture);
8✔
391

392
    return QLCFile::userDirectory(QString(USERFIXTUREDIR), QString(FIXTUREDIR), filters);
12✔
393
}
4✔
394

395
bool QLCFixtureDefCache::loadQXF(const QString& path, bool isUser)
10✔
396
{
397
    QLCFixtureDef *fxi = new QLCFixtureDef();
10✔
398
    Q_ASSERT(fxi != NULL);
10✔
399

400
    QFile::FileError error = fxi->loadXML(path);
10✔
401
    if (error == QFile::NoError)
10✔
402
    {
403
        fxi->setIsUser(isUser);
2✔
404
        fxi->setDefinitionSourceFile(path);
2✔
405
        fxi->setLoaded(true);
2✔
406

407
        /* Delete the def if it's a duplicate. */
408
        if (addFixtureDef(fxi) == false)
2✔
409
            delete fxi;
2✔
410
        fxi = NULL;
2✔
411
    }
412
    else
413
    {
414
        qWarning() << Q_FUNC_INFO << "Fixture definition loading from"
8✔
415
                   << path << "failed:" << QLCFile::errorString(error);
8✔
416
        delete fxi;
8✔
417
        fxi = NULL;
8✔
418
        return false;
8✔
419
    }
420
    return true;
2✔
421
}
422

423
bool QLCFixtureDefCache::loadD4(const QString& path)
1✔
424
{
425
    QLCFixtureDef *fxi = new QLCFixtureDef();
1✔
426
    AvolitesD4Parser parser;
1✔
427
    if (parser.loadXML(path, fxi) == false)
1✔
428
    {
429
        qWarning() << Q_FUNC_INFO << "Unable to load D4 fixture from" << path
1✔
430
                   << ":" << parser.lastError();
1✔
431
        delete fxi;
1✔
432
        return false;
1✔
433
    }
434

435
    // a D4 personality is always a user-made fixture
436
    fxi->setIsUser(true);
×
437
    fxi->setDefinitionSourceFile(path);
×
438
    fxi->setLoaded(true);
×
439

440
    /* Delete the def if it's a duplicate. */
441
    if (addFixtureDef(fxi) == false)
×
442
    {
443
        qDebug() << Q_FUNC_INFO << "Deleting duplicate" << path;
×
444
        delete fxi;
×
445
    }
446
    fxi = NULL;
×
447

448
    return true;
×
449
}
1✔
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