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

mcallegari / qlcplus / 13633248611

03 Mar 2025 02:31PM UTC coverage: 31.871% (+0.4%) from 31.5%
13633248611

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 hits per line

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

90.91
/engine/src/doc.cpp
1
/*
2
  Q Light Controller Plus
3
  doc.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

8
  Licensed under the Apache License, Version 2.0 (the "License");
9
  you may not use this file except in compliance with the License.
10
  You may obtain a copy of the License at
11

12
      http://www.apache.org/licenses/LICENSE-2.0.txt
13

14
  Unless required by applicable law or agreed to in writing, software
15
  distributed under the License is distributed on an "AS IS" BASIS,
16
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
  See the License for the specific language governing permissions and
18
  limitations under the License.
19
*/
20

21
#include <QXmlStreamReader>
22
#include <QXmlStreamWriter>
23
#include <QStringList>
24
#include <QString>
25
#include <QDebug>
26
#include <QList>
27
#include <QTime>
28
#include <QDir>
29
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
30
#include <QRandomGenerator>
31
#endif
32

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

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

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

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

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

101
    clearContents();
177✔
102

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

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

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

117
    delete m_fixtureDefCache;
177✔
118
    m_fixtureDefCache = NULL;
177✔
119
}
491✔
120

121
void Doc::clearContents()
452✔
122
{
123
    emit clearing();
452✔
124

125
    m_clipboard->resetContents();
452✔
126

127
    if (m_monitorProps != NULL)
452✔
128
        m_monitorProps->reset();
9✔
129

130
    destroyAudioCapture();
452✔
131

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

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

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

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

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

182
    m_orderedGroups.clear();
452✔
183

184
    m_latestFunctionId = 0;
452✔
185
    m_latestFixtureId = 0;
452✔
186
    m_latestFixtureGroupId = 0;
452✔
187
    m_latestChannelsGroupId = 0;
452✔
188
    m_latestPaletteId = 0;
452✔
189
    m_addresses.clear();
452✔
190
    m_loadStatus = Cleared;
452✔
191

192
    emit cleared();
452✔
193
}
452✔
194

195
void Doc::setWorkspacePath(QString path)
4✔
196
{
197
    m_wsPath = path;
4✔
198
}
4✔
199

200
QString Doc::getWorkspacePath() const
23✔
201
{
202
    return m_wsPath;
23✔
203
}
204

205
QString Doc::normalizeComponentPath(const QString& filePath) const
7✔
206
{
207
    if (filePath.isEmpty())
7✔
208
        return filePath;
209

210
    QFileInfo f(filePath);
6✔
211

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

222
QString Doc::denormalizeComponentPath(const QString& filePath) const
8✔
223
{
224
    if (filePath.isEmpty())
8✔
225
        return filePath;
226

227
    return QFileInfo(QDir(getWorkspacePath()), filePath).absoluteFilePath();
6✔
228
}
229

230
/*****************************************************************************
231
 * Engine components
232
 *****************************************************************************/
233

234
QLCFixtureDefCache* Doc::fixtureDefCache() const
1,643✔
235
{
236
    return m_fixtureDefCache;
1,643✔
237
}
238

239
void Doc::setFixtureDefinitionCache(QLCFixtureDefCache *cache)
×
240
{
241
    m_fixtureDefCache = cache;
×
242
}
×
243

244
QLCModifiersCache* Doc::modifiersCache() const
1✔
245
{
246
    return m_modifiersCache;
1✔
247
}
248

249
RGBScriptsCache* Doc::rgbScriptsCache() const
69✔
250
{
251
    return m_rgbScriptsCache;
69✔
252
}
253

254
IOPluginCache* Doc::ioPluginCache() const
288✔
255
{
256
    return m_ioPluginCache;
288✔
257
}
258

259
AudioPluginCache *Doc::audioPluginCache() const
1✔
260
{
261
    return m_audioPluginCache;
1✔
262
}
263

264
InputOutputMap* Doc::inputOutputMap() const
2,707✔
265
{
266
    return m_ioMap;
2,707✔
267
}
268

269
MasterTimer* Doc::masterTimer() const
1,102✔
270
{
271
    return m_masterTimer;
1,102✔
272
}
273

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

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

307
/*****************************************************************************
308
 * Modified status
309
 *****************************************************************************/
310
Doc::LoadStatus Doc::loadStatus() const
2✔
311
{
312
    return m_loadStatus;
2✔
313
}
314

315
bool Doc::isModified() const
29✔
316
{
317
    return m_modified;
29✔
318
}
319

320
void Doc::setModified()
1,245✔
321
{
322
    m_modified = true;
1,245✔
323
    emit modified(true);
1,245✔
324
}
1,245✔
325

326
void Doc::resetModified()
192✔
327
{
328
    m_modified = false;
192✔
329
    emit modified(false);
192✔
330
}
192✔
331

332
/*****************************************************************************
333
 * Main operating mode
334
 *****************************************************************************/
335

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

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

359
    emit modeChanged(m_mode);
21✔
360
}
361

362
Doc::Mode Doc::mode() const
323✔
363
{
364
    return m_mode;
323✔
365
}
366

367
void Doc::setKiosk(bool state)
1✔
368
{
369
    m_kiosk = state;
1✔
370
}
1✔
371

372
bool Doc::isKiosk() const
179✔
373
{
374
    return m_kiosk;
179✔
375
}
376

377
/*********************************************************************
378
 * Clipboard
379
 *********************************************************************/
380

381
QLCClipboard *Doc::clipboard()
1✔
382
{
383
    return m_clipboard;
1✔
384
}
385

386
/*****************************************************************************
387
 * Fixtures
388
 *****************************************************************************/
389

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

401
    return m_latestFixtureId;
16,781✔
402
}
403

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

408
    quint32 i;
409
    quint32 uni = fixture->universe();
406✔
410

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

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

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

432
    fixture->setID(id);
401✔
433
    m_fixtures.insert(id, fixture);
401✔
434
    m_fixturesListCacheUpToDate = false;
401✔
435

436
    /* Patch fixture change signals thru Doc */
437
    connect(fixture, SIGNAL(changed(quint32)),
401✔
438
            this, SLOT(slotFixtureChanged(quint32)));
439

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

447
    if (crossUniverse)
401✔
448
        uni = floor((fixture->universeAddress() + fixture->channels()) / 512);
×
449

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

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

460
    QList<int> forcedHTP = fixture->forcedHTPChannels();
401✔
461
    QList<int> forcedLTP = fixture->forcedLTPChannels();
401✔
462
    quint32 fxAddress = fixture->address();
401✔
463

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

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

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

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

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

492
    emit fixtureAdded(id);
401✔
493
    setModified();
401✔
494

495
    return true;
496
}
401✔
497

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

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

517
        emit fixtureRemoved(id);
10✔
518
        setModified();
10✔
519
        delete fxi;
10✔
520

521
        if (m_fixtures.count() == 0)
10✔
522
            m_latestFixtureId = 0;
6✔
523

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

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

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

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

588
        newFixture->setExcludeFadeChannels(fixture->excludeFadeChannels());
2✔
589
        newFixture->setForcedHTPChannels(fixture->forcedHTPChannels());
2✔
590
        newFixture->setForcedLTPChannels(fixture->forcedLTPChannels());
2✔
591

592
        m_fixtures.insert(id, newFixture);
2✔
593
        m_fixturesListCacheUpToDate = false;
2✔
594

595
        /* Patch fixture change signals thru Doc */
596
        connect(newFixture, SIGNAL(changed(quint32)),
2✔
597
                this, SLOT(slotFixtureChanged(quint32)));
598

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

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

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

621
    // Set forced HTP channels
622
    fixture->setForcedHTPChannels(forcedHTP);
1✔
623

624
    // Set forced LTP channels
625
    fixture->setForcedLTPChannels(forcedLTP);
1✔
626

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

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

640
        // Apply the default value BEFORE modifiers
641
        universe->setChannelDefaultValue(fxAddress + i, channel->defaultValue());
6✔
642

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

648
    inputOutputMap()->releaseUniverses(true);
1✔
649

650
    return true;
651
}
1✔
652

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

671
int Doc::fixturesCount() const
×
672
{
673
    return m_fixtures.count();
×
674
}
675

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

681
quint32 Doc::fixtureForAddress(quint32 universeAddress) const
79✔
682
{
683
    return m_addresses.value(universeAddress, Fixture::invalidId());
79✔
684
}
685

686
int Doc::totalPowerConsumption(int& fuzzy) const
4✔
687
{
688
    int totalPowerConsumption = 0;
689

690
    // Make sure fuzzy starts from zero
691
    fuzzy = 0;
4✔
692

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

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

713
    return totalPowerConsumption;
4✔
714
}
715

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

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

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

744
    setModified();
4✔
745
    emit fixtureChanged(id);
4✔
746
}
4✔
747

748
/*****************************************************************************
749
 * Fixture groups
750
 *****************************************************************************/
751

752
bool Doc::addFixtureGroup(FixtureGroup* grp, quint32 id)
15✔
753
{
754
    Q_ASSERT(grp != NULL);
755

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

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

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

774
        emit fixtureGroupAdded(id);
13✔
775
        setModified();
13✔
776

777
        return true;
13✔
778
    }
779
}
780

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

788
        emit fixtureGroupRemoved(id);
2✔
789
        setModified();
2✔
790
        delete grp;
2✔
791

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

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

809
QList <FixtureGroup*> Doc::fixtureGroups() const
34✔
810
{
811
    return m_fixtureGroups.values();
34✔
812
}
813

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

825
    return m_latestFixtureGroupId;
8✔
826
}
827

828
void Doc::slotFixtureGroupChanged(quint32 id)
25✔
829
{
830
    setModified();
25✔
831
    emit fixtureGroupChanged(id);
25✔
832
}
25✔
833

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

841
    // No ID given, this method can assign one
842
    if (id == ChannelsGroup::invalidId())
4✔
843
        id = createChannelsGroupId();
4✔
844

845
     grp->setId(id);
4✔
846
     m_channelsGroups[id] = grp;
4✔
847
     if (m_orderedGroups.contains(id) == false)
4✔
848
        m_orderedGroups.append(id);
4✔
849

850
     emit channelsGroupAdded(id);
4✔
851
     setModified();
4✔
852

853
     return true;
4✔
854
}
855

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

863
        emit channelsGroupRemoved(id);
1✔
864
        setModified();
1✔
865
        delete grp;
1✔
866

867
        int idx = m_orderedGroups.indexOf(id);
1✔
868
        if (idx != -1)
1✔
869
            m_orderedGroups.takeAt(idx);
1✔
870

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

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

885
    int idx = m_orderedGroups.indexOf(id);
886

887
    if (idx + direction < 0 || idx + direction >= m_orderedGroups.count())
2✔
888
        return false;
889

890
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
891
    m_orderedGroups.takeAt(idx);
1✔
892
    m_orderedGroups.insert(idx + direction, id);
1✔
893
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
894

895
    setModified();
1✔
896
    return true;
1✔
897
}
898

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

907
QList <ChannelsGroup*> Doc::channelsGroups() const
15✔
908
{
909
    QList <ChannelsGroup*> orderedList;
910

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

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

926
    return m_latestChannelsGroupId;
4✔
927
}
928

929
/*********************************************************************
930
 * Palettes
931
 *********************************************************************/
932

933
bool Doc::addPalette(QLCPalette *palette, quint32 id)
2✔
934
{
935
    Q_ASSERT(palette != NULL);
936

937
    // No ID given, this method can assign one
938
    if (id == QLCPalette::invalidId())
2✔
939
        id = createPaletteId();
2✔
940

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

951
        emit paletteAdded(id);
2✔
952
        setModified();
2✔
953
    }
954

955
    return true;
2✔
956
}
957

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

965
        emit paletteRemoved(id);
2✔
966
        setModified();
2✔
967
        delete palette;
2✔
968

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

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

986
QList<QLCPalette *> Doc::palettes() const
8✔
987
{
988
    return m_palettes.values();
8✔
989
}
990

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

999
    return m_latestPaletteId;
2✔
1000
}
1001

1002
/*****************************************************************************
1003
 * Functions
1004
 *****************************************************************************/
1005

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

1017
    return m_latestFunctionId;
243✔
1018
}
1019

1020
bool Doc::addFunction(Function* func, quint32 id)
256✔
1021
{
1022
    Q_ASSERT(func != NULL);
1023

1024
    if (id == Function::invalidId())
256✔
1025
        id = createFunctionId();
243✔
1026

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

1038
        // Listen to function name changes
1039
        connect(func, SIGNAL(nameChanged(quint32)),
254✔
1040
                this, SLOT(slotFunctionNameChanged(quint32)));
1041

1042
        // Make the function listen to fixture removals
1043
        connect(this, SIGNAL(fixtureRemoved(quint32)),
254✔
1044
                func, SLOT(slotFixtureRemoved(quint32)));
1045

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

1052
        return true;
254✔
1053
    }
1054
}
1055

1056
QList <Function*> Doc::functions() const
49✔
1057
{
1058
    return m_functions.values();
49✔
1059
}
1060

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

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

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

1089
        if (m_startupFunctionId == id)
8✔
1090
            m_startupFunctionId = Function::invalidId();
×
1091

1092
        emit functionRemoved(id);
8✔
1093
        setModified();
8✔
1094
        delete func;
8✔
1095

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

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

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

1122
    return tmpFID;
2✔
1123
}
1124

1125
void Doc::setStartupFunction(quint32 fid)
1✔
1126
{
1127
    m_startupFunctionId = fid;
1✔
1128
}
1✔
1129

1130
quint32 Doc::startupFunction()
3✔
1131
{
1132
    return m_startupFunctionId;
3✔
1133
}
1134

1135
QList<quint32> Doc::getUsage(quint32 fid)
7✔
1136
{
1137
    QList<quint32> usageList;
1138

1139
    foreach (Function *f, m_functions)
70✔
1140
    {
1141
        if (f->id() == fid)
63✔
1142
            continue;
6✔
1143

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

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

1221
    return usageList;
7✔
1222
}
×
1223

1224
void Doc::slotFunctionChanged(quint32 fid)
111✔
1225
{
1226
    setModified();
111✔
1227
    emit functionChanged(fid);
111✔
1228
}
111✔
1229

1230
void Doc::slotFunctionNameChanged(quint32 fid)
2✔
1231
{
1232
    setModified();
2✔
1233
    emit functionNameChanged(fid);
2✔
1234
}
2✔
1235

1236
/*********************************************************************
1237
 * Monitor Properties
1238
 *********************************************************************/
1239

1240
MonitorProperties *Doc::monitorProperties()
1✔
1241
{
1242
    if (m_monitorProps == NULL)
1✔
1243
        m_monitorProps = new MonitorProperties();
2✔
1244

1245
    return m_monitorProps;
1✔
1246
}
1247

1248
/*****************************************************************************
1249
 * Load & Save
1250
 *****************************************************************************/
1251

1252
bool Doc::loadXML(QXmlStreamReader &doc, bool loadIO)
2✔
1253
{
1254
    clearErrorLog();
2✔
1255

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

1262
    m_loadStatus = Loading;
1✔
1263
    emit loading();
1✔
1264

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

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

1317
    postLoad();
1✔
1318

1319
    m_loadStatus = Loaded;
1✔
1320
    emit loaded();
1✔
1321

1322
    return true;
1✔
1323
}
1324

1325
bool Doc::saveXML(QXmlStreamWriter *doc)
1✔
1326
{
1327
    Q_ASSERT(doc != NULL);
1328

1329
    /* Create the master Engine node */
1330
    doc->writeStartElement(KXMLQLCEngine);
1✔
1331

1332
    if (startupFunction() != Function::invalidId())
1✔
1333
        doc->writeAttribute(KXMLQLCStartupFunction, QString::number(startupFunction()));
1✔
1334

1335
    m_ioMap->saveXML(doc);
1✔
1336

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

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

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

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

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

1382
    if (m_monitorProps != NULL)
1✔
1383
        m_monitorProps->saveXML(doc, this);
1✔
1384

1385
    /* End the <Engine> tag */
1386
    doc->writeEndElement();
1✔
1387

1388
    return true;
1✔
1389
}
1390

1391
void Doc::appendToErrorLog(QString error)
8✔
1392
{
1393
    if (m_errorLog.contains(error))
8✔
1394
        return;
1395

1396
    m_errorLog.append(error);
3✔
1397
    m_errorLog.append("<br>");
3✔
1398
}
1399

1400
void Doc::clearErrorLog()
2✔
1401
{
1402
    m_errorLog = "";
2✔
1403
}
2✔
1404

1405
QString Doc::errorLog()
1✔
1406
{
1407
    return m_errorLog;
1✔
1408
}
1409

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