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

mcallegari / qlcplus / 14809507932

03 May 2025 09:13AM UTC coverage: 31.879% (+0.03%) from 31.845%
14809507932

push

github

web-flow
Merge pull request #1745 from mcallegari/qmluiqt6

Port QML UI to Qt6

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

3720 existing lines in 174 files now uncovered.

16422 of 51513 relevant lines covered (31.88%)

19079.9 hits per line

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

67.01
/engine/src/inputoutputmap.cpp
1
/*
2
  Q Light Controller Plus
3
  inputoutputmap.cpp
4

5
  Copyright (c) Massimo Callegari
6

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

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

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

20
#if defined(WIN32) || defined(Q_OS_WIN)
21
#        include <Windows.h>
22
#else
23
#   include <unistd.h>
24
#endif
25

26
#include <QXmlStreamReader>
27
#include <QXmlStreamWriter>
28
#include <QElapsedTimer>
29
#include <QSettings>
30
#include <QDebug>
31
#include <qmath.h>
32

33
#include "inputoutputmap.h"
34
#include "qlcinputchannel.h"
35
#include "qlcinputsource.h"
36
#include "qlcioplugin.h"
37
#include "outputpatch.h"
38
#include "inputpatch.h"
39
#include "qlcconfig.h"
40
#include "universe.h"
41
#include "qlcfile.h"
42
#include "doc.h"
43

44
InputOutputMap::InputOutputMap(Doc *doc, quint32 universes)
200✔
45
  : QObject(doc)
46
  , m_blackout(false)
200✔
47
  , m_universeChanged(false)
200✔
48
  , m_currentBPM(0)
200✔
49
  , m_beatTime(new QElapsedTimer())
200✔
50
{
51
    m_grandMaster = new GrandMaster(this);
200✔
52
    for (quint32 i = 0; i < universes; i++)
1,000✔
53
        addUniverse();
800✔
54

55
    connect(doc->ioPluginCache(), SIGNAL(pluginConfigurationChanged(QLCIOPlugin*)),
200✔
56
            this, SLOT(slotPluginConfigurationChanged(QLCIOPlugin*)));
57
    connect(doc->masterTimer(), SIGNAL(beat()), this, SLOT(slotMasterTimerBeat()));
200✔
58
}
200✔
59

60
InputOutputMap::~InputOutputMap()
377✔
61
{
62
    removeAllUniverses();
200✔
63
    delete m_grandMaster;
200✔
64
    delete m_beatTime;
200✔
65
    qDeleteAll(m_profiles);
200✔
66
}
377✔
67

68
Doc* InputOutputMap::doc() const
867✔
69
{
70
    return qobject_cast<Doc*> (parent());
867✔
71
}
72

73
/*****************************************************************************
74
 * Blackout
75
 *****************************************************************************/
76

77
bool InputOutputMap::toggleBlackout()
4✔
78
{
79
    if (m_blackout == true)
4✔
80
        setBlackout(false);
2✔
81
    else
82
        setBlackout(true);
2✔
83

84
    return m_blackout;
4✔
85
}
86

87
bool InputOutputMap::setBlackout(bool blackout)
7✔
88
{
89
    /* Don't do blackout twice */
90
    if (m_blackout == blackout)
7✔
91
        return false;
2✔
92

93
    m_blackout = blackout;
5✔
94

95
    // blackout is an atomic setting, so it's safe to do it
96
    // without mutex locking
97
    foreach (Universe *universe, m_universeArray)
25✔
98
    {
99
        for (int i = 0; i < universe->outputPatchesCount(); i++)
32✔
100
        {
101
            OutputPatch *op = universe->outputPatch(i);
12✔
102
            if (op != NULL)
12✔
103
                op->setBlackout(blackout);
12✔
104
        }
105

106
        const QByteArray postGM = universe->postGMValues()->mid(0, universe->usedChannels());
20✔
107
        universe->dumpOutput(postGM, true);
20✔
108
    }
25✔
109

110
    emit blackoutChanged(m_blackout);
5✔
111

112
    return true;
5✔
113
}
114

115
void InputOutputMap::requestBlackout(BlackoutRequest blackout)
×
116
{
117
    if (blackout != BlackoutRequestNone)
×
118
        setBlackout(blackout == BlackoutRequestOn ? true : false);
×
119
}
×
120

121
bool InputOutputMap::blackout() const
9✔
122
{
123
    return m_blackout;
9✔
124
}
125

126
/*****************************************************************************
127
 * Universes
128
 *****************************************************************************/
129

130
quint32 InputOutputMap::invalidUniverse()
1,940✔
131
{
132
    return UINT_MAX;
1,940✔
133
}
134

135
bool InputOutputMap::addUniverse(quint32 id)
803✔
136
{
137
    {
138
        QMutexLocker locker(&m_universeMutex);
803✔
139
        Universe *uni = NULL;
803✔
140

141
        if (id == InputOutputMap::invalidUniverse())
803✔
142
        {
143
            id = universesCount();
801✔
144
        }
145
        else if (id < universesCount())
2✔
146
        {
147
            qWarning() << Q_FUNC_INFO
2✔
148
                << "Universe" << id << "is already present in the list."
1✔
149
                << "The universe list may be unsorted.";
1✔
150
            return false;
1✔
151
        }
152
        else if (id > universesCount())
1✔
153
        {
154
            qDebug() << Q_FUNC_INFO
2✔
155
                << "Gap between universe" << (universesCount() - 1)
1✔
156
                << "and universe" << id << ", filling the gap...";
1✔
157
            while (id > universesCount())
4✔
158
            {
159
                uni = new Universe(universesCount(), m_grandMaster);
3✔
160
                connect(doc()->masterTimer(), SIGNAL(tickReady()), uni, SLOT(tick()), Qt::QueuedConnection);
3✔
161
                connect(uni, SIGNAL(universeWritten(quint32,QByteArray)), this, SIGNAL(universeWritten(quint32,QByteArray)));
3✔
162
                m_universeArray.append(uni);
3✔
163
            }
164
        }
165

166
        uni = new Universe(id, m_grandMaster);
802✔
167
        connect(doc()->masterTimer(), SIGNAL(tickReady()), uni, SLOT(tick()), Qt::QueuedConnection);
802✔
168
        connect(uni, SIGNAL(universeWritten(quint32,QByteArray)), this, SIGNAL(universeWritten(quint32,QByteArray)));
802✔
169
        m_universeArray.append(uni);
802✔
170
    }
803✔
171

172
    emit universeAdded(id);
802✔
173
    return true;
802✔
174
}
175

176
bool InputOutputMap::removeUniverse(int index)
3✔
177
{
178
    {
179
        QMutexLocker locker(&m_universeMutex);
3✔
180

181
        if (index < 0 || index >= m_universeArray.count())
3✔
182
            return false;
1✔
183

184
        if (index != (m_universeArray.size() - 1))
2✔
185
        {
186
            qWarning() << Q_FUNC_INFO << "Removing universe" << index
2✔
187
                << "would create a gap in the universe list, cancelling";
1✔
188
            return false;
1✔
189
        }
190

191
        delete  m_universeArray.takeAt(index);
1✔
192
    }
3✔
193

194
    emit universeRemoved(index);
1✔
195
    return true;
1✔
196
}
197

198
bool InputOutputMap::removeAllUniverses()
201✔
199
{
200
    QMutexLocker locker(&m_universeMutex);
201✔
201
    qDeleteAll(m_universeArray);
201✔
202
    m_universeArray.clear();
201✔
203
    return true;
201✔
204
}
201✔
205

206
void InputOutputMap::startUniverses()
×
207
{
208
    foreach (Universe *uni, m_universeArray)
×
209
        uni->start();
×
210
}
×
211

212
quint32 InputOutputMap::getUniverseID(int index)
2✔
213
{
214
    if (index >= 0 && index < m_universeArray.count())
2✔
215
        return index;
1✔
216

217
    return invalidUniverse();
1✔
218
}
219

220
QString InputOutputMap::getUniverseNameByIndex(int index)
4✔
221
{
222
    if (index >= 0 && index < m_universeArray.count())
4✔
223
        return m_universeArray.at(index)->name();
3✔
224

225
    return QString();
1✔
226
}
227

228
QString InputOutputMap::getUniverseNameByID(quint32 id)
1✔
229
{
230
    return getUniverseNameByIndex(id);
1✔
231
}
232

233
void InputOutputMap::setUniverseName(int index, QString name)
2✔
234
{
235
    if (index < 0 || index >= m_universeArray.count())
2✔
236
        return;
1✔
237
    m_universeArray.at(index)->setName(name);
1✔
238
}
239

240
void InputOutputMap::setUniversePassthrough(int index, bool enable)
2✔
241
{
242
    if (index < 0 || index >= m_universeArray.count())
2✔
243
        return;
1✔
244
    m_universeArray.at(index)->setPassthrough(enable);
1✔
245
}
246

247
bool InputOutputMap::getUniversePassthrough(int index)
2✔
248
{
249
    if (index < 0 || index >= m_universeArray.count())
2✔
250
        return false;
1✔
251
    return m_universeArray.at(index)->passthrough();
1✔
252
}
253

254
void InputOutputMap::setUniverseMonitor(int index, bool enable)
2✔
255
{
256
    if (index < 0 || index >= m_universeArray.count())
2✔
257
        return;
1✔
258
    m_universeArray.at(index)->setMonitor(enable);
1✔
259
}
260

261
bool InputOutputMap::getUniverseMonitor(int index)
2✔
262
{
263
    if (index < 0 || index >= m_universeArray.count())
2✔
264
        return false;
1✔
265
    return m_universeArray.at(index)->monitor();
1✔
266
}
267

268
bool InputOutputMap::isUniversePatched(int index)
3✔
269
{
270
    if (index < 0 || index >= m_universeArray.count())
3✔
271
        return false;
1✔
272

273
    return m_universeArray.at(index)->isPatched();
2✔
274
}
275

276
quint32 InputOutputMap::universesCount() const
1,599✔
277
{
278
    return (quint32)m_universeArray.count();
1,599✔
279
}
280

281
QList<Universe *> InputOutputMap::universes() const
42✔
282
{
283
    return m_universeArray;
42✔
284
}
285

286
Universe *InputOutputMap::universe(quint32 id)
×
287
{
288
    for (int i = 0; i < m_universeArray.size(); i++)
×
289
        if (m_universeArray.at(i)->id() == id)
×
290
            return m_universeArray.at(i);
×
291

UNCOV
292
    return NULL;
×
293
}
294

295
QList<Universe*> InputOutputMap::claimUniverses()
1,045✔
296
{
297
    m_universeMutex.lock();
1,045✔
298
    return m_universeArray;
1,045✔
299
}
300

301
void InputOutputMap::releaseUniverses(bool changed)
1,045✔
302
{
303
    m_universeChanged = changed;
1,045✔
304
    m_universeMutex.unlock();
1,045✔
305
}
1,045✔
306

307
void InputOutputMap::resetUniverses()
1✔
308
{
309
    {
310
        QMutexLocker locker(&m_universeMutex);
1✔
311
        for (int i = 0; i < m_universeArray.size(); i++)
5✔
312
            m_universeArray.at(i)->reset();
4✔
313
    }
1✔
314

315
    /* Reset Grand Master parameters */
316
    setGrandMasterValue(255);
1✔
317
    setGrandMasterValueMode(GrandMaster::Reduce);
1✔
318
    setGrandMasterChannelMode(GrandMaster::Intensity);
1✔
319
}
1✔
320

321
/*********************************************************************
322
 * Grand Master
323
 *********************************************************************/
324

325
void InputOutputMap::setGrandMasterChannelMode(GrandMaster::ChannelMode mode)
2✔
326
{
327
    Q_ASSERT(m_grandMaster != NULL);
2✔
328

329
    if (m_grandMaster->channelMode() != mode)
2✔
330
    {
331
        m_grandMaster->setChannelMode(mode);
1✔
332
        m_universeChanged = true;
1✔
333
    }
334
}
2✔
335

336
GrandMaster::ChannelMode InputOutputMap::grandMasterChannelMode()
78✔
337
{
338
    Q_ASSERT(m_grandMaster != NULL);
78✔
339

340
    return m_grandMaster->channelMode();
78✔
341
}
342

343
void InputOutputMap::setGrandMasterValueMode(GrandMaster::ValueMode mode)
2✔
344
{
345
    Q_ASSERT(m_grandMaster != NULL);
2✔
346

347
    if (m_grandMaster->valueMode() != mode)
2✔
348
    {
349
        m_grandMaster->setValueMode(mode);
1✔
350
        m_universeChanged = true;
1✔
351
    }
352

353
    emit grandMasterValueModeChanged(mode);
2✔
354
}
2✔
355

356
GrandMaster::ValueMode InputOutputMap::grandMasterValueMode()
154✔
357
{
358
    Q_ASSERT(m_grandMaster != NULL);
154✔
359

360
    return m_grandMaster->valueMode();
154✔
361
}
362

363
void InputOutputMap::setGrandMasterValue(uchar value)
2✔
364
{
365
    Q_ASSERT(m_grandMaster != NULL);
2✔
366

367
    if (m_grandMaster->value() != value)
2✔
368
    {
369
        m_grandMaster->setValue(value);
1✔
370
        m_universeChanged = true;
1✔
371
    }
372

373
    if (m_universeChanged == true)
2✔
374
        emit grandMasterValueChanged(value);
2✔
375
}
2✔
376

377
uchar InputOutputMap::grandMasterValue()
2✔
378
{
379
    Q_ASSERT(m_grandMaster != NULL);
2✔
380

381
    return m_grandMaster->value();
2✔
382
}
383

384
/*********************************************************************
385
 * Patch
386
 *********************************************************************/
387

388
void InputOutputMap::flushInputs()
5✔
389
{
390
    QMutexLocker locker(&m_universeMutex);
5✔
391
    foreach (Universe *universe, m_universeArray)
25✔
392
        universe->flushInput();
25✔
393
}
5✔
394

395
bool InputOutputMap::setInputPatch(quint32 universe, const QString &pluginName,
7✔
396
                                   const QString &inputUID, quint32 input,
397
                                   const QString &profileName)
398
{
399
    /* Check that the universe that we're doing mapping for is valid */
400
    if (universe >= universesCount())
7✔
401
    {
402
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
1✔
403
        return false;
1✔
404
    }
405

406
    QMutexLocker locker(&m_universeMutex);
6✔
407
    InputPatch *currInPatch = m_universeArray.at(universe)->inputPatch();
6✔
408
    QLCInputProfile *currProfile = NULL;
6✔
409
    if (currInPatch != NULL)
6✔
410
    {
411
        currProfile = currInPatch->profile();
1✔
412
        disconnect(currInPatch, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)),
1✔
413
                this, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)));
414
        if (currInPatch->plugin()->capabilities() & QLCIOPlugin::Beats)
1✔
415
        {
416
            disconnect(currInPatch, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)),
×
417
                       this, SLOT(slotPluginBeat(quint32,quint32,uchar,const QString&)));
418
        }
419
    }
420
    InputPatch *ip = NULL;
6✔
421
    QLCIOPlugin *plugin = doc()->ioPluginCache()->plugin(pluginName);
6✔
422

423
    if (!inputUID.isEmpty() && plugin != NULL)
6✔
424
    {
425
        QStringList inputs = plugin->inputs();
5✔
426
        int lIdx = inputs.indexOf(inputUID);
5✔
427
        if (lIdx != -1)
5✔
428
        {
429
            qDebug() << "[IOMAP] Found match on input by name on universe" << universe << "-" << input << "vs" << lIdx;
5✔
430
            input = lIdx;
5✔
431
        }
432
        else
433
        {
UNCOV
434
            qDebug() << "[IOMAP] !!No match found!! for input on universe" << universe << "-" << input << inputUID;
×
UNCOV
435
            qDebug() << plugin->inputs();
×
436
        }
437
    }
5✔
438

439
    if (m_universeArray.at(universe)->setInputPatch(
6✔
440
                plugin, input, profile(profileName)) == true)
6✔
441
    {
442
        ip = m_universeArray.at(universe)->inputPatch();
6✔
443
        if (ip != NULL)
6✔
444
        {
445
            connect(ip, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)),
5✔
446
                    this, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)));
447
            if (ip->plugin()->capabilities() & QLCIOPlugin::Beats)
5✔
448
            {
449
                connect(ip, SIGNAL(inputValueChanged(quint32,quint32,uchar,const QString&)),
×
450
                        this, SLOT(slotPluginBeat(quint32,quint32,uchar,const QString&)));
451
            }
452
        }
453
    }
454
    else
455
    {
UNCOV
456
        return false;
×
457
    }
458

459
    if (ip != NULL && currProfile != ip->profile())
6✔
460
        emit profileChanged(universe, ip->profileName());
3✔
461

462
    return true;
6✔
463
}
6✔
464

465
bool InputOutputMap::setInputProfile(quint32 universe, const QString &profileName)
×
466
{
467
    /* Check that the universe that we're doing mapping for is valid */
468
    if (universe >= universesCount())
×
469
    {
470
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
×
471
        return false;
×
472
    }
473

474
    InputPatch *currInPatch = m_universeArray.at(universe)->inputPatch();
×
475
    if (currInPatch != NULL)
×
476
        currInPatch->set(profile(profileName));
×
477

478
    /* if no input patch is set, then setting a profile is useless,
479
       but there's no reason to cause an error here */
UNCOV
480
    return true;
×
481
}
482

483
bool InputOutputMap::setOutputPatch(quint32 universe, const QString &pluginName,
21✔
484
                                    const QString &outputUID, quint32 output,
485
                                    bool isFeedback, int index)
486
{
487
    /* Check that the universe that we're doing mapping for is valid */
488
    if (universe >= universesCount())
21✔
489
    {
490
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
2✔
491
        return false;
2✔
492
    }
493

494
    QMutexLocker locker(&m_universeMutex);
19✔
495
    QLCIOPlugin *plugin = doc()->ioPluginCache()->plugin(pluginName);
19✔
496

497
    if (!outputUID.isEmpty() && plugin != NULL)
19✔
498
    {
499
        QStringList inputs = plugin->outputs();
12✔
500
        int lIdx = inputs.indexOf(outputUID);
12✔
501
        if (lIdx != -1)
12✔
502
        {
503
            qDebug() << "[IOMAP] Found match on output by name on universe" << universe << "-" << output << "vs" << lIdx;
12✔
504
            output = lIdx;
12✔
505
        }
506
        else
507
        {
UNCOV
508
            qDebug() << "[IOMAP] !!No match found!! for output on universe" << universe << "-" << output << outputUID;
×
UNCOV
509
            qDebug() << plugin->outputs();
×
510
        }
511
    }
12✔
512

513
    if (isFeedback == false)
19✔
514
        return m_universeArray.at(universe)->setOutputPatch(plugin, output, index);
19✔
515
    else
516
        return m_universeArray.at(universe)->setFeedbackPatch(plugin, output);
×
517

518
    return false;
519
}
19✔
520

521
int InputOutputMap::outputPatchesCount(quint32 universe) const
4✔
522
{
523
    if (universe >= universesCount())
4✔
524
    {
525
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
×
526
        return 0;
×
527
    }
528

529
    return m_universeArray.at(universe)->outputPatchesCount();
4✔
530
}
531

532
InputPatch *InputOutputMap::inputPatch(quint32 universe) const
56✔
533
{
534
    if (universe >= universesCount())
56✔
535
    {
536
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
7✔
537
        return NULL;
7✔
538
    }
539
    return m_universeArray.at(universe)->inputPatch();
49✔
540
}
541

542
OutputPatch *InputOutputMap::outputPatch(quint32 universe, int index) const
27✔
543
{
544
    if (universe >= universesCount())
27✔
545
    {
546
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
×
547
        return NULL;
×
548
    }
549
    return m_universeArray.at(universe)->outputPatch(index);
27✔
550
}
551

552
OutputPatch *InputOutputMap::feedbackPatch(quint32 universe) const
2✔
553
{
554
    if (universe >= universesCount())
2✔
555
    {
556
        qWarning() << Q_FUNC_INFO << "Universe" << universe << "out of bounds.";
1✔
557
        return NULL;
1✔
558
    }
559
    return m_universeArray.at(universe)->feedbackPatch();
1✔
560
}
561

562
QStringList InputOutputMap::universeNames() const
23✔
563
{
564
    QStringList list;
23✔
565
    for (quint32 i = 0; i < universesCount(); i++)
115✔
566
        list << m_universeArray.at(i)->name();
92✔
567

568
    return list;
23✔
UNCOV
569
}
×
570

571
quint32 InputOutputMap::inputMapping(const QString &pluginName, quint32 input) const
16✔
572
{
573
    for (quint32 uni = 0; uni < universesCount(); uni++)
70✔
574
    {
575
        const InputPatch* p = m_universeArray.at(uni)->inputPatch();
57✔
576
        if (p != NULL && p->pluginName() == pluginName && p->input() == input)
57✔
577
            return uni;
3✔
578
    }
579

580
    return QLCIOPlugin::invalidLine();
13✔
581
}
582

583
quint32 InputOutputMap::outputMapping(const QString &pluginName, quint32 output) const
2✔
584
{
585
    for (quint32 uni = 0; uni < universesCount(); uni++)
9✔
586
    {
587
        Universe *universe = m_universeArray.at(uni);
8✔
588
        for (int i = 0; i < universe->outputPatchesCount(); i++)
15✔
589
        {
590
            const OutputPatch* p = universe->outputPatch(i);
8✔
591
            if (p != NULL && p->pluginName() == pluginName && p->output() == output)
8✔
592
                return uni;
1✔
593
        }
594
    }
595

596
    return QLCIOPlugin::invalidLine();
1✔
597
}
598

599
/*****************************************************************************
600
 * Plugins
601
 *****************************************************************************/
602

603
QString InputOutputMap::pluginDescription(const QString &pluginName)
2✔
604
{
605
    QLCIOPlugin* plugin = NULL;
2✔
606

607
    if (pluginName.isEmpty() == false)
2✔
608
        plugin = doc()->ioPluginCache()->plugin(pluginName);
2✔
609

610
    if (plugin != NULL)
2✔
611
    {
612
        return plugin->pluginInfo();
1✔
613
    }
614
    else
615
        return "";
1✔
616
}
617

618
void InputOutputMap::removeDuplicates(QStringList &list)
3✔
619
{
620
    if (list.count() == 1)
3✔
UNCOV
621
        return;
×
622

623
    int c = 2;
3✔
624

625
    for (int i = 1; i < list.count(); i++)
12✔
626
    {
627
        for (int j = 0; j < i; j++)
27✔
628
        {
629
            if (list.at(i) == list.at(j))
18✔
630
            {
631
                list.replace(i, QString("%1 %2").arg(list.at(j)).arg(c));
×
632
                c++;
×
633
            }
634
        }
635
    }
636
}
637

638
QStringList InputOutputMap::inputPluginNames()
2✔
639
{
640
    QStringList list;
2✔
641
    QListIterator <QLCIOPlugin*> it(doc()->ioPluginCache()->plugins());
2✔
642
    while (it.hasNext() == true)
4✔
643
    {
644
        QLCIOPlugin* plg(it.next());
2✔
645
        if (plg->capabilities() & QLCIOPlugin::Input)
2✔
646
            list << plg->name();
2✔
647
    }
648
    return list;
4✔
649
}
2✔
650

651
QStringList InputOutputMap::outputPluginNames()
2✔
652
{
653
    QStringList list;
2✔
654
    QListIterator <QLCIOPlugin*> it(doc()->ioPluginCache()->plugins());
2✔
655
    while (it.hasNext() == true)
4✔
656
    {
657
        QLCIOPlugin* plg(it.next());
2✔
658
        if (plg->capabilities() & QLCIOPlugin::Output)
2✔
659
            list << plg->name();
2✔
660
    }
661
    return list;
4✔
662
}
2✔
663

664
QStringList InputOutputMap::pluginInputs(const QString& pluginName)
3✔
665
{
666
    QLCIOPlugin* ip = doc()->ioPluginCache()->plugin(pluginName);
3✔
667
    if (ip == NULL)
3✔
668
        return QStringList();
1✔
669
    else
670
    {
671
        QStringList iList = ip->inputs();
2✔
672
        removeDuplicates(iList);
2✔
673
        return iList;
2✔
674
    }
2✔
675
}
676

677
QStringList InputOutputMap::pluginOutputs(const QString& pluginName)
2✔
678
{
679
    QLCIOPlugin* op = doc()->ioPluginCache()->plugin(pluginName);
2✔
680
    if (op == NULL)
2✔
681
        return QStringList();
1✔
682
    else
683
    {
684
        QStringList oList = op->outputs();
1✔
685
        removeDuplicates(oList);
1✔
686
        return oList;
1✔
687
    }
1✔
688
}
689

690
bool InputOutputMap::pluginSupportsFeedback(const QString& pluginName)
1✔
691
{
692
    QLCIOPlugin* outputPlugin = doc()->ioPluginCache()->plugin(pluginName);
1✔
693
    if (outputPlugin != NULL)
1✔
694
        return (outputPlugin->capabilities() & QLCIOPlugin::Feedback) > 0;
1✔
695
    else
UNCOV
696
        return false;
×
697
}
698

699
void InputOutputMap::configurePlugin(const QString& pluginName)
3✔
700
{
701
    QLCIOPlugin* outputPlugin = doc()->ioPluginCache()->plugin(pluginName);
3✔
702
    if (outputPlugin != NULL)
3✔
703
        outputPlugin->configure();
3✔
704
}
3✔
705

706
bool InputOutputMap::canConfigurePlugin(const QString& pluginName)
4✔
707
{
708
    QLCIOPlugin* outputPlugin = doc()->ioPluginCache()->plugin(pluginName);
4✔
709
    if (outputPlugin != NULL)
4✔
710
        return outputPlugin->canConfigure();
2✔
711
    else
712
        return false;
2✔
713
}
714

715
QString InputOutputMap::inputPluginStatus(const QString& pluginName, quint32 input)
9✔
716
{
717
    QLCIOPlugin* inputPlugin = NULL;
9✔
718
    QString info;
9✔
719

720
    if (pluginName.isEmpty() == false)
9✔
721
        inputPlugin = doc()->ioPluginCache()->plugin(pluginName);
9✔
722

723
    if (inputPlugin != NULL)
9✔
724
    {
725
        info = inputPlugin->inputInfo(input);
4✔
726
    }
727
    else
728
    {
729
        /* Nothing selected */
730
        info += QString("<HTML><HEAD></HEAD><BODY>");
5✔
731
        info += QString("<H3>%1</H3>").arg(tr("Nothing selected"));
5✔
732
        info += QString("</BODY></HTML>");
5✔
733
    }
734

735
    return info;
9✔
736
}
×
737

738
QString InputOutputMap::outputPluginStatus(const QString& pluginName, quint32 output)
9✔
739
{
740
    QLCIOPlugin* outputPlugin = doc()->ioPluginCache()->plugin(pluginName);
9✔
741
    if (outputPlugin != NULL)
9✔
742
    {
743
        return outputPlugin->outputInfo(output);
4✔
744
    }
745
    else
746
    {
747
        QString info;
5✔
748
        info += QString("<HTML><HEAD></HEAD><BODY>");
5✔
749
        info += QString("<H3>%1</H3>").arg(tr("Nothing selected"));
5✔
750
        info += QString("</BODY></HTML>");
5✔
751
        return info;
5✔
752
    }
5✔
753
}
754

755
bool InputOutputMap::sendFeedBack(quint32 universe, quint32 channel, uchar value, const QVariant &params)
12✔
756
{
757
    if (universe >= universesCount())
12✔
758
        return false;
3✔
759

760
    OutputPatch* patch = m_universeArray.at(universe)->feedbackPatch();
9✔
761

762
    if (patch != NULL && patch->isPatched())
9✔
763
    {
764
        patch->plugin()->sendFeedBack(universe, patch->output(), channel, value, params);
×
765
        return true;
×
766
    }
767
    else
768
    {
769
        return false;
9✔
770
    }
771
}
772

773
void InputOutputMap::slotPluginConfigurationChanged(QLCIOPlugin* plugin)
8✔
774
{
775
    QMutexLocker locker(&m_universeMutex);
8✔
776
    bool success = true;
8✔
777
    for (quint32 i = 0; i < universesCount(); i++)
40✔
778
    {
779
        Universe *universe = m_universeArray.at(i);
32✔
780
        for (int oi = 0; oi < universe->outputPatchesCount(); oi++)
32✔
781
        {
782
            OutputPatch* op = universe->outputPatch(oi);
×
783

784
            if (op != NULL && op->plugin() == plugin)
×
785
            {
786
                /*success = */ op->reconnect();
×
787
            }
788
        }
789

790
        InputPatch* ip = m_universeArray.at(i)->inputPatch();
32✔
791

792
        if (ip != NULL && ip->plugin() == plugin)
32✔
793
        {
794
            /*success = */ ip->reconnect();
×
795
        }
796

797
        OutputPatch* fp = m_universeArray.at(i)->feedbackPatch();
32✔
798
        if (fp != NULL && fp->plugin() == plugin)
32✔
799
        {
800
            /*success = */ fp->reconnect();
×
801
        }
802
    }
803
    locker.unlock();
8✔
804

805
    emit pluginConfigurationChanged(plugin->name(), success);
8✔
806
}
8✔
807

808
/*****************************************************************************
809
 * Profiles
810
 *****************************************************************************/
811

812
void InputOutputMap::loadProfiles(const QDir& dir)
5✔
813
{
814
    if (dir.exists() == false || dir.isReadable() == false)
5✔
815
        return;
1✔
816

817
    /* Go thru all found file entries and attempt to load an input
818
       profile from each of them. */
819
    QStringListIterator it(dir.entryList());
4✔
820
    while (it.hasNext() == true)
121✔
821
    {
822
        QLCInputProfile* prof;
823
        QString path;
117✔
824

825
        path = dir.absoluteFilePath(it.next());
117✔
826
        prof = QLCInputProfile::loader(path);
117✔
827
        if (prof != NULL)
117✔
828
        {
829
            /* Check for duplicates */
830
            if (profile(prof->name()) == NULL)
117✔
831
                addProfile(prof);
78✔
832
            else
833
                delete prof;
39✔
834
        }
835
        else
836
        {
837
            qWarning() << Q_FUNC_INFO << "Unable to find an input profile from" << path;
×
838
        }
839
    }
117✔
840
}
4✔
841

842
QStringList InputOutputMap::profileNames()
7✔
843
{
844
    QStringList list;
7✔
845
    QListIterator <QLCInputProfile*> it(m_profiles);
7✔
846
    while (it.hasNext() == true)
87✔
847
        list << it.next()->name();
80✔
848
    return list;
14✔
849
}
7✔
850

851
QLCInputProfile* InputOutputMap::profile(const QString& name)
125✔
852
{
853
    QListIterator <QLCInputProfile*> it(m_profiles);
125✔
854
    while (it.hasNext() == true)
2,403✔
855
    {
856
        QLCInputProfile* profile = it.next();
2,321✔
857
        if (profile->name() == name)
2,321✔
858
            return profile;
43✔
859
    }
860

861
    return NULL;
82✔
862
}
125✔
863

864
bool InputOutputMap::addProfile(QLCInputProfile* profile)
81✔
865
{
866
    Q_ASSERT(profile != NULL);
81✔
867

868
    /* Don't add the same profile twice */
869
    if (m_profiles.contains(profile) == false)
81✔
870
    {
871
        m_profiles.append(profile);
80✔
872
        return true;
80✔
873
    }
874
    else
875
    {
876
        return false;
1✔
877
    }
878
}
879

880
bool InputOutputMap::removeProfile(const QString& name)
2✔
881
{
882
    QMutableListIterator <QLCInputProfile*> it(m_profiles);
2✔
883
    while (it.hasNext() == true)
3✔
884
    {
885
        QLCInputProfile *profile = it.next();
2✔
886
        if (profile->name() == name)
2✔
887
        {
888
            it.remove();
1✔
889
            delete profile;
1✔
890
            return true;
1✔
891
        }
892
    }
893

894
    return false;
1✔
895
}
896

897
bool InputOutputMap::inputSourceNames(const QLCInputSource *src,
8✔
898
                                QString& uniName, QString& chName) const
899
{
900
    if (src == NULL || src->isValid() == false)
8✔
901
        return false;
3✔
902

903
    if (src->universe() >= universesCount())
5✔
904
        return false;
1✔
905

906
    InputPatch* pat = m_universeArray.at(src->universe())->inputPatch();
4✔
907
    if (pat == NULL)
4✔
908
    {
909
        /* There is no patch for the given universe */
910
        uniName = QString("%1 -UNPATCHED-").arg(src->universe() + 1);
1✔
911

912
        ushort page = src->page();
1✔
913
        ushort channel = (src->channel() & 0x0000FFFF) + 1;
1✔
914

915
        if (page != 0)
1✔
916
            chName = QString("%1: ? (Page %2)").arg(channel).arg(page + 1);
×
917
        else
918
            chName = QString("%1: ?").arg(channel);
1✔
919
        return true;
1✔
920
    }
921

922
    QLCInputProfile* profile = pat->profile();
3✔
923
    if (profile == NULL)
3✔
924
    {
925
        /* There is no profile. Display plugin name and channel number. */
926
        if (pat->plugin() != NULL)
1✔
927
            uniName = QString("%1: %2").arg(src->universe() + 1).arg(pat->plugin()->name());
1✔
928
        else
929
            uniName = QString("%1: ??").arg(src->universe() + 1);
×
930

931
        ushort page = src->page();
1✔
932
        ushort channel = (src->channel() & 0x0000FFFF) + 1;
1✔
933

934
        if (page != 0)
1✔
935
            chName = QString("%1: ? (Page %2)").arg(channel).arg(page + 1);
×
936
        else
937
            chName = QString("%1: ?").arg(channel);
1✔
938
    }
939
    else
940
    {
941
        QLCInputChannel* ich;
942
        QString name;
2✔
943

944
        /* Display profile name for universe */
945
        uniName = QString("%1: %2").arg(src->universe() + 1).arg(profile->name());
2✔
946

947
        /* User can input the channel number by hand, so put something
948
           rational to the channel name in those cases as well. */
949
        ushort page = src->page();
2✔
950
        ushort channel = (src->channel() & 0x0000FFFF);
2✔
951

952
        ich = profile->channel(channel);
2✔
953
        if (ich != NULL)
2✔
954
            name = ich->name();
1✔
955
        else
956
            name = QString("?");
1✔
957

958
        /* Display channel name */
959
        if (page != 0)
2✔
960
            chName = QString("%1: %2 (Page %3)").arg(channel + 1).arg(name).arg(page + 1);
×
961
        else
962
            chName = QString("%1: %2").arg(channel + 1).arg(name);
2✔
963
    }
2✔
964

965
    return true;
3✔
966
}
967

968
bool InputOutputMap::inputSourceNames(QSharedPointer<QLCInputSource> const& src,
×
969
                                QString& uniName, QString& chName) const
970
{
971
    return inputSourceNames(src.data(), uniName, chName);
×
972
}
973

974
QDir InputOutputMap::systemProfileDirectory()
1✔
975
{
976
    return QLCFile::systemDirectory(QString(INPUTPROFILEDIR), QString(KExtInputProfile));
2✔
977
}
978

979
QDir InputOutputMap::userProfileDirectory()
1✔
980
{
981
    return QLCFile::userDirectory(QString(USERINPUTPROFILEDIR), QString(INPUTPROFILEDIR),
2✔
982
                                  QStringList() << QString("*%1").arg(KExtInputProfile));
3✔
983
}
984

985
/*********************************************************************
986
 * Beats
987
 *********************************************************************/
988

989
void InputOutputMap::setBeatGeneratorType(InputOutputMap::BeatGeneratorType type)
×
990
{
991
    if (type == m_beatGeneratorType)
×
UNCOV
992
        return;
×
993

994
    m_beatGeneratorType = type;
×
UNCOV
995
    qDebug() << "[InputOutputMap] setting beat type:" << m_beatGeneratorType;
×
996

997
    switch (m_beatGeneratorType)
×
998
    {
999
        case Internal:
×
1000
            doc()->masterTimer()->setBeatSourceType(MasterTimer::Internal);
×
1001
            setBpmNumber(doc()->masterTimer()->bpmNumber());
×
1002
        break;
×
1003
        case Plugin:
×
1004
            doc()->masterTimer()->setBeatSourceType(MasterTimer::External);
×
1005
            // reset the current BPM number and detect it from the MIDI beats
1006
            setBpmNumber(0);
×
1007
            m_beatTime->restart();
×
1008
        break;
×
1009
        case Audio:
×
1010
            doc()->masterTimer()->setBeatSourceType(MasterTimer::External);
×
1011
            // reset the current BPM number and detect it from the audio input
1012
            setBpmNumber(0);
×
1013
            m_beatTime->restart();
×
1014
        break;
×
1015
        case Disabled:
×
1016
        default:
1017
            doc()->masterTimer()->setBeatSourceType(MasterTimer::None);
×
1018
            setBpmNumber(0);
×
1019
        break;
×
1020
    }
1021

1022
    emit beatGeneratorTypeChanged();
×
1023
}
1024

1025
InputOutputMap::BeatGeneratorType InputOutputMap::beatGeneratorType() const
×
1026
{
1027
    return m_beatGeneratorType;
×
1028
}
1029

1030
QString InputOutputMap::beatTypeToString(BeatGeneratorType type) const
1✔
1031
{
1032
    switch (type)
1✔
1033
    {
1034
        case Internal:  return "Internal";
×
1035
        case Plugin:    return "Plugin";
×
1036
        case Audio:     return "Audio";
×
1037
        default:        return "Disabled";
1✔
1038
    }
1039
}
1040

1041
InputOutputMap::BeatGeneratorType InputOutputMap::stringToBeatType(QString str)
×
1042
{
1043
    if (str == "Internal")
×
UNCOV
1044
        return Internal;
×
1045
    else if (str == "Plugin")
×
UNCOV
1046
        return Plugin;
×
1047
    else if (str == "Audio")
×
1048
        return Audio;
×
1049

UNCOV
1050
    return Disabled;
×
1051
}
1052

1053
void InputOutputMap::setBpmNumber(int bpm)
×
1054
{
1055
    if (m_beatGeneratorType == Disabled || bpm == m_currentBPM)
×
UNCOV
1056
        return;
×
1057

1058
    //qDebug() << "[InputOutputMap] set BPM to" << bpm;
1059
    m_currentBPM = bpm;
×
1060

1061
    if (bpm != 0)
×
1062
        doc()->masterTimer()->requestBpmNumber(bpm);
×
1063

1064
    emit bpmNumberChanged(m_currentBPM);
×
1065
}
1066

1067
int InputOutputMap::bpmNumber() const
×
1068
{
1069
    if (m_beatGeneratorType == Disabled)
×
UNCOV
1070
        return 0;
×
1071

1072
    return m_currentBPM;
×
1073
}
1074

1075
void InputOutputMap::slotMasterTimerBeat()
×
1076
{
1077
    if (m_beatGeneratorType != Internal)
×
UNCOV
1078
        return;
×
1079

1080
    emit beat();
×
1081
}
1082

1083
void InputOutputMap::slotPluginBeat(quint32 universe, quint32 channel, uchar value, const QString &key)
×
1084
{
1085
    Q_UNUSED(universe)
1086

1087
    // not interested in synthetic release or non-beat event
1088
    if (m_beatGeneratorType != Plugin || value == 0 || key != "beat")
×
1089
        return;
×
1090

UNCOV
1091
    qDebug() << "Plugin beat:" << channel << m_beatTime->elapsed();
×
1092

1093
    // process the timer as first thing, to avoid wasting time
1094
    // with the operations below
1095
    int elapsed = m_beatTime->elapsed();
×
1096
    m_beatTime->restart();
×
1097

1098
    int bpm = qRound(60000.0 / (float)elapsed);
×
1099
    float currBpmTime = 60000.0 / (float)m_currentBPM;
×
1100
    // here we check if the difference between the current BPM duration
1101
    // and the current time elapsed is within a range of +/-1ms.
1102
    // If it isn't, then the BPM number has really changed, otherwise
1103
    // it's just a tiny time drift
1104
    if (qAbs((float)elapsed - currBpmTime) > 1)
×
1105
        setBpmNumber(bpm);
×
1106

1107
    doc()->masterTimer()->requestBeat();
×
1108
    emit beat();
×
1109
}
1110

1111
void InputOutputMap::slotAudioSpectrum(double *spectrumBands, int size, double maxMagnitude, quint32 power)
×
1112
{
1113
    Q_UNUSED(spectrumBands)
1114
    Q_UNUSED(size)
1115
    Q_UNUSED(maxMagnitude)
1116
    Q_UNUSED(power)
1117
}
×
1118

1119
/*********************************************************************
1120
 * Defaults - !! FALLBACK !!
1121
 *********************************************************************/
1122

1123
void InputOutputMap::loadDefaults()
×
1124
{
1125
    /* ************************ INPUT *********************************** */
1126
    QSettings settings;
×
UNCOV
1127
    QString plugin;
×
UNCOV
1128
    QString input;
×
UNCOV
1129
    QString key;
×
1130

1131
    for (quint32 i = 0; i < universesCount(); i++)
×
1132
    {
UNCOV
1133
        QString profileName;
×
1134
        bool passthrough;
1135

1136
        /* Plugin name */
1137
        key = QString("/inputmap/universe%1/plugin/").arg(i);
×
1138
        plugin = settings.value(key).toString();
×
1139

1140
        /* Plugin input */
1141
        key = QString("/inputmap/universe%1/input/").arg(i);
×
1142
        input = settings.value(key).toString();
×
1143

1144
        /* Input profile */
1145
        key = QString("/inputmap/universe%1/profile/").arg(i);
×
1146
        profileName = settings.value(key).toString();
×
1147

1148
        key = QString("/inputmap/universe%1/passthrough/").arg(i);
×
1149
        passthrough = settings.value(key).toBool();
×
1150
        if (passthrough == true)
×
1151
            m_universeArray.at(i)->setPassthrough(passthrough);
×
1152

1153
        /* Do the mapping */
1154
        if (plugin != KInputNone && input != KInputNone)
×
1155
            setInputPatch(i, plugin, "", input.toUInt(), profileName);
×
1156
    }
×
1157

1158
    /* ************************ OUTPUT *********************************** */
UNCOV
1159
    QString output;
×
UNCOV
1160
    QString fb_plugin;
×
UNCOV
1161
    QString feedback;
×
1162

1163
    for (quint32 i = 0; i < universesCount(); i++)
×
1164
    {
1165
        /* Plugin name */
1166
        key = QString("/outputmap/universe%1/plugin/").arg(i);
×
1167
        plugin = settings.value(key).toString();
×
1168

1169
        /* Plugin output */
1170
        key = QString("/outputmap/universe%1/output/").arg(i);
×
1171
        output = settings.value(key).toString();
×
1172

1173
        /* Feedback plugin name */
1174
        key = QString("/outputmap/universe%1/feedbackplugin/").arg(i);
×
1175
        fb_plugin = settings.value(key).toString();
×
1176

1177
        /* Feedback line */
1178
        key = QString("/outputmap/universe%1/feedback/").arg(i);
×
1179
        feedback = settings.value(key).toString();
×
1180

1181
        if (plugin != KOutputNone && output != KOutputNone)
×
1182
            setOutputPatch(i, plugin, "", output.toUInt());
×
1183

1184
        if (fb_plugin != KOutputNone && feedback != KOutputNone)
×
1185
            setOutputPatch(i, fb_plugin, "", feedback.toUInt(), true);
×
1186
    }
1187
}
×
1188

1189
void InputOutputMap::saveDefaults()
×
1190
{
1191
    /* ************************ INPUT *********************************** */
1192
    QSettings settings;
×
UNCOV
1193
    QString key;
×
1194

1195
    for (quint32 i = 0; i < universesCount(); i++)
×
1196
    {
1197
        InputPatch* inPatch = inputPatch(i);
×
1198

1199
        /* Plugin name */
1200
        key = QString("/inputmap/universe%1/plugin/").arg(i);
×
1201
        if (inPatch != NULL)
×
1202
            settings.setValue(key, inPatch->pluginName());
×
1203
        else
1204
            settings.setValue(key, KInputNone);
×
1205

1206
        /* Plugin input */
1207
        key = QString("/inputmap/universe%1/input/").arg(i);
×
1208
        if (inPatch != NULL)
×
1209
            settings.setValue(key, QString::number(inPatch->input()));
×
1210
        else
1211
            settings.setValue(key, KInputNone);
×
1212

1213
        /* Input profile */
1214
        key = QString("/inputmap/universe%1/profile/").arg(i);
×
1215
        if (inPatch != NULL)
×
1216
            settings.setValue(key, inPatch->profileName());
×
1217
        else
1218
            settings.setValue(key, KInputNone);
×
1219

1220
        /* Passthrough */
1221
        key = QString("/inputmap/universe%1/passthrough/").arg(i);
×
1222
        bool passthrough = m_universeArray.at(i)->passthrough();
×
1223
        if (passthrough == true)
×
1224
            settings.setValue(key, passthrough);
×
1225
        else
1226
            settings.remove(key);
×
1227
    }
1228

1229
    /* ************************ OUTPUT *********************************** */
1230

1231
    for (quint32 i = 0; i < universesCount(); i++)
×
1232
    {
1233
        OutputPatch* outPatch = outputPatch(i);
×
1234
        OutputPatch* fbPatch = feedbackPatch(i);
×
1235

1236
        key = QString("/outputmap/universe%1/plugin/").arg(i);
×
1237

1238
        /* Plugin name */
1239
        if (outPatch != NULL)
×
1240
            settings.setValue(key, outPatch->pluginName());
×
1241
        else
1242
            settings.setValue(key, KOutputNone);
×
1243

1244
        /* Plugin output */
1245
        key = QString("/outputmap/universe%1/output/").arg(i);
×
1246
        if (outPatch != NULL)
×
1247
            settings.setValue(key, outPatch->output());
×
1248
        else
1249
            settings.setValue(key, KOutputNone);
×
1250

1251
        key = QString("/outputmap/universe%1/feedbackplugin/").arg(i);
×
1252

1253
        /* Feedback plugin name */
1254
        if (fbPatch != NULL)
×
1255
            settings.setValue(key, fbPatch->pluginName());
×
1256
        else
1257
            settings.setValue(key, KOutputNone);
×
1258

1259
        /* Feedback plugin output */
1260
        key = QString("/outputmap/universe%1/feedback/").arg(i);
×
1261
        if (fbPatch != NULL)
×
1262
            settings.setValue(key, QString::number(fbPatch->output()));
×
1263
        else
1264
            settings.setValue(key, KOutputNone);
×
1265
    }
1266
}
×
1267

1268
/*********************************************************************
1269
 * Load & Save
1270
 *********************************************************************/
1271

1272
bool InputOutputMap::loadXML(QXmlStreamReader &root)
×
1273
{
1274
    if (root.name() != KXMLIOMap)
×
1275
    {
1276
        qWarning() << Q_FUNC_INFO << "InputOutputMap node not found";
×
1277
        return false;
×
1278
    }
1279

1280
    /** Reset the current universe list and read the new one */
1281
    removeAllUniverses();
×
1282

1283
    while (root.readNextStartElement())
×
1284
    {
1285
        if (root.name() == KXMLQLCUniverse)
×
1286
        {
1287
            quint32 id = InputOutputMap::invalidUniverse();
×
1288
            if (root.attributes().hasAttribute(KXMLQLCUniverseID))
×
1289
                id = root.attributes().value(KXMLQLCUniverseID).toString().toUInt();
×
1290
            if (addUniverse(id))
×
1291
            {
1292
                Universe *uni = m_universeArray.last();
×
1293
                uni->loadXML(root, m_universeArray.count() - 1, this);
×
1294
            }
1295
        }
1296
        else if (root.name() == KXMLIOBeatGenerator)
×
1297
        {
1298
            QXmlStreamAttributes attrs = root.attributes();
×
1299

1300
            if (attrs.hasAttribute(KXMLIOBeatType))
×
1301
                setBeatGeneratorType(stringToBeatType(attrs.value(KXMLIOBeatType).toString()));
×
1302

1303
            if (attrs.hasAttribute(KXMLIOBeatsPerMinute))
×
1304
                setBpmNumber(attrs.value(KXMLIOBeatsPerMinute).toInt());
×
1305

1306
            root.skipCurrentElement();
×
UNCOV
1307
        }
×
1308
        else
1309
        {
1310
            qWarning() << Q_FUNC_INFO << "Unknown IO Map tag:" << root.name();
×
1311
            root.skipCurrentElement();
×
1312
        }
1313
    }
1314

UNCOV
1315
    return true;
×
1316
}
1317

1318
bool InputOutputMap::saveXML(QXmlStreamWriter *doc) const
1✔
1319
{
1320
    Q_ASSERT(doc != NULL);
1✔
1321

1322
    /* IO Map Instance entry */
1323
    doc->writeStartElement(KXMLIOMap);
2✔
1324

1325
    doc->writeStartElement(KXMLIOBeatGenerator);
2✔
1326
    doc->writeAttribute(KXMLIOBeatType, beatTypeToString(m_beatGeneratorType));
2✔
1327
    doc->writeAttribute(KXMLIOBeatsPerMinute, QString::number(m_currentBPM));
2✔
1328
    doc->writeEndElement();
1✔
1329

1330
    foreach (Universe *uni, m_universeArray)
5✔
1331
        uni->saveXML(doc);
5✔
1332

1333
    doc->writeEndElement();
1✔
1334

1335
    return true;
1✔
1336
}
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