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

mcallegari / qlcplus / 14445404527

14 Apr 2025 12:17PM UTC coverage: 31.854% (-0.05%) from 31.907%
14445404527

push

github

web-flow
Merge pull request #1714 from shaforostoff/webaccess_optimize_loadxml

engine: speedup loadXML methods by using QStringLiteral

1 of 1 new or added line in 1 file covered. (100.0%)

220 existing lines in 5 files now uncovered.

14674 of 46067 relevant lines covered (31.85%)

26455.49 hits per line

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

90.95
/engine/src/doc.cpp
1
/*
2
  Q Light Controller Plus
3
  doc.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 <QStringList>
24
#include <QString>
25
#include <QDebug>
26
#include <QList>
27
#include <QTime>
28
#include <QDir>
29
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
30
#include <QRandomGenerator>
31
#endif
32

33
#include "qlcfixturemode.h"
34
#include "qlcfixturedef.h"
35

36
#include "monitorproperties.h"
37
#include "audioplugincache.h"
38
#include "rgbscriptscache.h"
39
#include "channelsgroup.h"
40
#include "scriptwrapper.h"
41
#include "collection.h"
42
#include "function.h"
43
#include "universe.h"
44
#include "sequence.h"
45
#include "fixture.h"
46
#include "chaser.h"
47
#include "show.h"
48
#include "doc.h"
49
#include "bus.h"
50

51
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
52
 #if defined(__APPLE__) || defined(Q_OS_MAC)
53
  #include "audiocapture_portaudio.h"
54
 #elif defined(WIN32) || defined (Q_OS_WIN)
55
  #include "audiocapture_wavein.h"
56
 #else
57
  #include "audiocapture_alsa.h"
58
 #endif
59
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
60
 #include "audiocapture_qt5.h"
61
#else
62
 #include "audiocapture_qt6.h"
63
#endif
64

65
Doc::Doc(QObject* parent, int universes)
177✔
66
    : QObject(parent)
67
    , m_wsPath("")
177✔
68
    , m_fixtureDefCache(new QLCFixtureDefCache)
177✔
69
    , m_modifiersCache(new QLCModifiersCache)
177✔
70
    , m_rgbScriptsCache(new RGBScriptsCache(this))
177✔
71
    , m_ioPluginCache(new IOPluginCache(this))
177✔
72
    , m_audioPluginCache(new AudioPluginCache(this))
177✔
73
    , m_masterTimer(new MasterTimer(this))
177✔
74
    , m_ioMap(new InputOutputMap(this, universes))
177✔
75
    , m_monitorProps(NULL)
177✔
76
    , m_mode(Design)
177✔
77
    , m_kiosk(false)
177✔
78
    , m_loadStatus(Cleared)
177✔
79
    , m_clipboard(new QLCClipboard(this))
177✔
80
    , m_fixturesListCacheUpToDate(false)
177✔
81
    , m_latestFixtureId(0)
177✔
82
    , m_latestFixtureGroupId(0)
177✔
83
    , m_latestChannelsGroupId(0)
177✔
84
    , m_latestPaletteId(0)
177✔
85
    , m_latestFunctionId(0)
177✔
86
    , m_startupFunctionId(Function::invalidId())
354✔
87
{
88
    Bus::init(this);
177✔
89
    resetModified();
177✔
90
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
91
    qsrand(QTime::currentTime().msec());
92
#endif
93
    
94
}
177✔
95

96
Doc::~Doc()
314✔
97
{
98
    delete m_masterTimer;
177✔
99
    m_masterTimer = NULL;
177✔
100

101
    clearContents();
177✔
102

103
    if (isKiosk() == false)
177✔
104
    {
105
        // TODO: is this still needed ??
106
        //m_ioMap->saveDefaults();
107
    }
108
    delete m_ioMap;
177✔
109
    m_ioMap = NULL;
177✔
110

111
    delete m_ioPluginCache;
177✔
112
    m_ioPluginCache = NULL;
177✔
113

114
    delete m_modifiersCache;
177✔
115
    m_modifiersCache = NULL;
177✔
116

117
    delete m_fixtureDefCache;
177✔
118
    m_fixtureDefCache = NULL;
177✔
119

120
    delete m_rgbScriptsCache;
354✔
121
    m_rgbScriptsCache = NULL;
177✔
122
}
491✔
123

124
void Doc::clearContents()
452✔
125
{
126
    emit clearing();
452✔
127

128
    m_clipboard->resetContents();
452✔
129

130
    if (m_monitorProps != NULL)
452✔
131
        m_monitorProps->reset();
9✔
132

133
    destroyAudioCapture();
452✔
134

135
    // Delete all function instances
136
    QListIterator <quint32> funcit(m_functions.keys());
452✔
137
    while (funcit.hasNext() == true)
698✔
138
    {
139
        Function* func = m_functions.take(funcit.next());
246✔
140
        if (func == NULL)
246✔
UNCOV
141
            continue;
×
142
        emit functionRemoved(func->id());
246✔
143
        delete func;
246✔
144
    }
145

146
    // Delete all palettes
147
    QListIterator <quint32> palIt(m_palettes.keys());
452✔
148
    while (palIt.hasNext() == true)
904✔
149
    {
UNCOV
150
        QLCPalette *palette = m_palettes.take(palIt.next());
×
UNCOV
151
        emit paletteRemoved(palette->id());
×
UNCOV
152
        delete palette;
×
153
    }
154

155
    // Delete all channel groups
156
    QListIterator <quint32> grpchans(m_channelsGroups.keys());
452✔
157
    while (grpchans.hasNext() == true)
907✔
158
    {
159
        ChannelsGroup* grp = m_channelsGroups.take(grpchans.next());
3✔
160
        emit channelsGroupRemoved(grp->id());
3✔
161
        delete grp;
3✔
162
    }
163

164
    // Delete all fixture groups
165
    QListIterator <quint32> grpit(m_fixtureGroups.keys());
452✔
166
    while (grpit.hasNext() == true)
463✔
167
    {
168
        FixtureGroup* grp = m_fixtureGroups.take(grpit.next());
11✔
169
        quint32 grpID = grp->id();
11✔
170
        delete grp;
11✔
171
        emit fixtureGroupRemoved(grpID);
11✔
172
    }
173

174
    // Delete all fixture instances
175
    QListIterator <quint32> fxit(m_fixtures.keys());
452✔
176
    while (fxit.hasNext() == true)
17,226✔
177
    {
178
        Fixture* fxi = m_fixtures.take(fxit.next());
16,774✔
179
        quint32 fxID = fxi->id();
16,774✔
180
        delete fxi;
16,774✔
181
        emit fixtureRemoved(fxID);
16,774✔
182
    }
183
    m_fixturesListCacheUpToDate = false;
452✔
184

185
    m_orderedGroups.clear();
452✔
186

187
    m_latestFunctionId = 0;
452✔
188
    m_latestFixtureId = 0;
452✔
189
    m_latestFixtureGroupId = 0;
452✔
190
    m_latestChannelsGroupId = 0;
452✔
191
    m_latestPaletteId = 0;
452✔
192
    m_addresses.clear();
452✔
193
    m_loadStatus = Cleared;
452✔
194

195
    emit cleared();
452✔
196
}
452✔
197

198
void Doc::setWorkspacePath(QString path)
4✔
199
{
200
    m_wsPath = path;
4✔
201
}
4✔
202

203
QString Doc::getWorkspacePath() const
23✔
204
{
205
    return m_wsPath;
23✔
206
}
207

208
QString Doc::normalizeComponentPath(const QString& filePath) const
7✔
209
{
210
    if (filePath.isEmpty())
7✔
211
        return filePath;
212

213
    QFileInfo f(filePath);
6✔
214

215
    if (f.absolutePath().startsWith(getWorkspacePath()))
6✔
216
    {
217
        return QDir(getWorkspacePath()).relativeFilePath(f.absoluteFilePath());
4✔
218
    }
219
    else
220
    {
221
        return f.absoluteFilePath();
2✔
222
    }
223
}
6✔
224

225
QString Doc::denormalizeComponentPath(const QString& filePath) const
8✔
226
{
227
    if (filePath.isEmpty())
8✔
228
        return filePath;
229

230
    return QFileInfo(QDir(getWorkspacePath()), filePath).absoluteFilePath();
6✔
231
}
232

233
/*****************************************************************************
234
 * Engine components
235
 *****************************************************************************/
236

237
QLCFixtureDefCache* Doc::fixtureDefCache() const
1,643✔
238
{
239
    return m_fixtureDefCache;
1,643✔
240
}
241

242
void Doc::setFixtureDefinitionCache(QLCFixtureDefCache *cache)
×
243
{
UNCOV
244
    m_fixtureDefCache = cache;
×
UNCOV
245
}
×
246

247
QLCModifiersCache* Doc::modifiersCache() const
1✔
248
{
249
    return m_modifiersCache;
1✔
250
}
251

252
RGBScriptsCache* Doc::rgbScriptsCache() const
69✔
253
{
254
    return m_rgbScriptsCache;
69✔
255
}
256

257
IOPluginCache* Doc::ioPluginCache() const
288✔
258
{
259
    return m_ioPluginCache;
288✔
260
}
261

262
AudioPluginCache *Doc::audioPluginCache() const
1✔
263
{
264
    return m_audioPluginCache;
1✔
265
}
266

267
InputOutputMap* Doc::inputOutputMap() const
2,709✔
268
{
269
    return m_ioMap;
2,709✔
270
}
271

272
MasterTimer* Doc::masterTimer() const
1,102✔
273
{
274
    return m_masterTimer;
1,102✔
275
}
276

277
QSharedPointer<AudioCapture> Doc::audioInputCapture()
17✔
278
{
279
    if (!m_inputCapture)
17✔
280
    {
281
        qDebug() << "Creating new audio capture";
282
        m_inputCapture = QSharedPointer<AudioCapture>(
2✔
283
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
284
#if defined(__APPLE__) || defined(Q_OS_MAC)
285
            new AudioCapturePortAudio()
286
#elif defined(WIN32) || defined (Q_OS_WIN)
287
            new AudioCaptureWaveIn()
288
#else
289
            new AudioCaptureAlsa()
290
#endif
291
#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
292
            new AudioCaptureQt6()
2✔
293
#else
294
            new AudioCaptureQt6()
295
#endif
296
            );
297
    }
298
    return m_inputCapture;
17✔
299
}
300

301
void Doc::destroyAudioCapture()
452✔
302
{
303
    if (m_inputCapture.isNull() == false)
452✔
304
    {
305
        qDebug() << "Destroying audio capture";
306
        m_inputCapture.clear();
307
    }
308
}
452✔
309

310
/*****************************************************************************
311
 * Modified status
312
 *****************************************************************************/
313
Doc::LoadStatus Doc::loadStatus() const
2✔
314
{
315
    return m_loadStatus;
2✔
316
}
317

318
bool Doc::isModified() const
29✔
319
{
320
    return m_modified;
29✔
321
}
322

323
void Doc::setModified()
1,245✔
324
{
325
    m_modified = true;
1,245✔
326
    emit modified(true);
1,245✔
327
}
1,245✔
328

329
void Doc::resetModified()
192✔
330
{
331
    m_modified = false;
192✔
332
    emit modified(false);
192✔
333
}
192✔
334

335
/*****************************************************************************
336
 * Main operating mode
337
 *****************************************************************************/
338

339
void Doc::setMode(Doc::Mode mode)
23✔
340
{
341
    /* Don't do mode switching twice */
342
    if (m_mode == mode)
23✔
343
        return;
344
    m_mode = mode;
21✔
345

346
    // Run startup function
347
    if (m_mode == Operate && m_startupFunctionId != Function::invalidId())
21✔
348
    {
UNCOV
349
        Function *func = function(m_startupFunctionId);
×
350
        if (func != NULL)
×
351
        {
352
            qDebug() << Q_FUNC_INFO << "Starting startup function. (" << m_startupFunctionId << ")";
UNCOV
353
            func->start(masterTimer(), FunctionParent::master());
×
354
        }
355
        else
356
        {
UNCOV
357
            qWarning() << Q_FUNC_INFO << "Startup function does not exist, erasing. (" << m_startupFunctionId << ")";
×
UNCOV
358
            m_startupFunctionId = Function::invalidId();
×
359
        }
360
    }
361

362
    emit modeChanged(m_mode);
21✔
363
}
364

365
Doc::Mode Doc::mode() const
323✔
366
{
367
    return m_mode;
323✔
368
}
369

370
void Doc::setKiosk(bool state)
1✔
371
{
372
    m_kiosk = state;
1✔
373
}
1✔
374

375
bool Doc::isKiosk() const
179✔
376
{
377
    return m_kiosk;
179✔
378
}
379

380
/*********************************************************************
381
 * Clipboard
382
 *********************************************************************/
383

384
QLCClipboard *Doc::clipboard()
1✔
385
{
386
    return m_clipboard;
1✔
387
}
388

389
/*****************************************************************************
390
 * Fixtures
391
 *****************************************************************************/
392

393
quint32 Doc::createFixtureId()
16,781✔
394
{
395
    /* This results in an endless loop if there are UINT_MAX-1 fixtures. That,
396
       however, seems a bit unlikely. Are there even 4294967295-1 fixtures in
397
       total in the whole world? */
398
    while (m_fixtures.contains(m_latestFixtureId) == true ||
50,195✔
399
           m_latestFixtureId == Fixture::invalidId())
16,781✔
400
    {
401
        m_latestFixtureId++;
16,633✔
402
    }
403

404
    return m_latestFixtureId;
16,781✔
405
}
406

407
bool Doc::addFixture(Fixture* fixture, quint32 id, bool crossUniverse)
406✔
408
{
409
    Q_ASSERT(fixture != NULL);
410

411
    quint32 i;
412
    quint32 uni = fixture->universe();
406✔
413

414
    // No ID given, this method can assign one
415
    if (id == Fixture::invalidId())
406✔
416
        id = createFixtureId();
397✔
417

418
    if (m_fixtures.contains(id) == true || id == Fixture::invalidId())
406✔
419
    {
420
        qWarning() << Q_FUNC_INFO << "a fixture with ID" << id << "already exists!";
1✔
421
        return false;
1✔
422
    }
423

424
    /* Check for overlapping address */
425
    for (i = fixture->universeAddress();
2,971✔
426
         i < fixture->universeAddress() + fixture->channels(); i++)
2,971✔
427
    {
428
        if (m_addresses.contains(i))
2,570✔
429
        {
430
            qWarning() << Q_FUNC_INFO << "fixture" << id << "overlapping with fixture" << m_addresses[i] << "@ channel" << i;
4✔
431
            return false;
4✔
432
        }
433
    }
434

435
    fixture->setID(id);
401✔
436
    m_fixtures.insert(id, fixture);
401✔
437
    m_fixturesListCacheUpToDate = false;
401✔
438

439
    /* Patch fixture change signals thru Doc */
440
    connect(fixture, SIGNAL(changed(quint32)),
401✔
441
            this, SLOT(slotFixtureChanged(quint32)));
442

443
    /* Keep track of fixture addresses */
444
    for (i = fixture->universeAddress();
401✔
445
         i < fixture->universeAddress() + fixture->channels(); i++)
2,967✔
446
    {
447
        m_addresses[i] = id;
2,566✔
448
    }
449

450
    if (crossUniverse)
401✔
UNCOV
451
        uni = floor((fixture->universeAddress() + fixture->channels()) / 512);
×
452

453
    if (uni >= inputOutputMap()->universesCount())
401✔
454
    {
UNCOV
455
        for (i = inputOutputMap()->universesCount(); i <= uni; i++)
×
UNCOV
456
            inputOutputMap()->addUniverse(i);
×
UNCOV
457
        inputOutputMap()->startUniverses();
×
458
    }
459

460
    // Add the fixture channels capabilities to the universe they belong
461
    QList<Universe *> universes = inputOutputMap()->claimUniverses();
401✔
462

463
    QList<int> forcedHTP = fixture->forcedHTPChannels();
401✔
464
    QList<int> forcedLTP = fixture->forcedLTPChannels();
401✔
465
    quint32 fxAddress = fixture->address();
401✔
466

467
    for (i = 0; i < fixture->channels(); i++)
2,967✔
468
    {
469
        const QLCChannel *channel(fixture->channel(i));
2,566✔
470
        quint32 addr = fxAddress + i;
2,566✔
471

472
        if (crossUniverse)
2,566✔
473
        {
UNCOV
474
            uni = floor((fixture->universeAddress() + i) / 512);
×
UNCOV
475
            addr = (fixture->universeAddress() + i) - (uni * 512);
×
476
        }
477

478
        // Inform Universe of any HTP/LTP forcing
479
        if (forcedHTP.contains(int(i)))
2,566✔
UNCOV
480
            universes.at(uni)->setChannelCapability(addr, channel->group(), Universe::HTP);
×
481
        else if (forcedLTP.contains(int(i)))
2,566✔
482
            universes.at(uni)->setChannelCapability(addr, channel->group(), Universe::LTP);
1✔
483
        else
484
            universes.at(uni)->setChannelCapability(addr, channel->group());
2,565✔
485

486
        // Apply the default value BEFORE modifiers
487
        universes.at(uni)->setChannelDefaultValue(addr, channel->defaultValue());
2,566✔
488

489
        // Apply a channel modifier, if defined
490
        ChannelModifier *mod = fixture->channelModifier(i);
2,566✔
491
        universes.at(uni)->setChannelModifier(addr, mod);
2,566✔
492
    }
493
    inputOutputMap()->releaseUniverses(true);
401✔
494

495
    emit fixtureAdded(id);
401✔
496
    setModified();
401✔
497

498
    return true;
499
}
401✔
500

501
bool Doc::deleteFixture(quint32 id)
16✔
502
{
503
    if (m_fixtures.contains(id) == true)
16✔
504
    {
505
        Fixture* fxi = m_fixtures.take(id);
10✔
506
        Q_ASSERT(fxi != NULL);
507
        m_fixturesListCacheUpToDate = false;
10✔
508

509
        /* Keep track of fixture addresses */
510
        QMutableHashIterator <uint,uint> it(m_addresses);
10✔
511
        while (it.hasNext() == true)
102✔
512
        {
513
            it.next();
92✔
514
            if (it.value() == id)
92✔
515
                it.remove();
47✔
516
        }
517
        if (m_monitorProps != NULL)
10✔
UNCOV
518
            m_monitorProps->removeFixture(id);
×
519

520
        emit fixtureRemoved(id);
10✔
521
        setModified();
10✔
522
        delete fxi;
10✔
523

524
        if (m_fixtures.count() == 0)
10✔
525
            m_latestFixtureId = 0;
6✔
526

527
        return true;
528
    }
529
    else
530
    {
531
        qWarning() << Q_FUNC_INFO << "No fixture with id" << id;
6✔
532
        return false;
6✔
533
    }
534
}
535

536
bool Doc::replaceFixtures(QList<Fixture*> newFixturesList)
1✔
537
{
538
    // Delete all fixture instances
539
    QListIterator <quint32> fxit(m_fixtures.keys());
1✔
540
    while (fxit.hasNext() == true)
4✔
541
    {
542
        Fixture* fxi = m_fixtures.take(fxit.next());
3✔
543
        disconnect(fxi, SIGNAL(changed(quint32)),
3✔
544
                   this, SLOT(slotFixtureChanged(quint32)));
545
        delete fxi;
3✔
546
        m_fixturesListCacheUpToDate = false;
3✔
547
    }
548
    m_latestFixtureId = 0;
1✔
549
    m_addresses.clear();
1✔
550

551
    foreach (Fixture *fixture, newFixturesList)
3✔
552
    {
553
        quint32 id = fixture->id();
2✔
554
        // create a copy of the original cause remapping will
555
        // destroy it later
556
        Fixture *newFixture = new Fixture(this);
2✔
557
        newFixture->setID(id);
2✔
558
        newFixture->setName(fixture->name());
2✔
559
        newFixture->setAddress(fixture->address());
2✔
560
        newFixture->setUniverse(fixture->universe());
2✔
561

562
        if (fixture->fixtureDef() == NULL ||
4✔
563
            (fixture->fixtureDef()->manufacturer() == KXMLFixtureGeneric &&
5✔
564
             fixture->fixtureDef()->model() == KXMLFixtureGeneric))
3✔
565
        {
566
            // Generic dimmers just need to know the number of channels
567
            newFixture->setChannels(fixture->channels());
1✔
568
        }
569
        else if (fixture->fixtureDef() == NULL ||
2✔
570
            (fixture->fixtureDef()->manufacturer() == KXMLFixtureGeneric &&
2✔
571
             fixture->fixtureDef()->model() == KXMLFixtureRGBPanel))
1✔
572
        {
573
            // RGB Panels definitions are not cached or shared, so
574
            // let's make a deep copy of them
575
            QLCFixtureDef *fixtureDef = new QLCFixtureDef();
×
576
            *fixtureDef = *fixture->fixtureDef();
×
UNCOV
577
            QLCFixtureMode *mode = new QLCFixtureMode(fixtureDef);
×
UNCOV
578
            *mode = *fixture->fixtureMode();
×
UNCOV
579
            newFixture->setFixtureDefinition(fixtureDef, mode);
×
580
        }
581
        else
582
        {
583
            QLCFixtureDef *def = fixtureDefCache()->fixtureDef(fixture->fixtureDef()->manufacturer(),
2✔
584
                                                               fixture->fixtureDef()->model());
2✔
585
            QLCFixtureMode *mode = NULL;
586
            if (def != NULL)
1✔
587
                mode = def->mode(fixture->fixtureMode()->name());
1✔
588
            newFixture->setFixtureDefinition(def, mode);
1✔
589
        }
590

591
        newFixture->setExcludeFadeChannels(fixture->excludeFadeChannels());
2✔
592
        newFixture->setForcedHTPChannels(fixture->forcedHTPChannels());
2✔
593
        newFixture->setForcedLTPChannels(fixture->forcedLTPChannels());
2✔
594

595
        m_fixtures.insert(id, newFixture);
2✔
596
        m_fixturesListCacheUpToDate = false;
2✔
597

598
        /* Patch fixture change signals thru Doc */
599
        connect(newFixture, SIGNAL(changed(quint32)),
2✔
600
                this, SLOT(slotFixtureChanged(quint32)));
601

602
        /* Keep track of fixture addresses */
603
        for (uint i = newFixture->universeAddress();
2✔
604
             i < newFixture->universeAddress() + newFixture->channels(); i++)
13✔
605
        {
606
            m_addresses[i] = id;
11✔
607
        }
608
        m_latestFixtureId = id;
2✔
609
    }
610
    return true;
1✔
611
}
612

613
bool Doc::updateFixtureChannelCapabilities(quint32 id, QList<int> forcedHTP, QList<int> forcedLTP)
2✔
614
{
615
    if (m_fixtures.contains(id) == false)
2✔
616
        return false;
617

618
    Fixture* fixture = m_fixtures[id];
1✔
619
    // get exclusive access to the universes list
620
    QList<Universe *> universes = inputOutputMap()->claimUniverses();
1✔
621
    Universe *universe = universes.at(fixture->universe());
1✔
622
    quint32 fxAddress = fixture->address();
1✔
623

624
    // Set forced HTP channels
625
    fixture->setForcedHTPChannels(forcedHTP);
1✔
626

627
    // Set forced LTP channels
628
    fixture->setForcedLTPChannels(forcedLTP);
1✔
629

630
    // Update the Fixture Universe with the current channel states
631
    for (quint32 i = 0 ; i < fixture->channels(); i++)
7✔
632
    {
633
        const QLCChannel *channel(fixture->channel(i));
6✔
634

635
        // Inform Universe of any HTP/LTP forcing
636
        if (forcedHTP.contains(int(i)))
6✔
637
            universe->setChannelCapability(fxAddress + i, channel->group(), Universe::HTP);
2✔
638
        else if (forcedLTP.contains(int(i)))
4✔
639
            universe->setChannelCapability(fxAddress + i, channel->group(), Universe::LTP);
1✔
640
        else
641
            universe->setChannelCapability(fxAddress + i, channel->group());
3✔
642

643
        // Apply the default value BEFORE modifiers
644
        universe->setChannelDefaultValue(fxAddress + i, channel->defaultValue());
6✔
645

646
        // Apply a channel modifier, if defined
647
        ChannelModifier *mod = fixture->channelModifier(i);
6✔
648
        universe->setChannelModifier(fxAddress + i, mod);
6✔
649
    }
650

651
    inputOutputMap()->releaseUniverses(true);
1✔
652

653
    return true;
654
}
1✔
655

656
QList<Fixture*> const& Doc::fixtures() const
71✔
657
{
658
    if (!m_fixturesListCacheUpToDate)
71✔
659
    {
660
        // Sort fixtures by id
661
        QMap <quint32, Fixture*> fixturesMap;
662
        QHashIterator <quint32, Fixture*> hashIt(m_fixtures);
40✔
663
        while (hashIt.hasNext())
75✔
664
        {
665
            hashIt.next();
35✔
666
            fixturesMap.insert(hashIt.key(), hashIt.value());
35✔
667
        }
668
        const_cast<QList<Fixture*>&>(m_fixturesListCache) = fixturesMap.values();
80✔
669
        const_cast<bool&>(m_fixturesListCacheUpToDate) = true;
40✔
670
    }
40✔
671
    return m_fixturesListCache;
71✔
672
}
673

UNCOV
674
int Doc::fixturesCount() const
×
675
{
UNCOV
676
    return m_fixtures.count();
×
677
}
678

679
Fixture* Doc::fixture(quint32 id) const
796,289✔
680
{
681
    return m_fixtures.value(id, NULL);
796,289✔
682
}
683

684
quint32 Doc::fixtureForAddress(quint32 universeAddress) const
79✔
685
{
686
    return m_addresses.value(universeAddress, Fixture::invalidId());
79✔
687
}
688

689
int Doc::totalPowerConsumption(int& fuzzy) const
4✔
690
{
691
    int totalPowerConsumption = 0;
692

693
    // Make sure fuzzy starts from zero
694
    fuzzy = 0;
4✔
695

696
    QListIterator <Fixture*> fxit(fixtures());
4✔
697
    while (fxit.hasNext() == true)
14✔
698
    {
699
        Fixture* fxi(fxit.next());
10✔
700
        Q_ASSERT(fxi != NULL);
701

702
        if (fxi->fixtureMode() != NULL)
10✔
703
        {
704
            QLCPhysical phys = fxi->fixtureMode()->physical();
10✔
705
            if (phys.powerConsumption() > 0)
10✔
706
                totalPowerConsumption += phys.powerConsumption();
7✔
707
            else
708
                fuzzy++;
3✔
709
        }
10✔
710
        else
711
        {
UNCOV
712
            fuzzy++;
×
713
        }
714
    }
715

716
    return totalPowerConsumption;
4✔
717
}
718

719
void Doc::slotFixtureChanged(quint32 id)
4✔
720
{
721
    /* Keep track of fixture addresses */
722
    Fixture* fxi = fixture(id);
4✔
723

724
    // remove it
725
    QMutableHashIterator <uint,uint> it(m_addresses);
4✔
726
    while (it.hasNext() == true)
67✔
727
    {
728
        it.next();
63✔
729
        if (it.value() == id)
63✔
730
        {
731
            qDebug() << Q_FUNC_INFO << " remove: " << it.key() << " val: " << it.value();
732
            it.remove();
19✔
733
        }
734
    }
735

736
    for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++)
23✔
737
    {
738
        /*
739
         * setting new universe and address calls this twice,
740
         * with an tmp wrong address after the first call (old address() + new universe()).
741
         * we only add if the channel is free, to prevent messing up things
742
         */
743
        Q_ASSERT(!m_addresses.contains(i));
744
        m_addresses[i] = id;
19✔
745
    }
746

747
    setModified();
4✔
748
    emit fixtureChanged(id);
4✔
749
}
4✔
750

751
/*****************************************************************************
752
 * Fixture groups
753
 *****************************************************************************/
754

755
bool Doc::addFixtureGroup(FixtureGroup* grp, quint32 id)
15✔
756
{
757
    Q_ASSERT(grp != NULL);
758

759
    // No ID given, this method can assign one
760
    if (id == FixtureGroup::invalidId())
15✔
761
        id = createFixtureGroupId();
8✔
762

763
    if (m_fixtureGroups.contains(id) == true || id == FixtureGroup::invalidId())
15✔
764
    {
765
        qWarning() << Q_FUNC_INFO << "a fixture group with ID" << id << "already exists!";
2✔
766
        return false;
2✔
767
    }
768
    else
769
    {
770
        grp->setId(id);
13✔
771
        m_fixtureGroups[id] = grp;
13✔
772

773
        /* Patch fixture group change signals thru Doc */
774
        connect(grp, SIGNAL(changed(quint32)),
13✔
775
                this, SLOT(slotFixtureGroupChanged(quint32)));
776

777
        emit fixtureGroupAdded(id);
13✔
778
        setModified();
13✔
779

780
        return true;
13✔
781
    }
782
}
783

784
bool Doc::deleteFixtureGroup(quint32 id)
4✔
785
{
786
    if (m_fixtureGroups.contains(id) == true)
4✔
787
    {
788
        FixtureGroup* grp = m_fixtureGroups.take(id);
2✔
789
        Q_ASSERT(grp != NULL);
790

791
        emit fixtureGroupRemoved(id);
2✔
792
        setModified();
2✔
793
        delete grp;
2✔
794

795
        return true;
2✔
796
    }
797
    else
798
    {
799
        qWarning() << Q_FUNC_INFO << "No fixture group with id" << id;
2✔
800
        return false;
2✔
801
    }
802
}
803

804
FixtureGroup* Doc::fixtureGroup(quint32 id) const
45✔
805
{
806
    if (m_fixtureGroups.contains(id) == true)
45✔
807
        return m_fixtureGroups[id];
20✔
808
    else
809
        return NULL;
810
}
811

812
QList <FixtureGroup*> Doc::fixtureGroups() const
34✔
813
{
814
    return m_fixtureGroups.values();
34✔
815
}
816

817
quint32 Doc::createFixtureGroupId()
8✔
818
{
819
    /* This results in an endless loop if there are UINT_MAX-1 fixture groups. That,
820
       however, seems a bit unlikely. Are there even 4294967295-1 fixtures in
821
       total in the whole world? */
822
    while (m_fixtureGroups.contains(m_latestFixtureGroupId) == true ||
20✔
823
           m_latestFixtureGroupId == FixtureGroup::invalidId())
8✔
824
    {
825
        m_latestFixtureGroupId++;
4✔
826
    }
827

828
    return m_latestFixtureGroupId;
8✔
829
}
830

831
void Doc::slotFixtureGroupChanged(quint32 id)
25✔
832
{
833
    setModified();
25✔
834
    emit fixtureGroupChanged(id);
25✔
835
}
25✔
836

837
/*********************************************************************
838
 * Channels groups
839
 *********************************************************************/
840
bool Doc::addChannelsGroup(ChannelsGroup *grp, quint32 id)
4✔
841
{
842
    Q_ASSERT(grp != NULL);
843

844
    // No ID given, this method can assign one
845
    if (id == ChannelsGroup::invalidId())
4✔
846
        id = createChannelsGroupId();
4✔
847

848
     grp->setId(id);
4✔
849
     m_channelsGroups[id] = grp;
4✔
850
     if (m_orderedGroups.contains(id) == false)
4✔
851
        m_orderedGroups.append(id);
4✔
852

853
     emit channelsGroupAdded(id);
4✔
854
     setModified();
4✔
855

856
     return true;
4✔
857
}
858

859
bool Doc::deleteChannelsGroup(quint32 id)
2✔
860
{
861
    if (m_channelsGroups.contains(id) == true)
2✔
862
    {
863
        ChannelsGroup* grp = m_channelsGroups.take(id);
1✔
864
        Q_ASSERT(grp != NULL);
865

866
        emit channelsGroupRemoved(id);
1✔
867
        setModified();
1✔
868
        delete grp;
1✔
869

870
        int idx = m_orderedGroups.indexOf(id);
1✔
871
        if (idx != -1)
1✔
872
            m_orderedGroups.takeAt(idx);
1✔
873

874
        return true;
1✔
875
    }
876
    else
877
    {
878
        qWarning() << Q_FUNC_INFO << "No channels group with id" << id;
1✔
879
        return false;
1✔
880
    }
881
}
882

883
bool Doc::moveChannelGroup(quint32 id, int direction)
3✔
884
{
885
    if (direction == 0 || m_orderedGroups.contains(id) == false)
3✔
886
        return false;
887

888
    int idx = m_orderedGroups.indexOf(id);
889

890
    if (idx + direction < 0 || idx + direction >= m_orderedGroups.count())
2✔
891
        return false;
892

893
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
894
    m_orderedGroups.takeAt(idx);
1✔
895
    m_orderedGroups.insert(idx + direction, id);
1✔
896
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
897

898
    setModified();
1✔
899
    return true;
1✔
900
}
901

902
ChannelsGroup* Doc::channelsGroup(quint32 id) const
2✔
903
{
904
    if (m_channelsGroups.contains(id) == true)
2✔
905
        return m_channelsGroups[id];
1✔
906
    else
907
        return NULL;
908
}
909

910
QList <ChannelsGroup*> Doc::channelsGroups() const
15✔
911
{
912
    QList <ChannelsGroup*> orderedList;
913

914
    for (int i = 0; i < m_orderedGroups.count(); i++)
37✔
915
    {
916
        orderedList.append(m_channelsGroups[m_orderedGroups.at(i)]);
22✔
917
    }
918
    return orderedList;
15✔
UNCOV
919
}
×
920

921
quint32 Doc::createChannelsGroupId()
4✔
922
{
923
    while (m_channelsGroups.contains(m_latestChannelsGroupId) == true ||
10✔
924
           m_latestChannelsGroupId == ChannelsGroup::invalidId())
4✔
925
    {
926
        m_latestChannelsGroupId++;
2✔
927
    }
928

929
    return m_latestChannelsGroupId;
4✔
930
}
931

932
/*********************************************************************
933
 * Palettes
934
 *********************************************************************/
935

936
bool Doc::addPalette(QLCPalette *palette, quint32 id)
2✔
937
{
938
    Q_ASSERT(palette != NULL);
939

940
    // No ID given, this method can assign one
941
    if (id == QLCPalette::invalidId())
2✔
942
        id = createPaletteId();
2✔
943

944
    if (m_palettes.contains(id) == true || id == QLCPalette::invalidId())
2✔
945
    {
UNCOV
946
        qWarning() << Q_FUNC_INFO << "a palette with ID" << id << "already exists!";
×
UNCOV
947
        return false;
×
948
    }
949
    else
950
    {
951
        palette->setID(id);
2✔
952
        m_palettes[id] = palette;
2✔
953

954
        emit paletteAdded(id);
2✔
955
        setModified();
2✔
956
    }
957

958
    return true;
2✔
959
}
960

961
bool Doc::deletePalette(quint32 id)
3✔
962
{
963
    if (m_palettes.contains(id) == true)
3✔
964
    {
965
        QLCPalette *palette = m_palettes.take(id);
2✔
966
        Q_ASSERT(palette != NULL);
967

968
        emit paletteRemoved(id);
2✔
969
        setModified();
2✔
970
        delete palette;
2✔
971

972
        return true;
2✔
973
    }
974
    else
975
    {
976
        qWarning() << Q_FUNC_INFO << "No palette with id" << id;
1✔
977
        return false;
1✔
978
    }
979
}
980

981
QLCPalette *Doc::palette(quint32 id) const
2✔
982
{
983
    if (m_palettes.contains(id) == true)
2✔
984
        return m_palettes[id];
1✔
985
    else
986
        return NULL;
987
}
988

989
QList<QLCPalette *> Doc::palettes() const
8✔
990
{
991
    return m_palettes.values();
8✔
992
}
993

994
quint32 Doc::createPaletteId()
2✔
995
{
996
    while (m_palettes.contains(m_latestPaletteId) == true ||
5✔
997
           m_latestPaletteId == FixtureGroup::invalidId())
2✔
998
    {
999
        m_latestPaletteId++;
1✔
1000
    }
1001

1002
    return m_latestPaletteId;
2✔
1003
}
1004

1005
/*****************************************************************************
1006
 * Functions
1007
 *****************************************************************************/
1008

1009
quint32 Doc::createFunctionId()
243✔
1010
{
1011
    /* This results in an endless loop if there are UINT_MAX-1 functions. That,
1012
       however, seems a bit unlikely. Are there even 4294967295-1 functions in
1013
       total in the whole world? */
1014
    while (m_functions.contains(m_latestFunctionId) == true ||
653✔
1015
           m_latestFunctionId == Fixture::invalidId())
243✔
1016
    {
1017
        m_latestFunctionId++;
167✔
1018
    }
1019

1020
    return m_latestFunctionId;
243✔
1021
}
1022

1023
bool Doc::addFunction(Function* func, quint32 id)
256✔
1024
{
1025
    Q_ASSERT(func != NULL);
1026

1027
    if (id == Function::invalidId())
256✔
1028
        id = createFunctionId();
243✔
1029

1030
    if (m_functions.contains(id) == true || id == Fixture::invalidId())
256✔
1031
    {
1032
        qWarning() << Q_FUNC_INFO << "a function with ID" << id << "already exists!";
2✔
1033
        return false;
2✔
1034
    }
1035
    else
1036
    {
1037
        // Listen to function changes
1038
        connect(func, SIGNAL(changed(quint32)),
254✔
1039
                this, SLOT(slotFunctionChanged(quint32)));
1040

1041
        // Listen to function name changes
1042
        connect(func, SIGNAL(nameChanged(quint32)),
254✔
1043
                this, SLOT(slotFunctionNameChanged(quint32)));
1044

1045
        // Make the function listen to fixture removals
1046
        connect(this, SIGNAL(fixtureRemoved(quint32)),
254✔
1047
                func, SLOT(slotFixtureRemoved(quint32)));
1048

1049
        // Place the function in the map and assign it the new ID
1050
        m_functions[id] = func;
254✔
1051
        func->setID(id);
254✔
1052
        emit functionAdded(id);
254✔
1053
        setModified();
254✔
1054

1055
        return true;
254✔
1056
    }
1057
}
1058

1059
QList <Function*> Doc::functions() const
49✔
1060
{
1061
    return m_functions.values();
49✔
1062
}
1063

1064
QList<Function *> Doc::functionsByType(Function::Type type) const
1✔
1065
{
1066
    QList <Function*> list;
1067
    foreach (Function *f, m_functions)
11✔
1068
    {
1069
        if (f != NULL && f->type() == type)
9✔
1070
            list.append(f);
5✔
1071
    }
1072
    return list;
1✔
UNCOV
1073
}
×
1074

UNCOV
1075
Function *Doc::functionByName(QString name)
×
1076
{
UNCOV
1077
    foreach (Function *f, m_functions)
×
1078
    {
1079
        if (f != NULL && f->name() == name)
×
1080
            return f;
1081
    }
UNCOV
1082
    return NULL;
×
1083
}
1084

1085
bool Doc::deleteFunction(quint32 id)
10✔
1086
{
1087
    if (m_functions.contains(id) == true)
10✔
1088
    {
1089
        Function* func = m_functions.take(id);
8✔
1090
        Q_ASSERT(func != NULL);
1091

1092
        if (m_startupFunctionId == id)
8✔
UNCOV
1093
            m_startupFunctionId = Function::invalidId();
×
1094

1095
        emit functionRemoved(id);
8✔
1096
        setModified();
8✔
1097
        delete func;
8✔
1098

1099
        return true;
8✔
1100
    }
1101
    else
1102
    {
1103
        qWarning() << Q_FUNC_INFO << "No function with id" << id;
2✔
1104
        return false;
2✔
1105
    }
1106
}
1107

1108
Function* Doc::function(quint32 id) const
884✔
1109
{
1110
    if (m_functions.contains(id) == true)
884✔
1111
        return m_functions[id];
821✔
1112
    else
1113
        return NULL;
1114
}
1115

1116
quint32 Doc::nextFunctionID()
2✔
1117
{
1118
    quint32 tmpFID = m_latestFunctionId;
2✔
1119
    while (m_functions.contains(tmpFID) == true ||
3✔
1120
           tmpFID == Fixture::invalidId())
2✔
1121
    {
1122
        tmpFID++;
1✔
1123
    }
1124

1125
    return tmpFID;
2✔
1126
}
1127

1128
void Doc::setStartupFunction(quint32 fid)
1✔
1129
{
1130
    m_startupFunctionId = fid;
1✔
1131
}
1✔
1132

1133
quint32 Doc::startupFunction()
3✔
1134
{
1135
    return m_startupFunctionId;
3✔
1136
}
1137

1138
QList<quint32> Doc::getUsage(quint32 fid)
7✔
1139
{
1140
    QList<quint32> usageList;
1141

1142
    foreach (Function *f, m_functions)
70✔
1143
    {
1144
        if (f->id() == fid)
63✔
1145
            continue;
6✔
1146

1147
        switch(f->type())
57✔
1148
        {
1149
            case Function::CollectionType:
1150
            {
1151
                Collection *c = qobject_cast<Collection *>(f);
1152
                int pos = c->functions().indexOf(fid);
7✔
1153
                if (pos != -1)
7✔
1154
                {
1155
                    usageList.append(f->id());
2✔
1156
                    usageList.append(pos);
2✔
1157
                }
1158
            }
1159
            break;
1160
            case Function::ChaserType:
1161

1162
            {
1163
                Chaser *c = qobject_cast<Chaser *>(f);
1164
                for (int i = 0; i < c->stepsCount(); i++)
18✔
1165
                {
1166
                    ChaserStep *cs = c->stepAt(i);
12✔
1167
                    if (cs->fid == fid)
12✔
1168
                    {
1169
                        usageList.append(f->id());
2✔
1170
                        usageList.append(i);
2✔
1171
                    }
1172
                }
1173
            }
1174
            break;
1175
            case Function::SequenceType:
1176
            {
1177
                Sequence *s = qobject_cast<Sequence *>(f);
1178
                if (s->boundSceneID() == fid)
7✔
1179
                {
1180
                    usageList.append(f->id());
1✔
1181
                    usageList.append(0);
1✔
1182
                }
1183
            }
1184
            break;
1185
            case Function::ScriptType:
1186
            {
1187
                Script *s = qobject_cast<Script *>(f);
1188
                QList<quint32> l = s->functionList();
7✔
1189
                for (int i = 0; i < l.count(); i+=2)
14✔
1190
                {
1191
                    if (l.at(i) == fid)
7✔
1192
                    {
1193
                        if (i + 1 >= l.count()) {
1✔
1194
                            qDebug() << "Doc::getUsage: Index entry missing on " << f->name();
1195
                            break;
1196
                        }
1197
                        usageList.append(s->id());
1✔
1198
                        usageList.append(l.at(i + 1)); // line number
1✔
1199
                    }
1200
                }
1201
            }
7✔
1202
            break;
7✔
1203
            case Function::ShowType:
1204
            {
1205
                Show *s = qobject_cast<Show *>(f);
UNCOV
1206
                foreach (Track *t, s->tracks())
×
1207
                {
UNCOV
1208
                    foreach (ShowFunction *sf, t->showFunctions())
×
1209
                    {
1210
                        if (sf->functionID() == fid)
×
1211
                        {
UNCOV
1212
                            usageList.append(f->id());
×
UNCOV
1213
                            usageList.append(t->id());
×
1214
                        }
1215
                    }
1216
                }
1217
            }
UNCOV
1218
            break;
×
1219
            default:
1220
            break;
1221
        }
1222
    }
1223

1224
    return usageList;
7✔
UNCOV
1225
}
×
1226

1227
void Doc::slotFunctionChanged(quint32 fid)
111✔
1228
{
1229
    setModified();
111✔
1230
    emit functionChanged(fid);
111✔
1231
}
111✔
1232

1233
void Doc::slotFunctionNameChanged(quint32 fid)
2✔
1234
{
1235
    setModified();
2✔
1236
    emit functionNameChanged(fid);
2✔
1237
}
2✔
1238

1239
/*********************************************************************
1240
 * Monitor Properties
1241
 *********************************************************************/
1242

1243
MonitorProperties *Doc::monitorProperties()
1✔
1244
{
1245
    if (m_monitorProps == NULL)
1✔
1246
        m_monitorProps = new MonitorProperties();
2✔
1247

1248
    return m_monitorProps;
1✔
1249
}
1250

1251
/*****************************************************************************
1252
 * Load & Save
1253
 *****************************************************************************/
1254

1255
bool Doc::loadXML(QXmlStreamReader &doc, bool loadIO)
2✔
1256
{
1257
    clearErrorLog();
2✔
1258

1259
    if (doc.name() != KXMLQLCEngine)
4✔
1260
    {
1261
        qWarning() << Q_FUNC_INFO << "Engine node not found";
1✔
1262
        return false;
1✔
1263
    }
1264

1265
    m_loadStatus = Loading;
1✔
1266
    emit loading();
1✔
1267

1268
    if (doc.attributes().hasAttribute(KXMLQLCStartupFunction))
1✔
1269
    {
UNCOV
1270
        quint32 sID = doc.attributes().value(KXMLQLCStartupFunction).toString().toUInt();
×
UNCOV
1271
        if (sID != Function::invalidId())
×
UNCOV
1272
            setStartupFunction(sID);
×
1273
    }
1274

1275
    while (doc.readNextStartElement())
17✔
1276
    {
1277
        //qDebug() << "Doc tag:" << doc.name();
1278
        if (doc.name() == KXMLFixture)
32✔
1279
        {
1280
            Fixture::loader(doc, this);
3✔
1281
        }
1282
        else if (doc.name() == KXMLQLCFixtureGroup)
26✔
1283
        {
1284
            FixtureGroup::loader(doc, this);
3✔
1285
        }
1286
        else if (doc.name() == KXMLQLCChannelsGroup)
20✔
1287
        {
UNCOV
1288
            ChannelsGroup::loader(doc, this);
×
1289
        }
1290
        else if (doc.name() == KXMLQLCPalette)
20✔
1291
        {
UNCOV
1292
            QLCPalette::loader(doc, this);
×
UNCOV
1293
            doc.skipCurrentElement();
×
1294
        }
1295
        else if (doc.name() == KXMLQLCFunction)
20✔
1296
        {
1297
            //qDebug() << doc.attributes().value("Name").toString();
1298
            Function::loader(doc, this);
4✔
1299
        }
1300
        else if (doc.name() == KXMLQLCBus)
12✔
1301
        {
1302
            /* LEGACY */
1303
            Bus::instance()->loadXML(doc);
5✔
1304
        }
1305
        else if (doc.name() == KXMLIOMap && loadIO)
3✔
1306
        {
UNCOV
1307
            m_ioMap->loadXML(doc);
×
1308
        }
1309
        else if (doc.name() == KXMLQLCMonitorProperties)
2✔
1310
        {
UNCOV
1311
            monitorProperties()->loadXML(doc, this);
×
1312
        }
1313
        else
1314
        {
1315
            qWarning() << Q_FUNC_INFO << "Unknown engine tag:" << doc.name();
1✔
1316
            doc.skipCurrentElement();
1✔
1317
        }
1318
    }
1319

1320
    postLoad();
1✔
1321

1322
    m_loadStatus = Loaded;
1✔
1323
    emit loaded();
1✔
1324

1325
    return true;
1✔
1326
}
1327

1328
bool Doc::saveXML(QXmlStreamWriter *doc)
1✔
1329
{
1330
    Q_ASSERT(doc != NULL);
1331

1332
    /* Create the master Engine node */
1333
    doc->writeStartElement(KXMLQLCEngine);
1✔
1334

1335
    if (startupFunction() != Function::invalidId())
1✔
1336
        doc->writeAttribute(KXMLQLCStartupFunction, QString::number(startupFunction()));
1✔
1337

1338
    m_ioMap->saveXML(doc);
1✔
1339

1340
    /* Write fixtures into an XML document */
1341
    QListIterator <Fixture*> fxit(fixtures());
1✔
1342
    while (fxit.hasNext() == true)
4✔
1343
    {
1344
        Fixture *fxi(fxit.next());
3✔
1345
        Q_ASSERT(fxi != NULL);
1346
        fxi->saveXML(doc);
3✔
1347
    }
1348

1349
    /* Write fixture groups into an XML document */
1350
    QListIterator <FixtureGroup*> grpit(fixtureGroups());
1✔
1351
    while (grpit.hasNext() == true)
3✔
1352
    {
1353
        FixtureGroup *grp(grpit.next());
2✔
1354
        Q_ASSERT(grp != NULL);
1355
        grp->saveXML(doc);
2✔
1356
    }
1357

1358
    /* Write channel groups into an XML document */
1359
    QListIterator <ChannelsGroup*> chanGroups(channelsGroups());
1✔
1360
    while (chanGroups.hasNext() == true)
1✔
1361
    {
UNCOV
1362
        ChannelsGroup *grp(chanGroups.next());
×
1363
        Q_ASSERT(grp != NULL);
UNCOV
1364
        grp->saveXML(doc);
×
1365
    }
1366

1367
    /* Write palettes into an XML document */
1368
    QListIterator <QLCPalette*> paletteIt(palettes());
1✔
1369
    while (paletteIt.hasNext() == true)
1✔
1370
    {
UNCOV
1371
        QLCPalette *palette(paletteIt.next());
×
1372
        Q_ASSERT(palette != NULL);
UNCOV
1373
        palette->saveXML(doc);
×
1374
    }
1375

1376
    /* Write functions into an XML document */
1377
    QListIterator <Function*> funcit(functions());
1✔
1378
    while (funcit.hasNext() == true)
5✔
1379
    {
1380
        Function *func(funcit.next());
4✔
1381
        Q_ASSERT(func != NULL);
1382
        func->saveXML(doc);
4✔
1383
    }
1384

1385
    if (m_monitorProps != NULL)
1✔
1386
        m_monitorProps->saveXML(doc, this);
1✔
1387

1388
    /* End the <Engine> tag */
1389
    doc->writeEndElement();
1✔
1390

1391
    return true;
1✔
1392
}
1393

1394
void Doc::appendToErrorLog(QString error)
8✔
1395
{
1396
    if (m_errorLog.contains(error))
8✔
1397
        return;
1398

1399
    m_errorLog.append(error);
3✔
1400
    m_errorLog.append("<br>");
3✔
1401
}
1402

1403
void Doc::clearErrorLog()
2✔
1404
{
1405
    m_errorLog = "";
2✔
1406
}
2✔
1407

1408
QString Doc::errorLog()
1✔
1409
{
1410
    return m_errorLog;
1✔
1411
}
1412

1413
void Doc::postLoad()
1✔
1414
{
1415
    QListIterator <Function*> functionit(functions());
1✔
1416
    while (functionit.hasNext() == true)
5✔
1417
    {
1418
        Function* function(functionit.next());
4✔
1419
        Q_ASSERT(function != NULL);
1420
        function->postLoad();
4✔
1421
    }
1422
}
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

© 2025 Coveralls, Inc