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

mcallegari / qlcplus / 16072648568

04 Jul 2025 11:22AM UTC coverage: 31.889% (-0.01%) from 31.899%
16072648568

push

github

mcallegari
engine: handle fixture definitions without modes (fix #1775)

2 of 3 new or added lines in 2 files covered. (66.67%)

3722 existing lines in 175 files now uncovered.

16453 of 51594 relevant lines covered (31.89%)

19305.2 hits per line

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

90.14
/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(6, 0, 0)
52
 #include "audiocapture_qt5.h"
53
#else
54
 #include "audiocapture_qt6.h"
55
#endif
56

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

88
Doc::~Doc()
314✔
89
{
90
    delete m_masterTimer;
177✔
91
    m_masterTimer = NULL;
177✔
92

93
    clearContents();
177✔
94

95
    if (isKiosk() == false)
177✔
96
    {
97
        // TODO: is this still needed ??
98
        //m_ioMap->saveDefaults();
99
    }
100
    delete m_ioMap;
177✔
101
    m_ioMap = NULL;
177✔
102

103
    delete m_ioPluginCache;
177✔
104
    m_ioPluginCache = NULL;
177✔
105

106
    delete m_modifiersCache;
177✔
107
    m_modifiersCache = NULL;
177✔
108

109
    delete m_fixtureDefCache;
177✔
110
    m_fixtureDefCache = NULL;
177✔
111

112
    delete m_rgbScriptsCache;
177✔
113
    m_rgbScriptsCache = NULL;
177✔
114
}
314✔
115

116
void Doc::clearContents()
452✔
117
{
118
    emit clearing();
452✔
119

120
    m_clipboard->resetContents();
452✔
121

122
    if (m_monitorProps != NULL)
452✔
123
        m_monitorProps->reset();
9✔
124

125
    destroyAudioCapture();
452✔
126

127
    // Delete all function instances
128
    QListIterator <quint32> funcit(m_functions.keys());
452✔
129
    while (funcit.hasNext() == true)
698✔
130
    {
131
        Function* func = m_functions.take(funcit.next());
246✔
132
        if (func == NULL)
246✔
133
            continue;
×
134
        emit functionRemoved(func->id());
246✔
135
        delete func;
246✔
136
    }
137

138
    // Delete all palettes
139
    QListIterator <quint32> palIt(m_palettes.keys());
452✔
140
    while (palIt.hasNext() == true)
452✔
141
    {
142
        QLCPalette *palette = m_palettes.take(palIt.next());
×
143
        emit paletteRemoved(palette->id());
×
144
        delete palette;
×
145
    }
146

147
    // Delete all channel groups
148
    QListIterator <quint32> grpchans(m_channelsGroups.keys());
452✔
149
    while (grpchans.hasNext() == true)
455✔
150
    {
151
        ChannelsGroup* grp = m_channelsGroups.take(grpchans.next());
3✔
152
        emit channelsGroupRemoved(grp->id());
3✔
153
        delete grp;
3✔
154
    }
155

156
    // Delete all fixture groups
157
    QListIterator <quint32> grpit(m_fixtureGroups.keys());
452✔
158
    while (grpit.hasNext() == true)
463✔
159
    {
160
        FixtureGroup* grp = m_fixtureGroups.take(grpit.next());
11✔
161
        quint32 grpID = grp->id();
11✔
162
        delete grp;
11✔
163
        emit fixtureGroupRemoved(grpID);
11✔
164
    }
165

166
    // Delete all fixture instances
167
    QListIterator <quint32> fxit(m_fixtures.keys());
452✔
168
    while (fxit.hasNext() == true)
17,226✔
169
    {
170
        Fixture* fxi = m_fixtures.take(fxit.next());
16,774✔
171
        quint32 fxID = fxi->id();
16,774✔
172
        delete fxi;
16,774✔
173
        emit fixtureRemoved(fxID);
16,774✔
174
    }
175
    m_fixturesListCacheUpToDate = false;
452✔
176

177
    m_orderedGroups.clear();
452✔
178

179
    m_latestFunctionId = 0;
452✔
180
    m_latestFixtureId = 0;
452✔
181
    m_latestFixtureGroupId = 0;
452✔
182
    m_latestChannelsGroupId = 0;
452✔
183
    m_latestPaletteId = 0;
452✔
184
    m_addresses.clear();
452✔
185
    m_loadStatus = Cleared;
452✔
186

187
    emit cleared();
452✔
188
}
452✔
189

190
void Doc::setWorkspacePath(QString path)
4✔
191
{
192
    m_workspacePath = path;
4✔
193
}
4✔
194

195
QString Doc::workspacePath() const
105✔
196
{
197
    return m_workspacePath;
105✔
198
}
199

200
QString Doc::normalizeComponentPath(const QString& filePath) const
7✔
201
{
202
    if (filePath.isEmpty())
7✔
203
        return filePath;
1✔
204

205
    QFileInfo f(filePath);
6✔
206

207
    if (f.absolutePath().startsWith(workspacePath()))
6✔
208
    {
209
        return QDir(workspacePath()).relativeFilePath(f.absoluteFilePath());
8✔
210
    }
211
    else
212
    {
213
        return f.absoluteFilePath();
2✔
214
    }
215
}
6✔
216

217
QString Doc::denormalizeComponentPath(const QString& filePath) const
8✔
218
{
219
    if (filePath.isEmpty())
8✔
220
        return filePath;
2✔
221

222
    return QFileInfo(QDir(workspacePath()), filePath).absoluteFilePath();
12✔
223
}
224

225
/*****************************************************************************
226
 * Engine components
227
 *****************************************************************************/
228

229
QLCFixtureDefCache* Doc::fixtureDefCache() const
1,643✔
230
{
231
    return m_fixtureDefCache;
1,643✔
232
}
233

234
void Doc::setFixtureDefinitionCache(QLCFixtureDefCache *cache)
×
235
{
236
    m_fixtureDefCache = cache;
×
237
}
×
238

239
QLCModifiersCache* Doc::modifiersCache() const
1✔
240
{
241
    return m_modifiersCache;
1✔
242
}
243

244
RGBScriptsCache* Doc::rgbScriptsCache() const
69✔
245
{
246
    return m_rgbScriptsCache;
69✔
247
}
248

249
IOPluginCache* Doc::ioPluginCache() const
288✔
250
{
251
    return m_ioPluginCache;
288✔
252
}
253

254
AudioPluginCache *Doc::audioPluginCache() const
1✔
255
{
256
    return m_audioPluginCache;
1✔
257
}
258

259
InputOutputMap* Doc::inputOutputMap() const
2,709✔
260
{
261
    return m_ioMap;
2,709✔
262
}
263

264
MasterTimer* Doc::masterTimer() const
1,102✔
265
{
266
    return m_masterTimer;
1,102✔
267
}
268

269
QSharedPointer<AudioCapture> Doc::audioInputCapture()
17✔
270
{
271
    if (!m_inputCapture)
17✔
272
    {
273
        qDebug() << "Creating new audio capture";
2✔
274
        m_inputCapture = QSharedPointer<AudioCapture>(
4✔
275
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
276
            new AudioCaptureQt5()
277
#else
278
            new AudioCaptureQt6()
2✔
279
#endif
280
            );
2✔
281
    }
282
    return m_inputCapture;
17✔
283
}
284

285
void Doc::destroyAudioCapture()
452✔
286
{
287
    if (m_inputCapture.isNull() == false)
452✔
288
    {
289
        qDebug() << "Destroying audio capture";
2✔
290
        m_inputCapture.clear();
2✔
291
    }
292
}
452✔
293

294
/*****************************************************************************
295
 * Modified status
296
 *****************************************************************************/
297
Doc::LoadStatus Doc::loadStatus() const
2✔
298
{
299
    return m_loadStatus;
2✔
300
}
301

302
bool Doc::isModified() const
29✔
303
{
304
    return m_modified;
29✔
305
}
306

307
void Doc::setModified()
1,245✔
308
{
309
    m_modified = true;
1,245✔
310
    emit modified(true);
1,245✔
311
}
1,245✔
312

313
void Doc::resetModified()
192✔
314
{
315
    m_modified = false;
192✔
316
    emit modified(false);
192✔
317
}
192✔
318

319
/*****************************************************************************
320
 * Main operating mode
321
 *****************************************************************************/
322

323
void Doc::setMode(Doc::Mode mode)
23✔
324
{
325
    /* Don't do mode switching twice */
326
    if (m_mode == mode)
23✔
327
        return;
2✔
328
    m_mode = mode;
21✔
329

330
    // Run startup function
331
    if (m_mode == Operate && m_startupFunctionId != Function::invalidId())
21✔
332
    {
333
        Function *func = function(m_startupFunctionId);
×
334
        if (func != NULL)
×
335
        {
336
            qDebug() << Q_FUNC_INFO << "Starting startup function. (" << m_startupFunctionId << ")";
×
337
            func->start(masterTimer(), FunctionParent::master());
×
338
        }
339
        else
340
        {
341
            qWarning() << Q_FUNC_INFO << "Startup function does not exist, erasing. (" << m_startupFunctionId << ")";
×
342
            m_startupFunctionId = Function::invalidId();
×
343
        }
344
    }
345

346
    emit modeChanged(m_mode);
21✔
347
}
348

349
Doc::Mode Doc::mode() const
323✔
350
{
351
    return m_mode;
323✔
352
}
353

354
void Doc::setKiosk(bool state)
1✔
355
{
356
    m_kiosk = state;
1✔
357
}
1✔
358

359
bool Doc::isKiosk() const
179✔
360
{
361
    return m_kiosk;
179✔
362
}
363

364
/*********************************************************************
365
 * Clipboard
366
 *********************************************************************/
367

368
QLCClipboard *Doc::clipboard()
1✔
369
{
370
    return m_clipboard;
1✔
371
}
372

373
/*****************************************************************************
374
 * Fixtures
375
 *****************************************************************************/
376

377
quint32 Doc::createFixtureId()
16,781✔
378
{
379
    /* This results in an endless loop if there are UINT_MAX-1 fixtures. That,
380
       however, seems a bit unlikely. Are there even 4294967295-1 fixtures in
381
       total in the whole world? */
382
    while (m_fixtures.contains(m_latestFixtureId) == true ||
50,195✔
383
           m_latestFixtureId == Fixture::invalidId())
16,781✔
384
    {
385
        m_latestFixtureId++;
16,633✔
386
    }
387

388
    return m_latestFixtureId;
16,781✔
389
}
390

391
bool Doc::addFixture(Fixture* fixture, quint32 id, bool crossUniverse)
406✔
392
{
393
    Q_ASSERT(fixture != NULL);
406✔
394

395
    quint32 i;
396
    quint32 uni = fixture->universe();
406✔
397

398
    // No ID given, this method can assign one
399
    if (id == Fixture::invalidId())
406✔
400
        id = createFixtureId();
397✔
401

402
    if (m_fixtures.contains(id) == true || id == Fixture::invalidId())
406✔
403
    {
404
        qWarning() << Q_FUNC_INFO << "a fixture with ID" << id << "already exists!";
1✔
405
        return false;
1✔
406
    }
407

408
    /* Check for overlapping address */
409
    for (i = fixture->universeAddress();
2,971✔
410
         i < fixture->universeAddress() + fixture->channels(); i++)
2,971✔
411
    {
412
        if (m_addresses.contains(i))
2,570✔
413
        {
414
            qWarning() << Q_FUNC_INFO << "fixture" << id << "overlapping with fixture" << m_addresses[i] << "@ channel" << i;
4✔
415
            return false;
4✔
416
        }
417
    }
418

419
    fixture->setID(id);
401✔
420
    m_fixtures.insert(id, fixture);
401✔
421
    m_fixturesListCacheUpToDate = false;
401✔
422

423
    /* Patch fixture change signals thru Doc */
424
    connect(fixture, SIGNAL(changed(quint32)),
401✔
425
            this, SLOT(slotFixtureChanged(quint32)));
426

427
    /* Keep track of fixture addresses */
428
    for (i = fixture->universeAddress();
401✔
429
         i < fixture->universeAddress() + fixture->channels(); i++)
2,967✔
430
    {
431
        m_addresses[i] = id;
2,566✔
432
    }
433

434
    if (crossUniverse)
401✔
435
        uni = floor((fixture->universeAddress() + fixture->channels()) / 512);
×
436

437
    if (uni >= inputOutputMap()->universesCount())
401✔
438
    {
439
        for (i = inputOutputMap()->universesCount(); i <= uni; i++)
×
440
            inputOutputMap()->addUniverse(i);
×
441
        inputOutputMap()->startUniverses();
×
442
    }
443

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

447
    QList<int> forcedHTP = fixture->forcedHTPChannels();
401✔
448
    QList<int> forcedLTP = fixture->forcedLTPChannels();
401✔
449
    quint32 fxAddress = fixture->address();
401✔
450

451
    for (i = 0; i < fixture->channels(); i++)
2,967✔
452
    {
453
        const QLCChannel *channel(fixture->channel(i));
2,566✔
454
        quint32 addr = fxAddress + i;
2,566✔
455

456
        if (crossUniverse)
2,566✔
457
        {
458
            uni = floor((fixture->universeAddress() + i) / 512);
×
459
            addr = (fixture->universeAddress() + i) - (uni * 512);
×
460
        }
461

462
        // Inform Universe of any HTP/LTP forcing
463
        if (forcedHTP.contains(int(i)))
2,566✔
464
            universes.at(uni)->setChannelCapability(addr, channel->group(), Universe::HTP);
×
465
        else if (forcedLTP.contains(int(i)))
2,566✔
466
            universes.at(uni)->setChannelCapability(addr, channel->group(), Universe::LTP);
1✔
467
        else
468
            universes.at(uni)->setChannelCapability(addr, channel->group());
2,565✔
469

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

473
        // Apply a channel modifier, if defined
474
        ChannelModifier *mod = fixture->channelModifier(i);
2,566✔
475
        universes.at(uni)->setChannelModifier(addr, mod);
2,566✔
476
    }
477
    inputOutputMap()->releaseUniverses(true);
401✔
478

479
    emit fixtureAdded(id);
401✔
480
    setModified();
401✔
481

482
    return true;
401✔
483
}
401✔
484

485
bool Doc::deleteFixture(quint32 id)
16✔
486
{
487
    if (m_fixtures.contains(id) == true)
16✔
488
    {
489
        Fixture* fxi = m_fixtures.take(id);
10✔
490
        Q_ASSERT(fxi != NULL);
10✔
491
        m_fixturesListCacheUpToDate = false;
10✔
492

493
        /* Keep track of fixture addresses */
494
        QMutableHashIterator <uint,uint> it(m_addresses);
10✔
495
        while (it.hasNext() == true)
102✔
496
        {
497
            it.next();
92✔
498
            if (it.value() == id)
92✔
499
                it.remove();
47✔
500
        }
501
        if (m_monitorProps != NULL)
10✔
502
            m_monitorProps->removeFixture(id);
×
503

504
        emit fixtureRemoved(id);
10✔
505
        setModified();
10✔
506
        delete fxi;
10✔
507

508
        if (m_fixtures.count() == 0)
10✔
509
            m_latestFixtureId = 0;
6✔
510

511
        return true;
10✔
512
    }
513
    else
514
    {
515
        qWarning() << Q_FUNC_INFO << "No fixture with id" << id;
6✔
516
        return false;
6✔
517
    }
518
}
519

520
bool Doc::replaceFixtures(QList<Fixture*> newFixturesList)
1✔
521
{
522
    // Delete all fixture instances
523
    QListIterator <quint32> fxit(m_fixtures.keys());
1✔
524
    while (fxit.hasNext() == true)
4✔
525
    {
526
        Fixture* fxi = m_fixtures.take(fxit.next());
3✔
527
        disconnect(fxi, SIGNAL(changed(quint32)),
3✔
528
                   this, SLOT(slotFixtureChanged(quint32)));
529
        delete fxi;
3✔
530
        m_fixturesListCacheUpToDate = false;
3✔
531
    }
532
    m_latestFixtureId = 0;
1✔
533
    m_addresses.clear();
1✔
534

535
    foreach (Fixture *fixture, newFixturesList)
3✔
536
    {
537
        quint32 id = fixture->id();
2✔
538
        // create a copy of the original cause remapping will
539
        // destroy it later
540
        Fixture *newFixture = new Fixture(this);
2✔
541
        newFixture->setID(id);
2✔
542
        newFixture->setName(fixture->name());
2✔
543
        newFixture->setAddress(fixture->address());
2✔
544
        newFixture->setUniverse(fixture->universe());
2✔
545

546
        if (fixture->fixtureDef() == NULL ||
5✔
547
            (fixture->fixtureDef()->manufacturer() == KXMLFixtureGeneric &&
5✔
548
             fixture->fixtureDef()->model() == KXMLFixtureGeneric))
3✔
549
        {
550
            // Generic dimmers just need to know the number of channels
551
            newFixture->setChannels(fixture->channels());
1✔
552
        }
553
        else if (fixture->fixtureDef() == NULL ||
2✔
554
            (fixture->fixtureDef()->manufacturer() == KXMLFixtureGeneric &&
2✔
555
             fixture->fixtureDef()->model() == KXMLFixtureRGBPanel))
1✔
556
        {
557
            // RGB Panels definitions are not cached or shared, so
558
            // let's make a deep copy of them
559
            QLCFixtureDef *fixtureDef = new QLCFixtureDef();
×
560
            *fixtureDef = *fixture->fixtureDef();
×
561
            QLCFixtureMode *mode = new QLCFixtureMode(fixtureDef);
×
562
            *mode = *fixture->fixtureMode();
×
563
            newFixture->setFixtureDefinition(fixtureDef, mode);
×
564
        }
565
        else
566
        {
567
            QLCFixtureDef *def = fixtureDefCache()->fixtureDef(fixture->fixtureDef()->manufacturer(),
2✔
568
                                                               fixture->fixtureDef()->model());
2✔
569
            QLCFixtureMode *mode = NULL;
1✔
570
            if (def != NULL)
1✔
571
                mode = def->mode(fixture->fixtureMode()->name());
1✔
572
            newFixture->setFixtureDefinition(def, mode);
1✔
573
        }
574

575
        newFixture->setExcludeFadeChannels(fixture->excludeFadeChannels());
2✔
576
        newFixture->setForcedHTPChannels(fixture->forcedHTPChannels());
2✔
577
        newFixture->setForcedLTPChannels(fixture->forcedLTPChannels());
2✔
578

579
        for (quint32 s = 0; s < fixture->channels(); s++)
13✔
580
        {
581
            ChannelModifier *chMod = fixture->channelModifier(s);
11✔
582
            if (chMod != NULL)
11✔
583
                newFixture->setChannelModifier(s, chMod);
×
584
        }
585

586
        m_fixtures.insert(id, newFixture);
2✔
587
        m_fixturesListCacheUpToDate = false;
2✔
588

589
        /* Patch fixture change signals thru Doc */
590
        connect(newFixture, SIGNAL(changed(quint32)),
2✔
591
                this, SLOT(slotFixtureChanged(quint32)));
592

593
        /* Keep track of fixture addresses */
594
        for (uint i = newFixture->universeAddress();
2✔
595
             i < newFixture->universeAddress() + newFixture->channels(); i++)
13✔
596
        {
597
            m_addresses[i] = id;
11✔
598
        }
599
        m_latestFixtureId = id;
2✔
600
    }
1✔
601
    return true;
1✔
602
}
1✔
603

604
bool Doc::updateFixtureChannelCapabilities(quint32 id, QList<int> forcedHTP, QList<int> forcedLTP)
2✔
605
{
606
    if (m_fixtures.contains(id) == false)
2✔
607
        return false;
1✔
608

609
    Fixture* fixture = m_fixtures[id];
1✔
610
    // get exclusive access to the universes list
611
    QList<Universe *> universes = inputOutputMap()->claimUniverses();
1✔
612
    Universe *universe = universes.at(fixture->universe());
1✔
613
    quint32 fxAddress = fixture->address();
1✔
614

615
    // Set forced HTP channels
616
    fixture->setForcedHTPChannels(forcedHTP);
1✔
617

618
    // Set forced LTP channels
619
    fixture->setForcedLTPChannels(forcedLTP);
1✔
620

621
    // Update the Fixture Universe with the current channel states
622
    for (quint32 i = 0 ; i < fixture->channels(); i++)
7✔
623
    {
624
        const QLCChannel *channel(fixture->channel(i));
6✔
625

626
        // Inform Universe of any HTP/LTP forcing
627
        if (forcedHTP.contains(int(i)))
6✔
628
            universe->setChannelCapability(fxAddress + i, channel->group(), Universe::HTP);
2✔
629
        else if (forcedLTP.contains(int(i)))
4✔
630
            universe->setChannelCapability(fxAddress + i, channel->group(), Universe::LTP);
1✔
631
        else
632
            universe->setChannelCapability(fxAddress + i, channel->group());
3✔
633

634
        // Apply the default value BEFORE modifiers
635
        universe->setChannelDefaultValue(fxAddress + i, channel->defaultValue());
6✔
636

637
        // Apply a channel modifier, if defined
638
        ChannelModifier *mod = fixture->channelModifier(i);
6✔
639
        universe->setChannelModifier(fxAddress + i, mod);
6✔
640
    }
641

642
    inputOutputMap()->releaseUniverses(true);
1✔
643

644
    return true;
1✔
645
}
1✔
646

647
QList<Fixture*> const& Doc::fixtures() const
71✔
648
{
649
    if (!m_fixturesListCacheUpToDate)
71✔
650
    {
651
        // Sort fixtures by id
652
        QMap <quint32, Fixture*> fixturesMap;
40✔
653
        QHashIterator <quint32, Fixture*> hashIt(m_fixtures);
40✔
654
        while (hashIt.hasNext())
75✔
655
        {
656
            hashIt.next();
35✔
657
            fixturesMap.insert(hashIt.key(), hashIt.value());
35✔
658
        }
659
        const_cast<QList<Fixture*>&>(m_fixturesListCache) = fixturesMap.values();
40✔
660
        const_cast<bool&>(m_fixturesListCacheUpToDate) = true;
40✔
661
    }
40✔
662
    return m_fixturesListCache;
71✔
663
}
664

665
int Doc::fixturesCount() const
×
666
{
667
    return m_fixtures.count();
×
668
}
669

670
Fixture* Doc::fixture(quint32 id) const
796,289✔
671
{
672
    return m_fixtures.value(id, NULL);
796,289✔
673
}
674

675
quint32 Doc::fixtureForAddress(quint32 universeAddress) const
79✔
676
{
677
    return m_addresses.value(universeAddress, Fixture::invalidId());
79✔
678
}
679

680
int Doc::totalPowerConsumption(int& fuzzy) const
4✔
681
{
682
    int totalPowerConsumption = 0;
4✔
683

684
    // Make sure fuzzy starts from zero
685
    fuzzy = 0;
4✔
686

687
    QListIterator <Fixture*> fxit(fixtures());
4✔
688
    while (fxit.hasNext() == true)
14✔
689
    {
690
        Fixture* fxi(fxit.next());
10✔
691
        Q_ASSERT(fxi != NULL);
10✔
692

693
        if (fxi->fixtureMode() != NULL)
10✔
694
        {
695
            QLCPhysical phys = fxi->fixtureMode()->physical();
10✔
696
            if (phys.powerConsumption() > 0)
10✔
697
                totalPowerConsumption += phys.powerConsumption();
7✔
698
            else
699
                fuzzy++;
3✔
700
        }
10✔
701
        else
702
        {
703
            fuzzy++;
×
704
        }
705
    }
706

707
    return totalPowerConsumption;
4✔
708
}
4✔
709

710
void Doc::slotFixtureChanged(quint32 id)
4✔
711
{
712
    /* Keep track of fixture addresses */
713
    Fixture* fxi = fixture(id);
4✔
714

715
    // remove it
716
    QMutableHashIterator <uint,uint> it(m_addresses);
4✔
717
    while (it.hasNext() == true)
67✔
718
    {
719
        it.next();
63✔
720
        if (it.value() == id)
63✔
721
        {
722
            qDebug() << Q_FUNC_INFO << " remove: " << it.key() << " val: " << it.value();
19✔
723
            it.remove();
19✔
724
        }
725
    }
726

727
    for (uint i = fxi->universeAddress(); i < fxi->universeAddress() + fxi->channels(); i++)
23✔
728
    {
729
        /*
730
         * setting new universe and address calls this twice,
731
         * with an tmp wrong address after the first call (old address() + new universe()).
732
         * we only add if the channel is free, to prevent messing up things
733
         */
734
        Q_ASSERT(!m_addresses.contains(i));
19✔
735
        m_addresses[i] = id;
19✔
736
    }
737

738
    setModified();
4✔
739
    emit fixtureChanged(id);
4✔
740
}
4✔
741

742
/*****************************************************************************
743
 * Fixture groups
744
 *****************************************************************************/
745

746
bool Doc::addFixtureGroup(FixtureGroup* grp, quint32 id)
15✔
747
{
748
    Q_ASSERT(grp != NULL);
15✔
749

750
    // No ID given, this method can assign one
751
    if (id == FixtureGroup::invalidId())
15✔
752
        id = createFixtureGroupId();
8✔
753

754
    if (m_fixtureGroups.contains(id) == true || id == FixtureGroup::invalidId())
15✔
755
    {
756
        qWarning() << Q_FUNC_INFO << "a fixture group with ID" << id << "already exists!";
2✔
757
        return false;
2✔
758
    }
759
    else
760
    {
761
        grp->setId(id);
13✔
762
        m_fixtureGroups[id] = grp;
13✔
763

764
        /* Patch fixture group change signals thru Doc */
765
        connect(grp, SIGNAL(changed(quint32)),
13✔
766
                this, SLOT(slotFixtureGroupChanged(quint32)));
767

768
        emit fixtureGroupAdded(id);
13✔
769
        setModified();
13✔
770

771
        return true;
13✔
772
    }
773
}
774

775
bool Doc::deleteFixtureGroup(quint32 id)
4✔
776
{
777
    if (m_fixtureGroups.contains(id) == true)
4✔
778
    {
779
        FixtureGroup* grp = m_fixtureGroups.take(id);
2✔
780
        Q_ASSERT(grp != NULL);
2✔
781

782
        emit fixtureGroupRemoved(id);
2✔
783
        setModified();
2✔
784
        delete grp;
2✔
785

786
        return true;
2✔
787
    }
788
    else
789
    {
790
        qWarning() << Q_FUNC_INFO << "No fixture group with id" << id;
2✔
791
        return false;
2✔
792
    }
793
}
794

795
FixtureGroup* Doc::fixtureGroup(quint32 id) const
45✔
796
{
797
    return m_fixtureGroups.value(id, NULL);
45✔
798
}
799

800
QList <FixtureGroup*> Doc::fixtureGroups() const
34✔
801
{
802
    return m_fixtureGroups.values();
34✔
803
}
804

805
quint32 Doc::createFixtureGroupId()
8✔
806
{
807
    /* This results in an endless loop if there are UINT_MAX-1 fixture groups. That,
808
       however, seems a bit unlikely. Are there even 4294967295-1 fixtures in
809
       total in the whole world? */
810
    while (m_fixtureGroups.contains(m_latestFixtureGroupId) == true ||
20✔
811
           m_latestFixtureGroupId == FixtureGroup::invalidId())
8✔
812
    {
813
        m_latestFixtureGroupId++;
4✔
814
    }
815

816
    return m_latestFixtureGroupId;
8✔
817
}
818

819
void Doc::slotFixtureGroupChanged(quint32 id)
25✔
820
{
821
    setModified();
25✔
822
    emit fixtureGroupChanged(id);
25✔
823
}
25✔
824

825
/*********************************************************************
826
 * Channels groups
827
 *********************************************************************/
828
bool Doc::addChannelsGroup(ChannelsGroup *grp, quint32 id)
4✔
829
{
830
    Q_ASSERT(grp != NULL);
4✔
831

832
    // No ID given, this method can assign one
833
    if (id == ChannelsGroup::invalidId())
4✔
834
        id = createChannelsGroupId();
4✔
835

836
     grp->setId(id);
4✔
837
     m_channelsGroups[id] = grp;
4✔
838
     if (m_orderedGroups.contains(id) == false)
4✔
839
        m_orderedGroups.append(id);
4✔
840

841
     emit channelsGroupAdded(id);
4✔
842
     setModified();
4✔
843

844
     return true;
4✔
845
}
846

847
bool Doc::deleteChannelsGroup(quint32 id)
2✔
848
{
849
    if (m_channelsGroups.contains(id) == true)
2✔
850
    {
851
        ChannelsGroup* grp = m_channelsGroups.take(id);
1✔
852
        Q_ASSERT(grp != NULL);
1✔
853

854
        emit channelsGroupRemoved(id);
1✔
855
        setModified();
1✔
856
        delete grp;
1✔
857

858
        int idx = m_orderedGroups.indexOf(id);
1✔
859
        if (idx != -1)
1✔
860
            m_orderedGroups.takeAt(idx);
1✔
861

862
        return true;
1✔
863
    }
864
    else
865
    {
866
        qWarning() << Q_FUNC_INFO << "No channels group with id" << id;
1✔
867
        return false;
1✔
868
    }
869
}
870

871
bool Doc::moveChannelGroup(quint32 id, int direction)
3✔
872
{
873
    if (direction == 0 || m_orderedGroups.contains(id) == false)
3✔
874
        return false;
1✔
875

876
    int idx = m_orderedGroups.indexOf(id);
2✔
877

878
    if (idx + direction < 0 || idx + direction >= m_orderedGroups.count())
2✔
879
        return false;
1✔
880

881
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
1✔
882
    m_orderedGroups.takeAt(idx);
1✔
883
    m_orderedGroups.insert(idx + direction, id);
1✔
884
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
1✔
885

886
    setModified();
1✔
887
    return true;
1✔
888
}
889

890
ChannelsGroup* Doc::channelsGroup(quint32 id) const
2✔
891
{
892
    return m_channelsGroups.value(id, NULL);
2✔
893
}
894

895
QList <ChannelsGroup*> Doc::channelsGroups() const
15✔
896
{
897
    QList <ChannelsGroup*> orderedList;
15✔
898

899
    for (int i = 0; i < m_orderedGroups.count(); i++)
37✔
900
    {
901
        orderedList.append(m_channelsGroups[m_orderedGroups.at(i)]);
22✔
902
    }
903
    return orderedList;
15✔
UNCOV
904
}
×
905

906
quint32 Doc::createChannelsGroupId()
4✔
907
{
908
    while (m_channelsGroups.contains(m_latestChannelsGroupId) == true ||
10✔
909
           m_latestChannelsGroupId == ChannelsGroup::invalidId())
4✔
910
    {
911
        m_latestChannelsGroupId++;
2✔
912
    }
913

914
    return m_latestChannelsGroupId;
4✔
915
}
916

917
/*********************************************************************
918
 * Palettes
919
 *********************************************************************/
920

921
bool Doc::addPalette(QLCPalette *palette, quint32 id)
2✔
922
{
923
    Q_ASSERT(palette != NULL);
2✔
924

925
    // No ID given, this method can assign one
926
    if (id == QLCPalette::invalidId())
2✔
927
        id = createPaletteId();
2✔
928

929
    if (m_palettes.contains(id) == true || id == QLCPalette::invalidId())
2✔
930
    {
931
        qWarning() << Q_FUNC_INFO << "a palette with ID" << id << "already exists!";
×
932
        return false;
×
933
    }
934
    else
935
    {
936
        palette->setID(id);
2✔
937
        m_palettes[id] = palette;
2✔
938

939
        emit paletteAdded(id);
2✔
940
        setModified();
2✔
941
    }
942

943
    return true;
2✔
944
}
945

946
bool Doc::deletePalette(quint32 id)
3✔
947
{
948
    if (m_palettes.contains(id) == true)
3✔
949
    {
950
        QLCPalette *palette = m_palettes.take(id);
2✔
951
        Q_ASSERT(palette != NULL);
2✔
952

953
        emit paletteRemoved(id);
2✔
954
        setModified();
2✔
955
        delete palette;
2✔
956

957
        return true;
2✔
958
    }
959
    else
960
    {
961
        qWarning() << Q_FUNC_INFO << "No palette with id" << id;
1✔
962
        return false;
1✔
963
    }
964
}
965

966
QLCPalette *Doc::palette(quint32 id) const
2✔
967
{
968
    return m_palettes.value(id, NULL);
2✔
969
}
970

971
QList<QLCPalette *> Doc::palettes() const
8✔
972
{
973
    return m_palettes.values();
8✔
974
}
975

976
quint32 Doc::createPaletteId()
2✔
977
{
978
    while (m_palettes.contains(m_latestPaletteId) == true ||
5✔
979
           m_latestPaletteId == FixtureGroup::invalidId())
2✔
980
    {
981
        m_latestPaletteId++;
1✔
982
    }
983

984
    return m_latestPaletteId;
2✔
985
}
986

987
/*****************************************************************************
988
 * Functions
989
 *****************************************************************************/
990

991
quint32 Doc::createFunctionId()
243✔
992
{
993
    /* This results in an endless loop if there are UINT_MAX-1 functions. That,
994
       however, seems a bit unlikely. Are there even 4294967295-1 functions in
995
       total in the whole world? */
996
    while (m_functions.contains(m_latestFunctionId) == true ||
653✔
997
           m_latestFunctionId == Fixture::invalidId())
243✔
998
    {
999
        m_latestFunctionId++;
167✔
1000
    }
1001

1002
    return m_latestFunctionId;
243✔
1003
}
1004

1005
bool Doc::addFunction(Function* func, quint32 id)
256✔
1006
{
1007
    Q_ASSERT(func != NULL);
256✔
1008

1009
    if (id == Function::invalidId())
256✔
1010
        id = createFunctionId();
243✔
1011

1012
    if (m_functions.contains(id) == true || id == Fixture::invalidId())
256✔
1013
    {
1014
        qWarning() << Q_FUNC_INFO << "a function with ID" << id << "already exists!";
2✔
1015
        return false;
2✔
1016
    }
1017
    else
1018
    {
1019
        // Listen to function changes
1020
        connect(func, SIGNAL(changed(quint32)),
254✔
1021
                this, SLOT(slotFunctionChanged(quint32)));
1022

1023
        // Listen to function name changes
1024
        connect(func, SIGNAL(nameChanged(quint32)),
254✔
1025
                this, SLOT(slotFunctionNameChanged(quint32)));
1026

1027
        // Make the function listen to fixture removals
1028
        connect(this, SIGNAL(fixtureRemoved(quint32)),
254✔
1029
                func, SLOT(slotFixtureRemoved(quint32)));
1030

1031
        // Place the function in the map and assign it the new ID
1032
        m_functions[id] = func;
254✔
1033
        func->setID(id);
254✔
1034
        emit functionAdded(id);
254✔
1035
        setModified();
254✔
1036

1037
        return true;
254✔
1038
    }
1039
}
1040

1041
QList <Function*> Doc::functions() const
49✔
1042
{
1043
    return m_functions.values();
49✔
1044
}
1045

1046
QList<Function *> Doc::functionsByType(Function::Type type) const
1✔
1047
{
1048
    QList <Function*> list;
1✔
1049
    foreach (Function *f, m_functions)
10✔
1050
    {
1051
        if (f != NULL && f->type() == type)
9✔
1052
            list.append(f);
5✔
1053
    }
1✔
1054
    return list;
1✔
UNCOV
1055
}
×
1056

1057
Function *Doc::functionByName(QString name)
×
1058
{
1059
    foreach (Function *f, m_functions)
×
1060
    {
1061
        if (f != NULL && f->name() == name)
×
UNCOV
1062
            return f;
×
UNCOV
1063
    }
×
1064
    return NULL;
×
1065
}
1066

1067
bool Doc::deleteFunction(quint32 id)
10✔
1068
{
1069
    if (m_functions.contains(id) == true)
10✔
1070
    {
1071
        Function* func = m_functions.take(id);
8✔
1072
        Q_ASSERT(func != NULL);
8✔
1073

1074
        if (m_startupFunctionId == id)
8✔
1075
            m_startupFunctionId = Function::invalidId();
×
1076

1077
        emit functionRemoved(id);
8✔
1078
        setModified();
8✔
1079
        delete func;
8✔
1080

1081
        return true;
8✔
1082
    }
1083
    else
1084
    {
1085
        qWarning() << Q_FUNC_INFO << "No function with id" << id;
2✔
1086
        return false;
2✔
1087
    }
1088
}
1089

1090
Function* Doc::function(quint32 id) const
884✔
1091
{
1092
    return m_functions.value(id, NULL);
884✔
1093
}
1094

1095
quint32 Doc::nextFunctionID()
2✔
1096
{
1097
    quint32 tmpFID = m_latestFunctionId;
2✔
1098
    while (m_functions.contains(tmpFID) == true ||
5✔
1099
           tmpFID == Fixture::invalidId())
2✔
1100
    {
1101
        tmpFID++;
1✔
1102
    }
1103

1104
    return tmpFID;
2✔
1105
}
1106

1107
void Doc::setStartupFunction(quint32 fid)
1✔
1108
{
1109
    m_startupFunctionId = fid;
1✔
1110
}
1✔
1111

1112
quint32 Doc::startupFunction()
3✔
1113
{
1114
    return m_startupFunctionId;
3✔
1115
}
1116

1117
QList<quint32> Doc::getUsage(quint32 fid)
7✔
1118
{
1119
    QList<quint32> usageList;
7✔
1120

1121
    foreach (Function *f, m_functions)
70✔
1122
    {
1123
        if (f->id() == fid)
63✔
1124
            continue;
6✔
1125

1126
        switch(f->type())
57✔
1127
        {
1128
            case Function::CollectionType:
7✔
1129
            {
1130
                Collection *c = qobject_cast<Collection *>(f);
7✔
1131
                int pos = c->functions().indexOf(fid);
7✔
1132
                if (pos != -1)
7✔
1133
                {
1134
                    usageList.append(f->id());
2✔
1135
                    usageList.append(pos);
2✔
1136
                }
1137
            }
1138
            break;
7✔
1139
            case Function::ChaserType:
6✔
1140

1141
            {
1142
                Chaser *c = qobject_cast<Chaser *>(f);
6✔
1143
                for (int i = 0; i < c->stepsCount(); i++)
18✔
1144
                {
1145
                    ChaserStep *cs = c->stepAt(i);
12✔
1146
                    if (cs->fid == fid)
12✔
1147
                    {
1148
                        usageList.append(f->id());
2✔
1149
                        usageList.append(i);
2✔
1150
                    }
1151
                }
1152
            }
1153
            break;
6✔
1154
            case Function::SequenceType:
7✔
1155
            {
1156
                Sequence *s = qobject_cast<Sequence *>(f);
7✔
1157
                if (s->boundSceneID() == fid)
7✔
1158
                {
1159
                    usageList.append(f->id());
1✔
1160
                    usageList.append(0);
1✔
1161
                }
1162
            }
1163
            break;
7✔
1164
            case Function::ScriptType:
7✔
1165
            {
1166
                Script *s = qobject_cast<Script *>(f);
7✔
1167
                QList<quint32> l = s->functionList();
7✔
1168
                for (int i = 0; i < l.count(); i+=2)
14✔
1169
                {
1170
                    if (l.at(i) == fid)
7✔
1171
                    {
1172
                        if (i + 1 >= l.count()) {
1✔
1173
                            qDebug() << "Doc::getUsage: Index entry missing on " << f->name();
×
1174
                            break;
×
1175
                        }
1176
                        usageList.append(s->id());
1✔
1177
                        usageList.append(l.at(i + 1)); // line number
1✔
1178
                    }
1179
                }
1180
            }
7✔
1181
            break;
7✔
UNCOV
1182
            case Function::ShowType:
×
1183
            {
UNCOV
1184
                Show *s = qobject_cast<Show *>(f);
×
1185
                foreach (Track *t, s->tracks())
×
1186
                {
1187
                    foreach (ShowFunction *sf, t->showFunctions())
×
1188
                    {
1189
                        if (sf->functionID() == fid)
×
1190
                        {
1191
                            usageList.append(f->id());
×
1192
                            usageList.append(t->id());
×
1193
                        }
UNCOV
1194
                    }
×
UNCOV
1195
                }
×
1196
            }
1197
            break;
×
1198
            default:
30✔
1199
            break;
30✔
1200
        }
1201
    }
7✔
1202

1203
    return usageList;
7✔
UNCOV
1204
}
×
1205

1206
void Doc::slotFunctionChanged(quint32 fid)
111✔
1207
{
1208
    setModified();
111✔
1209
    emit functionChanged(fid);
111✔
1210
}
111✔
1211

1212
void Doc::slotFunctionNameChanged(quint32 fid)
2✔
1213
{
1214
    setModified();
2✔
1215
    emit functionNameChanged(fid);
2✔
1216
}
2✔
1217

1218
/*********************************************************************
1219
 * Monitor Properties
1220
 *********************************************************************/
1221

1222
MonitorProperties *Doc::monitorProperties()
1✔
1223
{
1224
    if (m_monitorProps == NULL)
1✔
1225
        m_monitorProps = new MonitorProperties();
1✔
1226

1227
    return m_monitorProps;
1✔
1228
}
1229

1230
/*****************************************************************************
1231
 * Load & Save
1232
 *****************************************************************************/
1233

1234
bool Doc::loadXML(QXmlStreamReader &doc, bool loadIO)
2✔
1235
{
1236
    clearErrorLog();
2✔
1237

1238
    if (doc.name() != KXMLQLCEngine)
2✔
1239
    {
1240
        qWarning() << Q_FUNC_INFO << "Engine node not found";
1✔
1241
        return false;
1✔
1242
    }
1243

1244
    m_loadStatus = Loading;
1✔
1245
    emit loading();
1✔
1246

1247
    if (doc.attributes().hasAttribute(KXMLQLCStartupFunction))
2✔
1248
    {
1249
        quint32 sID = doc.attributes().value(KXMLQLCStartupFunction).toString().toUInt();
×
1250
        if (sID != Function::invalidId())
×
1251
            setStartupFunction(sID);
×
1252
    }
1253

1254
    while (doc.readNextStartElement())
17✔
1255
    {
1256
        //qDebug() << "Doc tag:" << doc.name();
1257
        if (doc.name() == KXMLFixture)
16✔
1258
        {
1259
            Fixture::loader(doc, this);
3✔
1260
        }
1261
        else if (doc.name() == KXMLQLCFixtureGroup)
13✔
1262
        {
1263
            FixtureGroup::loader(doc, this);
3✔
1264
        }
1265
        else if (doc.name() == KXMLQLCChannelsGroup)
10✔
1266
        {
1267
            ChannelsGroup::loader(doc, this);
×
1268
        }
1269
        else if (doc.name() == KXMLQLCPalette)
10✔
1270
        {
1271
            QLCPalette::loader(doc, this);
×
1272
            doc.skipCurrentElement();
×
1273
        }
1274
        else if (doc.name() == KXMLQLCFunction)
10✔
1275
        {
1276
            //qDebug() << doc.attributes().value("Name").toString();
1277
            Function::loader(doc, this);
4✔
1278
        }
1279
        else if (doc.name() == KXMLQLCBus)
6✔
1280
        {
1281
            /* LEGACY */
1282
            Bus::instance()->loadXML(doc);
5✔
1283
        }
1284
        else if (doc.name() == KXMLIOMap && loadIO)
2✔
1285
        {
1286
            m_ioMap->loadXML(doc);
×
1287
        }
1288
        else if (doc.name() == KXMLQLCMonitorProperties)
1✔
1289
        {
1290
            monitorProperties()->loadXML(doc, this);
×
1291
        }
1292
        else
1293
        {
1294
            qWarning() << Q_FUNC_INFO << "Unknown engine tag:" << doc.name();
1✔
1295
            doc.skipCurrentElement();
1✔
1296
        }
1297
    }
1298

1299
    postLoad();
1✔
1300

1301
    m_loadStatus = Loaded;
1✔
1302
    emit loaded();
1✔
1303

1304
    return true;
1✔
1305
}
1306

1307
bool Doc::saveXML(QXmlStreamWriter *doc)
1✔
1308
{
1309
    Q_ASSERT(doc != NULL);
1✔
1310

1311
    /* Create the master Engine node */
1312
    doc->writeStartElement(KXMLQLCEngine);
2✔
1313

1314
    if (startupFunction() != Function::invalidId())
1✔
1315
        doc->writeAttribute(KXMLQLCStartupFunction, QString::number(startupFunction()));
2✔
1316

1317
    m_ioMap->saveXML(doc);
1✔
1318

1319
    /* Write fixtures into an XML document */
1320
    QListIterator <Fixture*> fxit(fixtures());
1✔
1321
    while (fxit.hasNext() == true)
4✔
1322
    {
1323
        Fixture *fxi(fxit.next());
3✔
1324
        Q_ASSERT(fxi != NULL);
3✔
1325
        fxi->saveXML(doc);
3✔
1326
    }
1327

1328
    /* Write fixture groups into an XML document */
1329
    QListIterator <FixtureGroup*> grpit(fixtureGroups());
1✔
1330
    while (grpit.hasNext() == true)
3✔
1331
    {
1332
        FixtureGroup *grp(grpit.next());
2✔
1333
        Q_ASSERT(grp != NULL);
2✔
1334
        grp->saveXML(doc);
2✔
1335
    }
1336

1337
    /* Write channel groups into an XML document */
1338
    QListIterator <ChannelsGroup*> chanGroups(channelsGroups());
1✔
1339
    while (chanGroups.hasNext() == true)
1✔
1340
    {
1341
        ChannelsGroup *grp(chanGroups.next());
×
UNCOV
1342
        Q_ASSERT(grp != NULL);
×
1343
        grp->saveXML(doc);
×
1344
    }
1345

1346
    /* Write palettes into an XML document */
1347
    QListIterator <QLCPalette*> paletteIt(palettes());
1✔
1348
    while (paletteIt.hasNext() == true)
1✔
1349
    {
1350
        QLCPalette *palette(paletteIt.next());
×
UNCOV
1351
        Q_ASSERT(palette != NULL);
×
1352
        palette->saveXML(doc);
×
1353
    }
1354

1355
    /* Write functions into an XML document */
1356
    QListIterator <Function*> funcit(functions());
1✔
1357
    while (funcit.hasNext() == true)
5✔
1358
    {
1359
        Function *func(funcit.next());
4✔
1360
        Q_ASSERT(func != NULL);
4✔
1361
        func->saveXML(doc);
4✔
1362
    }
1363

1364
    if (m_monitorProps != NULL)
1✔
1365
        m_monitorProps->saveXML(doc, this);
1✔
1366

1367
    /* End the <Engine> tag */
1368
    doc->writeEndElement();
1✔
1369

1370
    return true;
1✔
1371
}
1✔
1372

1373
void Doc::appendToErrorLog(QString error)
8✔
1374
{
1375
    if (m_errorLog.contains(error))
8✔
1376
        return;
5✔
1377

1378
    m_errorLog.append(error);
3✔
1379
    m_errorLog.append("<br>");
3✔
1380
}
1381

1382
void Doc::clearErrorLog()
2✔
1383
{
1384
    m_errorLog = "";
2✔
1385
}
2✔
1386

1387
QString Doc::errorLog()
1✔
1388
{
1389
    return m_errorLog;
1✔
1390
}
1391

1392
void Doc::postLoad()
1✔
1393
{
1394
    QListIterator <Function*> functionit(functions());
1✔
1395
    while (functionit.hasNext() == true)
5✔
1396
    {
1397
        Function* function(functionit.next());
4✔
1398
        Q_ASSERT(function != NULL);
4✔
1399
        function->postLoad();
4✔
1400
    }
1401
}
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