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

mcallegari / qlcplus / 6618760541

23 Oct 2023 08:37PM UTC coverage: 28.075% (+0.04%) from 28.038%
6618760541

Pull #1462

github

web-flow
Merge f29f91b17 into 646f68840
Pull Request #1462: Overriding flash functionality

56 of 56 new or added lines in 6 files covered. (100.0%)

15368 of 54740 relevant lines covered (28.07%)

20323.53 hits per line

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

90.69
/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
#include "qlcfile.h"
36

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

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

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

101
Doc::~Doc()
308✔
102
{
103
    delete m_masterTimer;
174✔
104
    m_masterTimer = NULL;
174✔
105

106
    clearContents();
174✔
107

108
    if (isKiosk() == false)
174✔
109
    {
110
        // TODO: is this still needed ??
111
        //m_ioMap->saveDefaults();
112
    }
113
    delete m_ioMap;
174✔
114
    m_ioMap = NULL;
174✔
115

116
    delete m_ioPluginCache;
174✔
117
    m_ioPluginCache = NULL;
174✔
118

119
    delete m_modifiersCache;
174✔
120
    m_modifiersCache = NULL;
174✔
121

122
    delete m_fixtureDefCache;
174✔
123
    m_fixtureDefCache = NULL;
174✔
124
}
308✔
125

126
void Doc::clearContents()
447✔
127
{
128
    emit clearing();
447✔
129

130
    m_clipboard->resetContents();
447✔
131

132
    if (m_monitorProps != NULL)
447✔
133
        m_monitorProps->reset();
9✔
134

135
    destroyAudioCapture();
447✔
136

137
    // Delete all function instances
138
    QListIterator <quint32> funcit(m_functions.keys());
1,341✔
139
    while (funcit.hasNext() == true)
685✔
140
    {
141
        Function* func = m_functions.take(funcit.next());
238✔
142
        if (func == NULL)
238✔
143
            continue;
×
144
        emit functionRemoved(func->id());
238✔
145
        delete func;
238✔
146
    }
147

148
    // Delete all palettes
149
    QListIterator <quint32> palIt(m_palettes.keys());
1,341✔
150
    while (palIt.hasNext() == true)
447✔
151
    {
152
        QLCPalette *palette = m_palettes.take(palIt.next());
×
153
        emit paletteRemoved(palette->id());
×
154
        delete palette;
×
155
    }
156

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

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

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

187
    m_orderedGroups.clear();
447✔
188

189
    m_latestFunctionId = 0;
447✔
190
    m_latestFixtureId = 0;
447✔
191
    m_latestFixtureGroupId = 0;
447✔
192
    m_latestChannelsGroupId = 0;
447✔
193
    m_latestPaletteId = 0;
447✔
194
    m_addresses.clear();
447✔
195
    m_loadStatus = Cleared;
447✔
196

197
    emit cleared();
447✔
198
}
447✔
199

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

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

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

215
    QFileInfo f(filePath);
12✔
216

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

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

232
    return QFileInfo(QDir(getWorkspacePath()), filePath).absoluteFilePath();
12✔
233
}
234

235
/*****************************************************************************
236
 * Engine components
237
 *****************************************************************************/
238

239
QLCFixtureDefCache* Doc::fixtureDefCache() const
1,581✔
240
{
241
    return m_fixtureDefCache;
1,581✔
242
}
243

244
void Doc::setFixtureDefinitionCache(QLCFixtureDefCache *cache)
×
245
{
246
    m_fixtureDefCache = cache;
×
247
}
×
248

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

254
RGBScriptsCache* Doc::rgbScriptsCache() const
68✔
255
{
256
    return m_rgbScriptsCache;
68✔
257
}
258

259
IOPluginCache* Doc::ioPluginCache() const
285✔
260
{
261
    return m_ioPluginCache;
285✔
262
}
263

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

269
InputOutputMap* Doc::inputOutputMap() const
2,598✔
270
{
271
    return m_ioMap;
2,598✔
272
}
273

274
MasterTimer* Doc::masterTimer() const
1,087✔
275
{
276
    return m_masterTimer;
1,087✔
277
}
278

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

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

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

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

325
void Doc::setModified()
1,233✔
326
{
327
    m_modified = true;
1,233✔
328
    emit modified(true);
1,233✔
329
}
1,233✔
330

331
void Doc::resetModified()
189✔
332
{
333
    m_modified = false;
189✔
334
    emit modified(false);
189✔
335
}
189✔
336

337
/*****************************************************************************
338
 * Main operating mode
339
 *****************************************************************************/
340

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

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

364
    emit modeChanged(m_mode);
21✔
365
}
366

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

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

377
bool Doc::isKiosk() const
176✔
378
{
379
    return m_kiosk;
176✔
380
}
381

382
/*********************************************************************
383
 * Clipboard
384
 *********************************************************************/
385

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

391
/*****************************************************************************
392
 * Fixtures
393
 *****************************************************************************/
394

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

406
    return m_latestFixtureId;
16,780✔
407
}
408

409
bool Doc::addFixture(Fixture* fixture, quint32 id)
405✔
410
{
411
    Q_ASSERT(fixture != NULL);
405✔
412

413
    quint32 i;
414
    quint32 uni = fixture->universe();
405✔
415

416
    // No ID given, this method can assign one
417
    if (id == Fixture::invalidId())
405✔
418
        id = createFixtureId();
396✔
419

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

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

437
    fixture->setID(id);
400✔
438
    m_fixtures.insert(id, fixture);
400✔
439
    m_fixturesListCacheUpToDate = false;
400✔
440

441
    /* Patch fixture change signals thru Doc */
442
    connect(fixture, SIGNAL(changed(quint32)),
400✔
443
            this, SLOT(slotFixtureChanged(quint32)));
444

445
    /* Keep track of fixture addresses */
446
    for (i = fixture->universeAddress();
400✔
447
         i < fixture->universeAddress() + fixture->channels(); i++)
2,950✔
448
    {
449
        m_addresses[i] = id;
2,550✔
450
    }
451

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

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

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

466
    for (i = 0; i < fixture->channels(); i++)
2,950✔
467
    {
468
        const QLCChannel *channel(fixture->channel(i));
2,550✔
469

470
        // Inform Universe of any HTP/LTP forcing
471
        if (forcedHTP.contains(int(i)))
2,550✔
472
            universes.at(uni)->setChannelCapability(fxAddress + i, channel->group(), Universe::HTP);
×
473
        else if (forcedLTP.contains(int(i)))
2,550✔
474
            universes.at(uni)->setChannelCapability(fxAddress + i, channel->group(), Universe::LTP);
1✔
475
        else
476
            universes.at(uni)->setChannelCapability(fxAddress + i, channel->group());
2,549✔
477

478
        // Apply the default value BEFORE modifiers
479
        universes.at(uni)->setChannelDefaultValue(fxAddress + i, channel->defaultValue());
2,550✔
480

481
        // Apply a channel modifier, if defined
482
        ChannelModifier *mod = fixture->channelModifier(i);
2,550✔
483
        universes.at(uni)->setChannelModifier(fxAddress + i, mod);
2,550✔
484
    }
485
    inputOutputMap()->releaseUniverses(true);
400✔
486

487
    emit fixtureAdded(id);
400✔
488
    setModified();
400✔
489

490
    return true;
400✔
491
}
492

493
bool Doc::deleteFixture(quint32 id)
16✔
494
{
495
    if (m_fixtures.contains(id) == true)
16✔
496
    {
497
        Fixture* fxi = m_fixtures.take(id);
10✔
498
        Q_ASSERT(fxi != NULL);
10✔
499
        m_fixturesListCacheUpToDate = false;
10✔
500

501
        /* Keep track of fixture addresses */
502
        QMutableHashIterator <uint,uint> it(m_addresses);
10✔
503
        while (it.hasNext() == true)
102✔
504
        {
505
            it.next();
92✔
506
            if (it.value() == id)
92✔
507
                it.remove();
47✔
508
        }
509
        if (m_monitorProps != NULL)
10✔
510
            m_monitorProps->removeFixture(id);
×
511

512
        emit fixtureRemoved(id);
10✔
513
        setModified();
10✔
514
        delete fxi;
10✔
515

516
        if (m_fixtures.count() == 0)
10✔
517
            m_latestFixtureId = 0;
6✔
518

519
        return true;
10✔
520
    }
521
    else
522
    {
523
        qWarning() << Q_FUNC_INFO << "No fixture with id" << id;
6✔
524
        return false;
6✔
525
    }
526
}
527

528
bool Doc::replaceFixtures(QList<Fixture*> newFixturesList)
1✔
529
{
530
    // Delete all fixture instances
531
    QListIterator <quint32> fxit(m_fixtures.keys());
2✔
532
    while (fxit.hasNext() == true)
4✔
533
    {
534
        Fixture* fxi = m_fixtures.take(fxit.next());
3✔
535
        disconnect(fxi, SIGNAL(changed(quint32)),
3✔
536
                   this, SLOT(slotFixtureChanged(quint32)));
537
        delete fxi;
3✔
538
        m_fixturesListCacheUpToDate = false;
3✔
539
    }
540
    m_latestFixtureId = 0;
1✔
541
    m_addresses.clear();
1✔
542

543
    foreach(Fixture *fixture, newFixturesList)
5✔
544
    {
545
        quint32 id = fixture->id();
2✔
546
        // create a copy of the original cause remapping will
547
        // destroy it later
548
        Fixture *newFixture = new Fixture(this);
2✔
549
        newFixture->setID(id);
2✔
550
        newFixture->setName(fixture->name());
2✔
551
        newFixture->setAddress(fixture->address());
2✔
552
        newFixture->setUniverse(fixture->universe());
2✔
553

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

583
        newFixture->setExcludeFadeChannels(fixture->excludeFadeChannels());
2✔
584
        newFixture->setForcedHTPChannels(fixture->forcedHTPChannels());
2✔
585
        newFixture->setForcedLTPChannels(fixture->forcedLTPChannels());
2✔
586

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

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

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

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

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

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

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

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

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

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

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

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

645
    return true;
1✔
646
}
647

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

666
Fixture* Doc::fixture(quint32 id) const
796,448✔
667
{
668
    return m_fixtures.value(id, NULL);
796,448✔
669
}
670

671
quint32 Doc::fixtureForAddress(quint32 universeAddress) const
80✔
672
{
673
    return m_addresses.value(universeAddress, Fixture::invalidId());
80✔
674
}
675

676
int Doc::totalPowerConsumption(int& fuzzy) const
4✔
677
{
678
    int totalPowerConsumption = 0;
4✔
679

680
    // Make sure fuzzy starts from zero
681
    fuzzy = 0;
4✔
682

683
    QListIterator <Fixture*> fxit(fixtures());
4✔
684
    while (fxit.hasNext() == true)
14✔
685
    {
686
        Fixture* fxi(fxit.next());
10✔
687
        Q_ASSERT(fxi != NULL);
10✔
688

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

703
    return totalPowerConsumption;
8✔
704
}
705

706
void Doc::slotFixtureChanged(quint32 id)
4✔
707
{
708
    /* Keep track of fixture addresses */
709
    Fixture* fxi = fixture(id);
4✔
710

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

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

734
    setModified();
4✔
735
    emit fixtureChanged(id);
4✔
736
}
4✔
737

738
/*****************************************************************************
739
 * Fixture groups
740
 *****************************************************************************/
741

742
bool Doc::addFixtureGroup(FixtureGroup* grp, quint32 id)
15✔
743
{
744
    Q_ASSERT(grp != NULL);
15✔
745

746
    // No ID given, this method can assign one
747
    if (id == FixtureGroup::invalidId())
15✔
748
        id = createFixtureGroupId();
8✔
749

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

760
        /* Patch fixture group change signals thru Doc */
761
        connect(grp, SIGNAL(changed(quint32)),
13✔
762
                this, SLOT(slotFixtureGroupChanged(quint32)));
763

764
        emit fixtureGroupAdded(id);
13✔
765
        setModified();
13✔
766

767
        return true;
13✔
768
    }
769
}
770

771
bool Doc::deleteFixtureGroup(quint32 id)
4✔
772
{
773
    if (m_fixtureGroups.contains(id) == true)
4✔
774
    {
775
        FixtureGroup* grp = m_fixtureGroups.take(id);
2✔
776
        Q_ASSERT(grp != NULL);
2✔
777

778
        emit fixtureGroupRemoved(id);
2✔
779
        setModified();
2✔
780
        delete grp;
2✔
781

782
        return true;
2✔
783
    }
784
    else
785
    {
786
        qWarning() << Q_FUNC_INFO << "No fixture group with id" << id;
2✔
787
        return false;
2✔
788
    }
789
}
790

791
FixtureGroup* Doc::fixtureGroup(quint32 id) const
47✔
792
{
793
    if (m_fixtureGroups.contains(id) == true)
47✔
794
        return m_fixtureGroups[id];
21✔
795
    else
796
        return NULL;
26✔
797
}
798

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

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

815
    return m_latestFixtureGroupId;
8✔
816
}
817

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

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

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

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

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

843
     return true;
4✔
844
}
845

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

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

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

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

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

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

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

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

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

889
ChannelsGroup* Doc::channelsGroup(quint32 id) const
2✔
890
{
891
    if (m_channelsGroups.contains(id) == true)
2✔
892
        return m_channelsGroups[id];
1✔
893
    else
894
        return NULL;
1✔
895
}
896

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

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

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

916
    return m_latestChannelsGroupId;
4✔
917
}
918

919
/*********************************************************************
920
 * Palettes
921
 *********************************************************************/
922

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

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

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

941
        emit paletteAdded(id);
2✔
942
        setModified();
2✔
943
    }
944

945
    return true;
2✔
946
}
947

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

955
        emit paletteRemoved(id);
2✔
956
        setModified();
2✔
957
        delete palette;
2✔
958

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

968
QLCPalette *Doc::palette(quint32 id) const
2✔
969
{
970
    if (m_palettes.contains(id) == true)
2✔
971
        return m_palettes[id];
1✔
972
    else
973
        return NULL;
1✔
974
}
975

976
QList<QLCPalette *> Doc::palettes() const
8✔
977
{
978
    return m_palettes.values();
8✔
979
}
980

981
quint32 Doc::createPaletteId()
3✔
982
{
983
    while (m_palettes.contains(m_latestPaletteId) == true ||
5✔
984
           m_latestPaletteId == FixtureGroup::invalidId())
2✔
985
    {
986
        m_latestPaletteId++;
1✔
987
    }
988

989
    return m_latestPaletteId;
2✔
990
}
991

992
/*****************************************************************************
993
 * Functions
994
 *****************************************************************************/
995

996
quint32 Doc::createFunctionId()
400✔
997
{
998
    /* This results in an endless loop if there are UINT_MAX-1 functions. That,
999
       however, seems a bit unlikely. Are there even 4294967295-1 functions in
1000
       total in the whole world? */
1001
    while (m_functions.contains(m_latestFunctionId) == true ||
637✔
1002
           m_latestFunctionId == Fixture::invalidId())
237✔
1003
    {
1004
        m_latestFunctionId++;
163✔
1005
    }
1006

1007
    return m_latestFunctionId;
237✔
1008
}
1009

1010
bool Doc::addFunction(Function* func, quint32 id)
248✔
1011
{
1012
    Q_ASSERT(func != NULL);
248✔
1013

1014
    if (id == Function::invalidId())
248✔
1015
        id = createFunctionId();
237✔
1016

1017
    if (m_functions.contains(id) == true || id == Fixture::invalidId())
248✔
1018
    {
1019
        qWarning() << Q_FUNC_INFO << "a function with ID" << id << "already exists!";
2✔
1020
        return false;
2✔
1021
    }
1022
    else
1023
    {
1024
        // Listen to function changes
1025
        connect(func, SIGNAL(changed(quint32)),
246✔
1026
                this, SLOT(slotFunctionChanged(quint32)));
1027

1028
        // Listen to function name changes
1029
        connect(func, SIGNAL(nameChanged(quint32)),
246✔
1030
                this, SLOT(slotFunctionNameChanged(quint32)));
1031

1032
        // Make the function listen to fixture removals
1033
        connect(this, SIGNAL(fixtureRemoved(quint32)),
246✔
1034
                func, SLOT(slotFixtureRemoved(quint32)));
1035

1036
        // Place the function in the map and assign it the new ID
1037
        m_functions[id] = func;
246✔
1038
        func->setID(id);
246✔
1039
        emit functionAdded(id);
246✔
1040
        setModified();
246✔
1041

1042
        return true;
246✔
1043
    }
1044
}
1045

1046
QList <Function*> Doc::functions() const
49✔
1047
{
1048
    return m_functions.values();
49✔
1049
}
1050

1051
QList<Function *> Doc::functionsByType(Function::Type type) const
1✔
1052
{
1053
    QList <Function*> list;
1✔
1054
    foreach(Function *f, m_functions)
19✔
1055
    {
1056
        if (f != NULL && f->type() == type)
9✔
1057
            list.append(f);
5✔
1058
    }
1059
    return list;
1✔
1060
}
1061

1062
Function *Doc::functionByName(QString name)
×
1063
{
1064
    foreach(Function *f, m_functions)
×
1065
    {
1066
        if (f != NULL && f->name() == name)
×
1067
            return f;
×
1068
    }
1069
    return NULL;
×
1070
}
1071

1072
bool Doc::deleteFunction(quint32 id)
10✔
1073
{
1074
    if (m_functions.contains(id) == true)
10✔
1075
    {
1076
        Function* func = m_functions.take(id);
8✔
1077
        Q_ASSERT(func != NULL);
8✔
1078

1079
        if (m_startupFunctionId == id)
8✔
1080
            m_startupFunctionId = Function::invalidId();
×
1081

1082
        emit functionRemoved(id);
8✔
1083
        setModified();
8✔
1084
        delete func;
8✔
1085

1086
        return true;
8✔
1087
    }
1088
    else
1089
    {
1090
        qWarning() << Q_FUNC_INFO << "No function with id" << id;
2✔
1091
        return false;
2✔
1092
    }
1093
}
1094

1095
Function* Doc::function(quint32 id) const
867✔
1096
{
1097
    if (m_functions.contains(id) == true)
867✔
1098
        return m_functions[id];
805✔
1099
    else
1100
        return NULL;
62✔
1101
}
1102

1103
quint32 Doc::nextFunctionID()
2✔
1104
{
1105
    quint32 tmpFID = m_latestFunctionId;
2✔
1106
    while (m_functions.contains(tmpFID) == true ||
5✔
1107
           tmpFID == Fixture::invalidId())
2✔
1108
    {
1109
        tmpFID++;
1✔
1110
    }
1111

1112
    return tmpFID;
2✔
1113
}
1114

1115
void Doc::setStartupFunction(quint32 fid)
1✔
1116
{
1117
    m_startupFunctionId = fid;
1✔
1118
}
1✔
1119

1120
quint32 Doc::startupFunction()
3✔
1121
{
1122
    return m_startupFunctionId;
3✔
1123
}
1124

1125
QList<quint32> Doc::getUsage(quint32 fid)
7✔
1126
{
1127
    QList<quint32> usageList;
7✔
1128

1129
    foreach (Function *f, m_functions)
133✔
1130
    {
1131
        if (f->id() == fid)
63✔
1132
            continue;
6✔
1133

1134
        switch(f->type())
57✔
1135
        {
1136
            case Function::CollectionType:
7✔
1137
            {
1138
                Collection *c = qobject_cast<Collection *>(f);
7✔
1139
                int pos = c->functions().indexOf(fid);
7✔
1140
                if (pos != -1)
7✔
1141
                {
1142
                    usageList.append(f->id());
2✔
1143
                    usageList.append(pos);
2✔
1144
                }
1145
            }
1146
            break;
7✔
1147
            case Function::ChaserType:
6✔
1148

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

1211
    return usageList;
7✔
1212
}
1213

1214
void Doc::slotFunctionChanged(quint32 fid)
109✔
1215
{
1216
    setModified();
109✔
1217
    emit functionChanged(fid);
109✔
1218
}
109✔
1219

1220
void Doc::slotFunctionNameChanged(quint32 fid)
1✔
1221
{
1222
    setModified();
1✔
1223
    emit functionNameChanged(fid);
1✔
1224
}
1✔
1225

1226
/*********************************************************************
1227
 * Monitor Properties
1228
 *********************************************************************/
1229

1230
MonitorProperties *Doc::monitorProperties()
1✔
1231
{
1232
    if (m_monitorProps == NULL)
1✔
1233
        m_monitorProps = new MonitorProperties();
1✔
1234

1235
    return m_monitorProps;
1✔
1236
}
1237

1238
/*********************************************************************
1239
 * Flash Properties
1240
 *********************************************************************/
1241
bool Doc::flashOverrides() const
1✔
1242
{
1243
    return m_flashOverrides;
1✔
1244
}
1245

1246
void Doc::setFlashOverrides(bool overrides)
×
1247
{
1248
    m_flashOverrides = overrides;
×
1249
}
×
1250

1251
bool Doc::flashForceLTP() const
3✔
1252
{
1253
    return m_flashForceLTP;
3✔
1254
}
1255

1256
void Doc::setFlashForceLTP(bool forceLTP) 
×
1257
{
1258
    m_flashForceLTP = forceLTP;
×
1259
}
×
1260

1261

1262
/*****************************************************************************
1263
 * Load & Save
1264
 *****************************************************************************/
1265

1266
bool Doc::loadXML(QXmlStreamReader &doc, bool loadIO)
2✔
1267
{
1268
    clearErrorLog();
2✔
1269

1270
    if (doc.name() != KXMLQLCEngine)
2✔
1271
    {
1272
        qWarning() << Q_FUNC_INFO << "Engine node not found";
1✔
1273
        return false;
1✔
1274
    }
1275

1276
    m_loadStatus = Loading;
1✔
1277
    emit loading();
1✔
1278

1279
    if (doc.attributes().hasAttribute(KXMLQLCStartupFunction))
1✔
1280
    {
1281
        quint32 sID = doc.attributes().value(KXMLQLCStartupFunction).toString().toUInt();
×
1282
        if (sID != Function::invalidId())
×
1283
            setStartupFunction(sID);
×
1284
    }
1285

1286
    while (doc.readNextStartElement())
17✔
1287
    {
1288
        //qDebug() << "Doc tag:" << doc.name();
1289
        if (doc.name() == KXMLFixture)
16✔
1290
        {
1291
            Fixture::loader(doc, this);
3✔
1292
        }
1293
        else if (doc.name() == KXMLQLCFixtureGroup)
13✔
1294
        {
1295
            FixtureGroup::loader(doc, this);
3✔
1296
        }
1297
        else if (doc.name() == KXMLQLCChannelsGroup)
10✔
1298
        {
1299
            ChannelsGroup::loader(doc, this);
×
1300
        }
1301
        else if (doc.name() == KXMLQLCPalette)
10✔
1302
        {
1303
            QLCPalette::loader(doc, this);
×
1304
            doc.skipCurrentElement();
×
1305
        }
1306
        else if (doc.name() == KXMLQLCFunction)
10✔
1307
        {
1308
            //qDebug() << doc.attributes().value("Name").toString();
1309
            Function::loader(doc, this);
4✔
1310
        }
1311
        else if (doc.name() == KXMLQLCBus)
6✔
1312
        {
1313
            /* LEGACY */
1314
            Bus::instance()->loadXML(doc);
5✔
1315
        }
1316
        else if (doc.name() == KXMLIOMap && loadIO)
1✔
1317
        {
1318
            m_ioMap->loadXML(doc);
×
1319
        }
1320
        else if (doc.name() == KXMLQLCMonitorProperties)
1✔
1321
        {
1322
            monitorProperties()->loadXML(doc, this);
×
1323
        }
1324
        else
1325
        {
1326
            qWarning() << Q_FUNC_INFO << "Unknown engine tag:" << doc.name();
1✔
1327
            doc.skipCurrentElement();
1✔
1328
        }
1329
    }
1330

1331
    postLoad();
1✔
1332

1333
    m_loadStatus = Loaded;
1✔
1334
    emit loaded();
1✔
1335

1336
    return true;
1✔
1337
}
1338

1339
bool Doc::saveXML(QXmlStreamWriter *doc)
1✔
1340
{
1341
    Q_ASSERT(doc != NULL);
1✔
1342

1343
    /* Create the master Engine node */
1344
    doc->writeStartElement(KXMLQLCEngine);
1✔
1345

1346
    if (startupFunction() != Function::invalidId())
1✔
1347
        doc->writeAttribute(KXMLQLCStartupFunction, QString::number(startupFunction()));
1✔
1348

1349
    m_ioMap->saveXML(doc);
1✔
1350

1351
    /* Write fixtures into an XML document */
1352
    QListIterator <Fixture*> fxit(fixtures());
2✔
1353
    while (fxit.hasNext() == true)
4✔
1354
    {
1355
        Fixture *fxi(fxit.next());
3✔
1356
        Q_ASSERT(fxi != NULL);
3✔
1357
        fxi->saveXML(doc);
3✔
1358
    }
1359

1360
    /* Write fixture groups into an XML document */
1361
    QListIterator <FixtureGroup*> grpit(fixtureGroups());
3✔
1362
    while (grpit.hasNext() == true)
3✔
1363
    {
1364
        FixtureGroup *grp(grpit.next());
2✔
1365
        Q_ASSERT(grp != NULL);
2✔
1366
        grp->saveXML(doc);
2✔
1367
    }
1368

1369
    /* Write channel groups into an XML document */
1370
    QListIterator <ChannelsGroup*> chanGroups(channelsGroups());
3✔
1371
    while (chanGroups.hasNext() == true)
1✔
1372
    {
1373
        ChannelsGroup *grp(chanGroups.next());
×
1374
        Q_ASSERT(grp != NULL);
×
1375
        grp->saveXML(doc);
×
1376
    }
1377

1378
    /* Write palettes into an XML document */
1379
    QListIterator <QLCPalette*> paletteIt(palettes());
3✔
1380
    while (paletteIt.hasNext() == true)
1✔
1381
    {
1382
        QLCPalette *palette(paletteIt.next());
×
1383
        Q_ASSERT(palette != NULL);
×
1384
        palette->saveXML(doc);
×
1385
    }
1386

1387
    /* Write functions into an XML document */
1388
    QListIterator <Function*> funcit(functions());
2✔
1389
    while (funcit.hasNext() == true)
5✔
1390
    {
1391
        Function *func(funcit.next());
4✔
1392
        Q_ASSERT(func != NULL);
4✔
1393
        func->saveXML(doc);
4✔
1394
    }
1395

1396
    if (m_monitorProps != NULL)
1✔
1397
        m_monitorProps->saveXML(doc, this);
1✔
1398

1399
    /* End the <Engine> tag */
1400
    doc->writeEndElement();
1✔
1401

1402
    return true;
2✔
1403
}
1404

1405
void Doc::appendToErrorLog(QString error)
8✔
1406
{
1407
    if (m_errorLog.contains(error))
8✔
1408
        return;
5✔
1409

1410
    m_errorLog.append(error);
3✔
1411
    m_errorLog.append("<br>");
3✔
1412
}
1413

1414
void Doc::clearErrorLog()
2✔
1415
{
1416
    m_errorLog = "";
2✔
1417
}
2✔
1418

1419
QString Doc::errorLog()
1✔
1420
{
1421
    return m_errorLog;
1✔
1422
}
1423

1424
void Doc::postLoad()
1✔
1425
{
1426
    QListIterator <Function*> functionit(functions());
3✔
1427
    while (functionit.hasNext() == true)
5✔
1428
    {
1429
        Function* function(functionit.next());
4✔
1430
        Q_ASSERT(function != NULL);
4✔
1431
        function->postLoad();
4✔
1432
    }
1433
}
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