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

mcallegari / qlcplus / 11882867408

17 Nov 2024 10:49PM UTC coverage: 31.964% (-0.003%) from 31.967%
11882867408

push

github

mcallegari
Add an option to allow fixture crossing a universe

7 of 19 new or added lines in 3 files covered. (36.84%)

2 existing lines in 2 files now uncovered.

14040 of 43925 relevant lines covered (31.96%)

27150.68 hits per line

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

91.19
/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("")
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)
76
    , m_mode(Design)
77
    , m_kiosk(false)
78
    , m_loadStatus(Cleared)
79
    , m_clipboard(new QLCClipboard(this))
177✔
80
    , m_fixturesListCacheUpToDate(false)
81
    , m_latestFixtureId(0)
82
    , m_latestFixtureGroupId(0)
83
    , m_latestChannelsGroupId(0)
84
    , m_latestPaletteId(0)
85
    , m_latestFunctionId(0)
86
    , m_startupFunctionId(Function::invalidId())
1,593✔
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()
491✔
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
}
314✔
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());
904✔
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());
904✔
145
    while (palIt.hasNext() == true)
452✔
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());
904✔
154
    while (grpchans.hasNext() == true)
455✔
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());
904✔
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());
904✔
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);
12✔
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
}
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,633✔
235
{
236
    return m_fixtureDefCache;
1,633✔
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()
7✔
275
{
276
    if (!m_inputCapture)
7✔
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;
7✔
296
}
297

298
void Doc::destroyAudioCapture()
452✔
299
{
300
    if (m_inputCapture.isNull() == false)
452✔
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 (uni >= inputOutputMap()->universesCount())
401✔
448
    {
449
        for (i = inputOutputMap()->universesCount(); i <= uni; i++)
×
450
            inputOutputMap()->addUniverse(i);
×
451
        inputOutputMap()->startUniverses();
×
452
    }
453

454
    // Add the fixture channels capabilities to the universe they belong
455
    QList<Universe *> universes = inputOutputMap()->claimUniverses();
802✔
456

457
    QList<int> forcedHTP = fixture->forcedHTPChannels();
802✔
458
    QList<int> forcedLTP = fixture->forcedLTPChannels();
802✔
459
    quint32 fxAddress = fixture->address();
401✔
460

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

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

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

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

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

489
    emit fixtureAdded(id);
401✔
490
    setModified();
401✔
491

492
    return true;
493
}
494

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

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

514
        emit fixtureRemoved(id);
10✔
515
        setModified();
10✔
516
        delete fxi;
10✔
517

518
        if (m_fixtures.count() == 0)
10✔
519
            m_latestFixtureId = 0;
6✔
520

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

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

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

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

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

589
        m_fixtures.insert(id, newFixture);
2✔
590
        m_fixturesListCacheUpToDate = false;
2✔
591

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

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

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

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

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

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

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

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

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

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

645
    inputOutputMap()->releaseUniverses(true);
1✔
646

647
    return true;
648
}
649

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

668
int Doc::fixturesCount() const
×
669
{
670
    return m_fixtures.count();
×
671
}
672

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

678
quint32 Doc::fixtureForAddress(quint32 universeAddress) const
79✔
679
{
680
    return m_addresses.value(universeAddress, Fixture::invalidId());
79✔
681
}
682

683
int Doc::totalPowerConsumption(int& fuzzy) const
4✔
684
{
685
    int totalPowerConsumption = 0;
686

687
    // Make sure fuzzy starts from zero
688
    fuzzy = 0;
4✔
689

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

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

710
    return totalPowerConsumption;
4✔
711
}
712

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

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

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

741
    setModified();
4✔
742
    emit fixtureChanged(id);
4✔
743
}
4✔
744

745
/*****************************************************************************
746
 * Fixture groups
747
 *****************************************************************************/
748

749
bool Doc::addFixtureGroup(FixtureGroup* grp, quint32 id)
15✔
750
{
751
    Q_ASSERT(grp != NULL);
752

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

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

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

771
        emit fixtureGroupAdded(id);
13✔
772
        setModified();
13✔
773

774
        return true;
13✔
775
    }
776
}
777

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

785
        emit fixtureGroupRemoved(id);
2✔
786
        setModified();
2✔
787
        delete grp;
2✔
788

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

798
FixtureGroup* Doc::fixtureGroup(quint32 id) const
47✔
799
{
800
    if (m_fixtureGroups.contains(id) == true)
47✔
801
        return m_fixtureGroups[id];
802
    else
803
        return NULL;
804
}
805

806
QList <FixtureGroup*> Doc::fixtureGroups() const
34✔
807
{
808
    return m_fixtureGroups.values();
34✔
809
}
810

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

822
    return m_latestFixtureGroupId;
8✔
823
}
824

825
void Doc::slotFixtureGroupChanged(quint32 id)
25✔
826
{
827
    setModified();
25✔
828
    emit fixtureGroupChanged(id);
25✔
829
}
25✔
830

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

838
    // No ID given, this method can assign one
839
    if (id == ChannelsGroup::invalidId())
4✔
840
        id = createChannelsGroupId();
4✔
841

842
     grp->setId(id);
4✔
843
     m_channelsGroups[id] = grp;
4✔
844
     if (m_orderedGroups.contains(id) == false)
4✔
845
        m_orderedGroups.append(id);
4✔
846

847
     emit channelsGroupAdded(id);
4✔
848
     setModified();
4✔
849

850
     return true;
4✔
851
}
852

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

860
        emit channelsGroupRemoved(id);
1✔
861
        setModified();
1✔
862
        delete grp;
1✔
863

864
        int idx = m_orderedGroups.indexOf(id);
1✔
865
        if (idx != -1)
1✔
866
            m_orderedGroups.takeAt(idx);
1✔
867

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

877
bool Doc::moveChannelGroup(quint32 id, int direction)
3✔
878
{
879
    if (direction == 0 || m_orderedGroups.contains(id) == false)
5✔
880
        return false;
881

882
    int idx = m_orderedGroups.indexOf(id);
2✔
883

884
    if (idx + direction < 0 || idx + direction >= m_orderedGroups.count())
2✔
885
        return false;
886

887
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
888
    m_orderedGroups.takeAt(idx);
1✔
889
    m_orderedGroups.insert(idx + direction, id);
1✔
890
    qDebug() << Q_FUNC_INFO << m_orderedGroups;
891

892
    setModified();
1✔
893
    return true;
1✔
894
}
895

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

904
QList <ChannelsGroup*> Doc::channelsGroups() const
15✔
905
{
906
    QList <ChannelsGroup*> orderedList;
907

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

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

923
    return m_latestChannelsGroupId;
4✔
924
}
925

926
/*********************************************************************
927
 * Palettes
928
 *********************************************************************/
929

930
bool Doc::addPalette(QLCPalette *palette, quint32 id)
2✔
931
{
932
    Q_ASSERT(palette != NULL);
933

934
    // No ID given, this method can assign one
935
    if (id == QLCPalette::invalidId())
2✔
936
        id = createPaletteId();
2✔
937

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

948
        emit paletteAdded(id);
2✔
949
        setModified();
2✔
950
    }
951

952
    return true;
2✔
953
}
954

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

962
        emit paletteRemoved(id);
2✔
963
        setModified();
2✔
964
        delete palette;
2✔
965

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

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

983
QList<QLCPalette *> Doc::palettes() const
8✔
984
{
985
    return m_palettes.values();
8✔
986
}
987

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

996
    return m_latestPaletteId;
2✔
997
}
998

999
/*****************************************************************************
1000
 * Functions
1001
 *****************************************************************************/
1002

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

1014
    return m_latestFunctionId;
243✔
1015
}
1016

1017
bool Doc::addFunction(Function* func, quint32 id)
256✔
1018
{
1019
    Q_ASSERT(func != NULL);
1020

1021
    if (id == Function::invalidId())
256✔
1022
        id = createFunctionId();
243✔
1023

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

1035
        // Listen to function name changes
1036
        connect(func, SIGNAL(nameChanged(quint32)),
254✔
1037
                this, SLOT(slotFunctionNameChanged(quint32)));
1038

1039
        // Make the function listen to fixture removals
1040
        connect(this, SIGNAL(fixtureRemoved(quint32)),
254✔
1041
                func, SLOT(slotFixtureRemoved(quint32)));
1042

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

1049
        return true;
254✔
1050
    }
1051
}
1052

1053
QList <Function*> Doc::functions() const
49✔
1054
{
1055
    return m_functions.values();
49✔
1056
}
1057

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

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

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

1086
        if (m_startupFunctionId == id)
8✔
1087
            m_startupFunctionId = Function::invalidId();
×
1088

1089
        emit functionRemoved(id);
8✔
1090
        setModified();
8✔
1091
        delete func;
8✔
1092

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

1102
Function* Doc::function(quint32 id) const
883✔
1103
{
1104
    if (m_functions.contains(id) == true)
883✔
1105
        return m_functions[id];
1106
    else
1107
        return NULL;
1108
}
1109

1110
quint32 Doc::nextFunctionID()
2✔
1111
{
1112
    quint32 tmpFID = m_latestFunctionId;
2✔
1113
    while (m_functions.contains(tmpFID) == true ||
5✔
1114
           tmpFID == Fixture::invalidId())
2✔
1115
    {
1116
        tmpFID++;
1✔
1117
    }
1118

1119
    return tmpFID;
2✔
1120
}
1121

1122
void Doc::setStartupFunction(quint32 fid)
1✔
1123
{
1124
    m_startupFunctionId = fid;
1✔
1125
}
1✔
1126

1127
quint32 Doc::startupFunction()
3✔
1128
{
1129
    return m_startupFunctionId;
3✔
1130
}
1131

1132
QList<quint32> Doc::getUsage(quint32 fid)
7✔
1133
{
1134
    QList<quint32> usageList;
1135

1136
    foreach (Function *f, m_functions)
140✔
1137
    {
1138
        if (f->id() == fid)
63✔
1139
            continue;
6✔
1140

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

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

1218
    return usageList;
7✔
1219
}
1220

1221
void Doc::slotFunctionChanged(quint32 fid)
111✔
1222
{
1223
    setModified();
111✔
1224
    emit functionChanged(fid);
111✔
1225
}
111✔
1226

1227
void Doc::slotFunctionNameChanged(quint32 fid)
2✔
1228
{
1229
    setModified();
2✔
1230
    emit functionNameChanged(fid);
2✔
1231
}
2✔
1232

1233
/*********************************************************************
1234
 * Monitor Properties
1235
 *********************************************************************/
1236

1237
MonitorProperties *Doc::monitorProperties()
1✔
1238
{
1239
    if (m_monitorProps == NULL)
1✔
1240
        m_monitorProps = new MonitorProperties();
2✔
1241

1242
    return m_monitorProps;
1✔
1243
}
1244

1245
/*****************************************************************************
1246
 * Load & Save
1247
 *****************************************************************************/
1248

1249
bool Doc::loadXML(QXmlStreamReader &doc, bool loadIO)
2✔
1250
{
1251
    clearErrorLog();
2✔
1252

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

1259
    m_loadStatus = Loading;
1✔
1260
    emit loading();
1✔
1261

1262
    if (doc.attributes().hasAttribute(KXMLQLCStartupFunction))
2✔
1263
    {
1264
        quint32 sID = doc.attributes().value(KXMLQLCStartupFunction).toString().toUInt();
×
1265
        if (sID != Function::invalidId())
×
1266
            setStartupFunction(sID);
×
1267
    }
1268

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

1314
    postLoad();
1✔
1315

1316
    m_loadStatus = Loaded;
1✔
1317
    emit loaded();
1✔
1318

1319
    return true;
1✔
1320
}
1321

1322
bool Doc::saveXML(QXmlStreamWriter *doc)
1✔
1323
{
1324
    Q_ASSERT(doc != NULL);
1325

1326
    /* Create the master Engine node */
1327
    doc->writeStartElement(KXMLQLCEngine);
1✔
1328

1329
    if (startupFunction() != Function::invalidId())
1✔
1330
        doc->writeAttribute(KXMLQLCStartupFunction, QString::number(startupFunction()));
1✔
1331

1332
    m_ioMap->saveXML(doc);
1✔
1333

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

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

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

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

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

1379
    if (m_monitorProps != NULL)
1✔
1380
        m_monitorProps->saveXML(doc, this);
1✔
1381

1382
    /* End the <Engine> tag */
1383
    doc->writeEndElement();
1✔
1384

1385
    return true;
1✔
1386
}
1387

1388
void Doc::appendToErrorLog(QString error)
8✔
1389
{
1390
    if (m_errorLog.contains(error))
8✔
1391
        return;
1392

1393
    m_errorLog.append(error);
3✔
1394
    m_errorLog.append("<br>");
3✔
1395
}
1396

1397
void Doc::clearErrorLog()
2✔
1398
{
1399
    m_errorLog = "";
2✔
1400
}
2✔
1401

1402
QString Doc::errorLog()
1✔
1403
{
1404
    return m_errorLog;
1✔
1405
}
1406

1407
void Doc::postLoad()
1✔
1408
{
1409
    QListIterator <Function*> functionit(functions());
2✔
1410
    while (functionit.hasNext() == true)
5✔
1411
    {
1412
        Function* function(functionit.next());
4✔
1413
        Q_ASSERT(function != NULL);
1414
        function->postLoad();
4✔
1415
    }
1416
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc