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

mcallegari / qlcplus / 13633248611

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

push

github

web-flow
actions: add chrpath to profile

14689 of 46089 relevant lines covered (31.87%)

26426.11 hits per line

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

73.88
/engine/src/qlcinputprofile.cpp
1
/*
2
  Q Light Controller
3
  qlcinputprofile.cpp
4

5
  Copyright (c) Heikki Junnila
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
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QString>
23
#include <QDebug>
24
#include <QMap>
25

26
#include "qlcinputchannel.h"
27
#include "qlcinputprofile.h"
28
#include "qlcchannel.h"
29
#include "qlcfile.h"
30

31
#define KXMLQLCInputProfileTypeMidi "MIDI"
32
#define KXMLQLCInputProfileTypeOs2l "OS2L"
33
#define KXMLQLCInputProfileTypeOsc "OSC"
34
#define KXMLQLCInputProfileTypeHid "HID"
35
#define KXMLQLCInputProfileTypeDmx "DMX"
36
#define KXMLQLCInputProfileTypeEnttec "Enttec"
37

38
#define KXMLQLCInputProfileValue "Value"
39
#define KXMLQLCInputProfileLabel "Label"
40
#define KXMLQLCInputProfileColorRGB "RGB"
41

42
/****************************************************************************
43
 * Initialization
44
 ****************************************************************************/
45

46
QLCInputProfile::QLCInputProfile()
136✔
47
    : m_manufacturer(QString())
48
    , m_model(QString())
49
    , m_path(QString())
50
    , m_type(MIDI)
136✔
51
    , m_midiSendNoteOff(true)
136✔
52
{
53
}
136✔
54

55
QLCInputProfile::~QLCInputProfile()
97✔
56
{
57
    destroyChannels();
57✔
58
}
97✔
59

60
QLCInputProfile *QLCInputProfile::createCopy()
1✔
61
{
62
    QLCInputProfile *copy = new QLCInputProfile();
1✔
63
    copy->setManufacturer(this->manufacturer());
1✔
64
    copy->setModel(this->model());
1✔
65
    copy->setType(this->type());
1✔
66
    copy->setPath(this->path());
1✔
67
    copy->setMidiSendNoteOff(this->midiSendNoteOff());
1✔
68

69
    /* Copy the other profile's channels */
70
    QMapIterator <quint32,QLCInputChannel*> it(this->channels());
1✔
71
    while (it.hasNext() == true)
5✔
72
    {
73
        it.next();
4✔
74
        copy->insertChannel(it.key(), it.value()->createCopy());
4✔
75
    }
76

77
    /* Copy the other profile's color table */
78
    QMapIterator <uchar, QPair<QString, QColor>> it2(this->colorTable());
1✔
79
    while (it2.hasNext() == true)
1✔
80
    {
81
        it2.next();
×
82
        QPair<QString, QColor> lc = it2.value();
83
        copy->addColor(it2.key(), lc.first, lc.second);
×
84
    }
85

86
    /* Copy the other profile's MIDI channel tabel */
87
    QMapIterator <uchar, QString> it3(this->midiChannelTable());
1✔
88
    while (it3.hasNext() == true)
1✔
89
    {
90
        it3.next();
×
91
        copy->addMidiChannel(it3.key(), it3.value());
×
92
    }
93

94
    return copy;
1✔
95
}
96

97
QLCInputProfile& QLCInputProfile::operator=(const QLCInputProfile& profile)
1✔
98
{
99
    if (this != &profile)
1✔
100
    {
101
        /* Copy basic properties */
102
        m_manufacturer = profile.m_manufacturer;
1✔
103
        m_model = profile.m_model;
1✔
104
        m_path = profile.m_path;
1✔
105
        m_type = profile.m_type;
1✔
106
        m_midiSendNoteOff = profile.m_midiSendNoteOff;
1✔
107
        m_globalSettingsMap = profile.m_globalSettingsMap;
1✔
108

109
        /* Destroy all existing channels */
110
        destroyChannels();
1✔
111

112
        /* Copy the other profile's channels */
113
        QMapIterator <quint32, QLCInputChannel*> it(profile.m_channels);
1✔
114
        while (it.hasNext() == true)
5✔
115
        {
116
            it.next();
4✔
117
            insertChannel(it.key(), it.value()->createCopy());
4✔
118
        }
119

120
        /* Copy the other profile's color table */
121
        QMapIterator <uchar, QPair<QString, QColor>> it2(profile.m_colorTable);
1✔
122
        while (it2.hasNext() == true)
1✔
123
        {
124
            it2.next();
×
125
            QPair<QString, QColor> lc = it2.value();
126
            addColor(it2.key(), lc.first, lc.second);
×
127
        }
128

129
        /* Copy the other profile's MIDI channel tabel */
130
        QMapIterator <uchar, QString> it3(profile.m_midiChannelTable);
1✔
131
        while (it3.hasNext() == true)
1✔
132
        {
133
            it3.next();
×
134
            addMidiChannel(it3.key(), it3.value());
×
135
        }
136
    }
137

138
    return *this;
1✔
139
}
140

141
/****************************************************************************
142
 * profile information
143
 ****************************************************************************/
144

145
void QLCInputProfile::setManufacturer(const QString& manufacturer)
129✔
146
{
147
    m_manufacturer = manufacturer;
129✔
148
}
129✔
149

150
QString QLCInputProfile::manufacturer() const
7✔
151
{
152
    return m_manufacturer;
7✔
153
}
154

155
void QLCInputProfile::setModel(const QString& model)
125✔
156
{
157
    m_model = model;
125✔
158
}
125✔
159

160
QString QLCInputProfile::model() const
7✔
161
{
162
    return m_model;
7✔
163
}
164

165
QString QLCInputProfile::name() const
2,422✔
166
{
167
    return QString("%1 %2").arg(m_manufacturer).arg(m_model);
2,422✔
168
}
169

170
void QLCInputProfile::setPath(QString path)
1✔
171
{
172
    m_path = path;
1✔
173
}
1✔
174

175
QString QLCInputProfile::path() const
2✔
176
{
177
    return m_path;
2✔
178
}
179

180
void QLCInputProfile::setType(QLCInputProfile::Type type)
117✔
181
{
182
    m_type = type;
117✔
183
}
117✔
184

185
QLCInputProfile::Type QLCInputProfile::type() const
1✔
186
{
187
    return m_type;
1✔
188
}
189

190
QString QLCInputProfile::typeToString(Type type)
1✔
191
{
192
    switch (type)
1✔
193
    {
194
    case MIDI:
1✔
195
        return KXMLQLCInputProfileTypeMidi;
1✔
196
    case OS2L:
×
197
        return KXMLQLCInputProfileTypeOs2l;
×
198
    case OSC:
×
199
        return KXMLQLCInputProfileTypeOsc;
×
200
    case HID:
×
201
        return KXMLQLCInputProfileTypeHid;
×
202
    case DMX:
×
203
        return KXMLQLCInputProfileTypeDmx;
×
204
    case Enttec:
×
205
        return KXMLQLCInputProfileTypeEnttec;
×
206
    default:
207
        return QString();
208
    }
209
}
210

211
QLCInputProfile::Type QLCInputProfile::stringToType(const QString& str)
116✔
212
{
213
    if (str == KXMLQLCInputProfileTypeMidi)
116✔
214
        return MIDI;
215
    else if (str == KXMLQLCInputProfileTypeOs2l)
18✔
216
        return OS2L;
217
    else if (str == KXMLQLCInputProfileTypeOsc)
18✔
218
        return OSC;
219
    else if (str == KXMLQLCInputProfileTypeHid)
9✔
220
        return HID;
221
    else if (str == KXMLQLCInputProfileTypeDmx)
6✔
222
        return DMX;
223
    else // if (str == KXMLQLCInputProfileTypeEnttec)
224
        return Enttec;
6✔
225
}
226

227
QList<QLCInputProfile::Type> QLCInputProfile::types()
×
228
{
229
    QList<Type> result;
230
    result
231
        << MIDI
×
232
        << OS2L
×
233
        << OSC
×
234
        << HID
×
235
        << DMX
×
236
        << Enttec;
×
237
    return result;
×
238
}
×
239

240
/********************************************************************
241
 * Plugin-specific global settings
242
 ********************************************************************/
243

244
void QLCInputProfile::setMidiSendNoteOff(bool enable)
19✔
245
{
246
    m_midiSendNoteOff = enable;
19✔
247
    m_globalSettingsMap["MIDISendNoteOff"] = QVariant(enable);
38✔
248
}
19✔
249

250
bool QLCInputProfile::midiSendNoteOff() const
2✔
251
{
252
    return m_midiSendNoteOff;
2✔
253
}
254

255
QMap<QString, QVariant> QLCInputProfile::globalSettings() const
5✔
256
{
257
    return m_globalSettingsMap;
5✔
258
}
259

260
/****************************************************************************
261
 * Channels
262
 ****************************************************************************/
263

264
bool QLCInputProfile::insertChannel(quint32 channel,
12,451✔
265
                                    QLCInputChannel* ich)
266
{
267
    if (ich != NULL && m_channels.contains(channel) == false)
12,451✔
268
    {
269
        m_channels.insert(channel, ich);
12,450✔
270
        return true;
12,450✔
271
    }
272
    else
273
    {
274
        return false;
275
    }
276
}
277

278
bool QLCInputProfile::removeChannel(quint32 channel)
6✔
279
{
280
    if (m_channels.contains(channel) == true)
6✔
281
    {
282
        QLCInputChannel* ich = m_channels.take(channel);
2✔
283
        Q_ASSERT(ich != NULL);
284
        delete ich;
2✔
285
        return true;
2✔
286
    }
287
    else
288
    {
289
        return false;
290
    }
291
}
292

293
bool QLCInputProfile::remapChannel(QLCInputChannel* ich, quint32 number)
3✔
294
{
295
    if (ich == NULL)
3✔
296
        return false;
297

298
    quint32 old = channelNumber(ich);
2✔
299
    if (old != QLCChannel::invalid() && m_channels.contains(number) == false)
2✔
300
    {
301
        m_channels.take(old);
1✔
302
        insertChannel(number, ich);
1✔
303
        return true;
1✔
304
    }
305
    else
306
    {
307
        return false;
308
    }
309
}
310

311
QLCInputChannel* QLCInputProfile::channel(quint32 channel) const
75✔
312
{
313
    if (m_channels.contains(channel) == true)
75✔
314
        return m_channels[channel];
60✔
315
    else
316
        return NULL;
317
}
318

319
quint32 QLCInputProfile::channelNumber(const QLCInputChannel* channel) const
6✔
320
{
321
    if (channel == NULL)
6✔
322
        return QLCChannel::invalid();
1✔
323

324
    QMapIterator <quint32,QLCInputChannel*> it(m_channels);
5✔
325
    while (it.hasNext() == true)
10✔
326
    {
327
        it.next();
9✔
328
        if (it.value() == channel)
9✔
329
            return it.key();
4✔
330
    }
331

332
    return QLCChannel::invalid();
1✔
333
}
334

335
QMap <quint32,QLCInputChannel*> QLCInputProfile::channels() const
30✔
336
{
337
    return m_channels;
30✔
338
}
339

340
QVariant QLCInputProfile::channelExtraParams(const QLCInputChannel* channel) const
×
341
{
342
    if (channel == NULL)
×
343
        return QVariant();
344

345
    switch (m_type)
×
346
    {
347
        case OSC: return channel->name();
×
348
        case MIDI: return channel->lowerChannel();
×
349
        default: return QVariant();
350
    }
351
}
352

353
void QLCInputProfile::destroyChannels()
58✔
354
{
355
    /* Delete existing channels but leave the pointers there */
356
    QMutableMapIterator <quint32,QLCInputChannel*> it(m_channels);
58✔
357
    while (it.hasNext() == true)
4,141✔
358
        delete it.next().value();
4,083✔
359

360
    /* Clear the list of freed pointers */
361
    m_channels.clear();
58✔
362
}
58✔
363

364
bool QLCInputProfile::hasColorTable()
1✔
365
{
366
    return m_colorTable.isEmpty() ? false : true;
1✔
367
}
368

369
void QLCInputProfile::addColor(uchar value, QString label, QColor color)
861✔
370
{
371
    QPair<QString, QColor> lc;
372
    lc.first = label;
861✔
373
    lc.second = color;
861✔
374
    m_colorTable.insert(value, lc);
861✔
375
}
861✔
376

377
void QLCInputProfile::removeColor(uchar value)
×
378
{
379
    m_colorTable.remove(value);
×
380
}
×
381

382
QMap<uchar, QPair<QString, QColor> > QLCInputProfile::colorTable()
1✔
383
{
384
    return m_colorTable;
1✔
385
}
386

387
/********************************************************************
388
 * MIDI Channel table
389
 ********************************************************************/
390

391
bool QLCInputProfile::hasMidiChannelTable()
1✔
392
{
393
    return m_midiChannelTable.isEmpty() ? false : true;
1✔
394
}
395

396
void QLCInputProfile::addMidiChannel(uchar channel, QString label)
57✔
397
{
398
    m_midiChannelTable.insert(channel, label);
57✔
399
}
57✔
400

401
void QLCInputProfile::removeMidiChannel(uchar channel)
×
402
{
403
    m_midiChannelTable.remove(channel);
×
404
}
×
405

406
QMap<uchar, QString> QLCInputProfile::midiChannelTable()
1✔
407
{
408
    return m_midiChannelTable;
1✔
409
}
410

411
/****************************************************************************
412
 * Load & Save
413
 ****************************************************************************/
414

415
QLCInputProfile* QLCInputProfile::loader(const QString& path)
118✔
416
{
417
    QXmlStreamReader *doc = QLCFile::getXMLReader(path);
118✔
418
    if (doc == NULL || doc->device() == NULL || doc->hasError())
234✔
419
    {
420
        qWarning() << Q_FUNC_INFO << "Unable to load input profile from" << path;
2✔
421
        return NULL;
2✔
422
    }
423

424
    QLCInputProfile* profile = new QLCInputProfile();
116✔
425
    if (profile->loadXML(*doc) == false)
116✔
426
    {
427
        qWarning() << path << QString("%1\nLine %2, column %3")
×
428
                    .arg(doc->errorString())
×
429
                    .arg(doc->lineNumber())
×
430
                    .arg(doc->columnNumber());
×
431

432
        delete profile;
×
433
        profile = NULL;
434
    }
435
    else
436
    {
437
        profile->m_path = path;
116✔
438
    }
439

440
    QLCFile::releaseXMLReader(doc);
116✔
441

442
    return profile;
116✔
443
}
444

445
bool QLCInputProfile::loadColorTableXML(QXmlStreamReader &tableRoot)
12✔
446
{
447
    if (tableRoot.name() != KXMLQLCInputProfileColorTable)
24✔
448
    {
449
        qWarning() << Q_FUNC_INFO << "Color table node not found";
×
450
        return false;
×
451
    }
452

453
    tableRoot.readNextStartElement();
12✔
454

455
    do
456
    {
457
        if (tableRoot.name() == KXMLQLCInputProfileColor)
1,722✔
458
        {
459
            /* get value & color */
460
            uchar value = tableRoot.attributes().value(KXMLQLCInputProfileValue).toInt();
861✔
461
            QString label = tableRoot.attributes().value(KXMLQLCInputProfileLabel).toString();
861✔
462
            QColor color = QColor(tableRoot.attributes().value(KXMLQLCInputProfileColorRGB).toString());
1,722✔
463
            addColor(value, label, color);
861✔
464
        }
861✔
465
        else
466
        {
467
            qWarning() << Q_FUNC_INFO << "Unknown color table tag:" << tableRoot.name().toString();
×
468
        }
469
        tableRoot.skipCurrentElement();
861✔
470
    } while (tableRoot.readNextStartElement());
861✔
471

472
    return true;
473
}
474

475
bool QLCInputProfile::loadMidiChannelTableXML(QXmlStreamReader &tableRoot)
6✔
476
{
477
    if (tableRoot.name() != KXMLQLCInputProfileMidiChannelTable)
12✔
478
    {
479
        qWarning() << Q_FUNC_INFO << "MIDI channel table node not found";
×
480
        return false;
×
481
    }
482

483
    tableRoot.readNextStartElement();
6✔
484

485
    do
486
    {
487
        if (tableRoot.name() == KXMLQLCInputProfileMidiChannel)
114✔
488
        {
489
            /* get value & color */
490
            uchar value = tableRoot.attributes().value(KXMLQLCInputProfileValue).toInt();
57✔
491
            QString label = tableRoot.attributes().value(KXMLQLCInputProfileLabel).toString();
57✔
492
            addMidiChannel(value, label);
57✔
493
        }
57✔
494
        else
495
        {
496
            qWarning() << Q_FUNC_INFO << "Unknown MIDI channel table tag:" << tableRoot.name().toString();
×
497
        }
498
        tableRoot.skipCurrentElement();
57✔
499
    } while (tableRoot.readNextStartElement());
57✔
500

501
    return true;
502
}
503

504
bool QLCInputProfile::loadXML(QXmlStreamReader& doc)
119✔
505
{
506
    if (doc.readNextStartElement() == false)
119✔
507
        return false;
508

509
    if (doc.name() == KXMLQLCInputProfile)
234✔
510
    {
511
        while (doc.readNextStartElement())
13,035✔
512
        {
513
            if (doc.name() == KXMLQLCCreator)
25,836✔
514
            {
515
                /* Ignore this block */
516
                doc.skipCurrentElement();
116✔
517
            }
518
            else if (doc.name() == KXMLQLCInputProfileManufacturer)
25,604✔
519
            {
520
                setManufacturer(doc.readElementText());
117✔
521
            }
522
            else if (doc.name() == KXMLQLCInputProfileModel)
25,370✔
523
            {
524
                setModel(doc.readElementText());
117✔
525
            }
526
            else if (doc.name() == KXMLQLCInputProfileType)
25,136✔
527
            {
528
                setType(stringToType(doc.readElementText()));
116✔
529
            }
530
            else if (doc.name() == KXMLQLCInputProfileMidiSendNoteOff)
24,904✔
531
            {
532
                if (doc.readElementText() == KXMLQLCFalse)
18✔
533
                    setMidiSendNoteOff(false);
18✔
534
                else
535
                    setMidiSendNoteOff(true);
×
536
            }
537
            else if (doc.name() == KXMLQLCInputChannel)
24,868✔
538
            {
539
                QString str = doc.attributes().value(KXMLQLCInputChannelNumber).toString();
12,416✔
540
                if (str.isEmpty() == false)
12,416✔
541
                {
542
                    quint32 ch = str.toInt();
12,416✔
543
                    QLCInputChannel* ich = new QLCInputChannel();
12,416✔
544
                    if (ich->loadXML(doc) == true)
12,416✔
545
                        insertChannel(ch, ich);
12,416✔
546
                    else
547
                        delete ich;
×
548
                }
549
                else
550
                    doc.skipCurrentElement();
×
551
            }
12,416✔
552
            else if (doc.name() == KXMLQLCInputProfileColorTable)
36✔
553
            {
554
                loadColorTableXML(doc);
12✔
555
            }
556
            else if (doc.name() == KXMLQLCInputProfileMidiChannelTable)
12✔
557
            {
558
                loadMidiChannelTableXML(doc);
6✔
559
            }
560
            else
561
            {
562
                qWarning() << Q_FUNC_INFO << "Unknown input profile tag:" << doc.name().toString();
×
563
                doc.skipCurrentElement();
×
564
            }
565
        }
566

567
        return true;
568
    }
569
    else
570
    {
571
        qWarning() << Q_FUNC_INFO << "Input profile not found";
×
572
        return false;
×
573
    }
574
}
575

576
bool QLCInputProfile::saveXML(const QString& fileName)
2✔
577
{
578
    QFile file(fileName);
2✔
579
    if (file.open(QIODevice::WriteOnly) == false)
2✔
580
    {
581
        qWarning() << Q_FUNC_INFO << "Unable to write to" << fileName;
1✔
582
        return false;
1✔
583
    }
584

585
    QXmlStreamWriter doc(&file);
1✔
586
    doc.setAutoFormatting(true);
1✔
587
    doc.setAutoFormattingIndent(1);
1✔
588
    QLCFile::writeXMLHeader(&doc, KXMLQLCInputProfile);
1✔
589

590
    doc.writeTextElement(KXMLQLCInputProfileManufacturer, m_manufacturer);
1✔
591
    doc.writeTextElement(KXMLQLCInputProfileModel, m_model);
1✔
592
    doc.writeTextElement(KXMLQLCInputProfileType, typeToString(m_type));
1✔
593

594
    if (midiSendNoteOff() == false)
1✔
595
        doc.writeTextElement(KXMLQLCInputProfileMidiSendNoteOff, QString(KXMLQLCFalse));
×
596

597
    /* Write channels to the document */
598
    QMapIterator <quint32, QLCInputChannel*> it(m_channels);
1✔
599
    while (it.hasNext() == true)
4✔
600
    {
601
        it.next();
3✔
602
        it.value()->saveXML(&doc, it.key());
3✔
603
    }
604

605
    if (hasColorTable())
1✔
606
    {
607
        doc.writeStartElement(KXMLQLCInputProfileColorTable);
×
608

609
        QMapIterator <uchar, QPair<QString, QColor>> it(m_colorTable);
×
610
        while (it.hasNext() == true)
×
611
        {
612
            it.next();
×
613
            QPair<QString, QColor> lc = it.value();
614
            doc.writeStartElement(KXMLQLCInputProfileColor);
×
615
            doc.writeAttribute(KXMLQLCInputProfileValue, QString::number(it.key()));
×
616
            doc.writeAttribute(KXMLQLCInputProfileLabel, lc.first);
×
617
            doc.writeAttribute(KXMLQLCInputProfileColorRGB, lc.second.name());
×
618
            doc.writeEndElement();
×
619
        }
620

621
        doc.writeEndElement();
×
622
    }
623

624
    if (hasMidiChannelTable())
1✔
625
    {
626
        doc.writeStartElement(KXMLQLCInputProfileMidiChannelTable);
×
627

628
        QMapIterator <uchar, QString> it(m_midiChannelTable);
×
629
        while (it.hasNext() == true)
×
630
        {
631
            it.next();
×
632
            doc.writeStartElement(KXMLQLCInputProfileMidiChannel);
×
633
            doc.writeAttribute(KXMLQLCInputProfileValue, QString::number(it.key()));
×
634
            doc.writeAttribute(KXMLQLCInputProfileLabel, it.value());
×
635
            doc.writeEndElement();
×
636

637
        }
638
        doc.writeEndElement();
×
639
    }
640

641
    m_path = fileName;
1✔
642

643
    /* End the document and close all the open elements */
644
    doc.writeEndDocument();
1✔
645
    file.close();
1✔
646

647
    return true;
648
}
2✔
649

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc