• 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

85.17
/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)
167,862✔
55
    {
56
        QLCFixtureDef* def = it.next();
167,844✔
57
        if (def->manufacturer() == manufacturer && def->model() == model)
167,844✔
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)
33,261✔
74
        makers << it.next()->manufacturer();
33,223✔
75

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

81
    return list;
76✔
82
}
38✔
83

84
QStringList QLCFixtureDefCache::models(const QString& manufacturer) const
81,061✔
85
{
86
    QSet <QString> models;
81,061✔
87
    QListIterator <QLCFixtureDef*> it(m_defs);
81,061✔
88
    while (it.hasNext() == true)
68,438,527✔
89
    {
90
        QLCFixtureDef* def = it.next();
68,357,466✔
91
        if (def->manufacturer() == manufacturer)
68,357,466✔
92
            models << def->model();
2,658,555✔
93
    }
94

95
    // Bounce the QSet into a QStringList
96
    QStringList list;
81,061✔
97
    foreach (QString model, models)
2,739,616✔
98
        list << model;
2,739,616✔
99

100
    return list;
162,122✔
101
}
81,061✔
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,320✔
109
    {
110
        QLCFixtureDef *def = it.next();
3,318✔
111
        map[def->manufacturer()][def->model()] = def->isUser();
3,318✔
112
    }
113

114
    return map;
4✔
115
}
2✔
116

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

122
    if (models(fixtureDef->manufacturer()).contains(fixtureDef->model()) == false)
79,643✔
123
    {
124
        m_defs << fixtureDef;
79,640✔
125
        return true;
79,640✔
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::load(const QDir& dir)
9✔
173
{
174
    qDebug() << Q_FUNC_INFO << dir.path();
9✔
175

176
    if (dir.exists() == false || dir.isReadable() == false)
9✔
177
        return false;
7✔
178

179
    /* Attempt to read all specified files from the given directory */
180
    QStringListIterator it(dir.entryList());
2✔
181
    while (it.hasNext() == true)
3✔
182
    {
183
        QString path(dir.absoluteFilePath(it.next()));
1✔
184

185
        if (path.toLower().endsWith(KExtFixture) == true)
2✔
186
            loadQXF(path, true);
1✔
187
        else if (path.toLower().endsWith(KExtAvolitesFixture) == true)
×
188
            loadD4(path);
×
189
        else
190
            qWarning() << Q_FUNC_INFO << "Unrecognized fixture extension:" << path;
×
191
    }
1✔
192

193
    return true;
2✔
194
}
2✔
195

196
int QLCFixtureDefCache::loadMapManufacturer(QXmlStreamReader *doc, QString manufacturer)
6,768✔
197
{
198
    int count = 0;
6,768✔
199
    QString spacedManufacturer = manufacturer;
6,768✔
200
    spacedManufacturer.replace("_", " ");
6,768✔
201

202
    while (doc->readNextStartElement())
86,400✔
203
    {
204
        if (doc->name() == QString("F"))
79,632✔
205
        {
206
            QString defFile = "";
79,632✔
207
            QString model = "";
79,632✔
208

209
            if (doc->attributes().hasAttribute("n"))
159,264✔
210
            {
211
                defFile = QString("%1%2%3%4")
159,264✔
212
                            .arg(manufacturer).arg(QDir::separator())
159,264✔
213
                            .arg(doc->attributes().value("n").toString()).arg(KExtFixture);
238,896✔
214
                //qDebug() << "Manufacturer" << spacedManufacturer << "file" << defFile;
215
            }
216

217
            if (doc->attributes().hasAttribute("m"))
159,264✔
218
                model = doc->attributes().value("m").toString();
159,264✔
219

220
            if (defFile.isEmpty() == false &&
79,632✔
221
                spacedManufacturer.isEmpty() == false &&
159,264✔
222
                model.isEmpty() == false)
79,632✔
223
            {
224
                QLCFixtureDef *fxi = new QLCFixtureDef();
79,632✔
225
                Q_ASSERT(fxi != NULL);
79,632✔
226

227
                fxi->setDefinitionSourceFile(defFile);
79,632✔
228
                fxi->setManufacturer(spacedManufacturer);
79,632✔
229
                fxi->setModel(model);
79,632✔
230

231
                /* Delete the def if it's a duplicate. */
232
                if (addFixtureDef(fxi) == false)
79,632✔
233
                    delete fxi;
×
234
                fxi = NULL;
79,632✔
235
                count++;
79,632✔
236
            }
237
        }
79,632✔
238
        else
239
        {
240
            qWarning() << Q_FUNC_INFO << "Unknown manufacturer tag: " << doc->name();
×
241
        }
242
        doc->skipCurrentElement();
79,632✔
243
    }
244

245
    return count;
6,768✔
246
}
6,768✔
247

248
bool QLCFixtureDefCache::loadMap(const QDir &dir)
48✔
249
{
250
    qDebug() << Q_FUNC_INFO << dir.path();
48✔
251

252
    if (dir.exists() == false || dir.isReadable() == false)
48✔
253
        return false;
×
254

255
    QString mapPath(dir.absoluteFilePath(FIXTURES_MAP_NAME));
96✔
256

257
    if (mapPath.isEmpty() == true)
48✔
258
        return false;
×
259

260
    // cache the map path to be used when composing the fixture
261
    // definition absolute path
262
    m_mapAbsolutePath = dir.absolutePath();
48✔
263

264
    QXmlStreamReader *doc = QLCFile::getXMLReader(mapPath);
48✔
265
    if (doc == NULL || doc->device() == NULL || doc->hasError())
48✔
266
    {
267
        qWarning() << Q_FUNC_INFO << "Unable to read from" << mapPath;
×
268
        return false;
×
269
    }
270

271
    while (!doc->atEnd())
96✔
272
    {
273
        if (doc->readNext() == QXmlStreamReader::DTD)
96✔
274
            break;
48✔
275
    }
276

277
    if (doc->hasError())
48✔
278
    {
279
        QLCFile::releaseXMLReader(doc);
×
280
        return false;
×
281
    }
282

283
    // make sure the doc type is FixtureMap
284
    if (doc->dtdName() != KXMLQLCFixtureMap)
48✔
285
    {
286
        qWarning() << Q_FUNC_INFO << mapPath << "is not a fixture map file";
×
287
        QLCFile::releaseXMLReader(doc);
×
288
        return false;
×
289
    }
290

291
    if (doc->readNextStartElement() == false)
48✔
292
    {
293
        QLCFile::releaseXMLReader(doc);
×
294
        return false;
×
295
    }
296

297
    // make sure the root tag is FixtureMap
298
    if (doc->name() != KXMLQLCFixtureMap)
48✔
299
    {
300
        qWarning() << Q_FUNC_INFO << mapPath << "is not a fixture map file";
×
301
        QLCFile::releaseXMLReader(doc);
×
302
        return false;
×
303
    }
304

305
    int fxCount = 0;
48✔
306
    QString manufacturer = "";
48✔
307

308
    while (doc->readNextStartElement())
6,816✔
309
    {
310
        if (doc->name() == QString("M"))
6,768✔
311
        {
312
            if (doc->attributes().hasAttribute("n"))
13,536✔
313
            {
314
                manufacturer = doc->attributes().value("n").toString();
13,536✔
315
                fxCount += loadMapManufacturer(doc, manufacturer);
6,768✔
316
            }
317
        }
318
        else
319
        {
320
            qWarning() << Q_FUNC_INFO << "Unknown Fixture Map tag: " << doc->name();
×
321
            doc->skipCurrentElement();
×
322
        }
323
    }
324
    qDebug() << fxCount << "fixtures found in map";
48✔
325

326
#if 0
327
    /* Attempt to read all files not in FixtureMap */
328
    QStringList definitionPaths;
329

330
    // Gather a list of manufacturers
331
    QListIterator <QLCFixtureDef*> mfit(m_defs);
332
    while (mfit.hasNext() == true)
333
        definitionPaths << mfit.next()->definitionSourceFile();
334

335
    QStringListIterator it(dir.entryList());
336
    while (it.hasNext() == true)
337
    {
338
        QString path(dir.absoluteFilePath(it.next()));
339
        if (definitionPaths.contains(path))
340
            continue;
341

342
        qWarning() << path << "not in" << FIXTURES_MAP_NAME;
343

344
        if (path.toLower().endsWith(KExtFixture) == true)
345
            loadQXF(path);
346
        else if (path.toLower().endsWith(KExtAvolitesFixture) == true)
347
            loadD4(path);
348
        else
349
            qWarning() << Q_FUNC_INFO << "Unrecognized fixture extension:" << path;
350
    }
351
#endif
352
    return true;
48✔
353
}
48✔
354

355
void QLCFixtureDefCache::clear()
207✔
356
{
357
    while (m_defs.isEmpty() == false)
79,847✔
358
        delete m_defs.takeFirst();
79,640✔
359
}
207✔
360

361
QDir QLCFixtureDefCache::systemDefinitionDirectory()
1✔
362
{
363
    return QLCFile::systemDirectory(QString(FIXTUREDIR), QString(KExtFixture));
2✔
364
}
365

366
QDir QLCFixtureDefCache::userDefinitionDirectory()
4✔
367
{
368
    QStringList filters;
4✔
369
    filters << QString("*%1").arg(KExtFixture);
8✔
370
    filters << QString("*%1").arg(KExtAvolitesFixture);
4✔
371

372
    return QLCFile::userDirectory(QString(USERFIXTUREDIR), QString(FIXTUREDIR), filters);
12✔
373
}
4✔
374

375
bool QLCFixtureDefCache::loadQXF(const QString& path, bool isUser)
10✔
376
{
377
    QLCFixtureDef *fxi = new QLCFixtureDef();
10✔
378
    Q_ASSERT(fxi != NULL);
10✔
379

380
    QFile::FileError error = fxi->loadXML(path);
10✔
381
    if (error == QFile::NoError)
10✔
382
    {
383
        fxi->setIsUser(isUser);
2✔
384
        fxi->setDefinitionSourceFile(path);
2✔
385
        fxi->setLoaded(true);
2✔
386

387
        /* Delete the def if it's a duplicate. */
388
        if (addFixtureDef(fxi) == false)
2✔
389
            delete fxi;
2✔
390
        fxi = NULL;
2✔
391
    }
392
    else
393
    {
394
        qWarning() << Q_FUNC_INFO << "Fixture definition loading from"
8✔
395
                   << path << "failed:" << QLCFile::errorString(error);
8✔
396
        delete fxi;
8✔
397
        fxi = NULL;
8✔
398
        return false;
8✔
399
    }
400
    return true;
2✔
401
}
402

403
bool QLCFixtureDefCache::loadD4(const QString& path)
1✔
404
{
405
    QLCFixtureDef *fxi = new QLCFixtureDef();
1✔
406
    AvolitesD4Parser parser;
1✔
407
    if (parser.loadXML(path, fxi) == false)
1✔
408
    {
409
        qWarning() << Q_FUNC_INFO << "Unable to load D4 fixture from" << path
1✔
410
                   << ":" << parser.lastError();
1✔
411
        delete fxi;
1✔
412
        return false;
1✔
413
    }
414

415
    // a D4 personality is always a user-made fixture
416
    fxi->setIsUser(true);
×
417
    fxi->setDefinitionSourceFile(path);
×
418
    fxi->setLoaded(true);
×
419

420
    /* Delete the def if it's a duplicate. */
421
    if (addFixtureDef(fxi) == false)
×
422
    {
423
        qDebug() << Q_FUNC_INFO << "Deleting duplicate" << path;
×
424
        delete fxi;
×
425
    }
426
    fxi = NULL;
×
427

428
    return true;
×
429
}
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