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

mcallegari / qlcplus / 14445404527

14 Apr 2025 12:17PM UTC coverage: 31.854% (-0.05%) from 31.907%
14445404527

push

github

web-flow
Merge pull request #1714 from shaforostoff/webaccess_optimize_loadxml

engine: speedup loadXML methods by using QStringLiteral

1 of 1 new or added line in 1 file covered. (100.0%)

220 existing lines in 5 files now uncovered.

14674 of 46067 relevant lines covered (31.85%)

26455.49 hits per line

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

75.18
/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 QStringLiteral("MIDI")
32
#define KXMLQLCInputProfileTypeOs2l QStringLiteral("OS2L")
33
#define KXMLQLCInputProfileTypeOsc QStringLiteral("OSC")
34
#define KXMLQLCInputProfileTypeHid QStringLiteral("HID")
35
#define KXMLQLCInputProfileTypeDmx QStringLiteral("DMX")
36
#define KXMLQLCInputProfileTypeEnttec QStringLiteral("Enttec")
37

38
#define KXMLQLCInputProfileValue QStringLiteral("Value")
39
#define KXMLQLCInputProfileLabel QStringLiteral("Label")
40
#define KXMLQLCInputProfileColorRGB QStringLiteral("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()
251✔
56
{
57
    destroyChannels();
134✔
58
}
251✔
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;
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.remove(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
    return m_channels.value(channel, NULL);
75✔
314
}
315

316
quint32 QLCInputProfile::channelNumber(const QLCInputChannel* channel) const
6✔
317
{
318
    if (channel == NULL)
6✔
319
        return QLCChannel::invalid();
1✔
320

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

329
    return QLCChannel::invalid();
1✔
330
}
331

332
QMap <quint32,QLCInputChannel*> QLCInputProfile::channels() const
30✔
333
{
334
    return m_channels;
30✔
335
}
336

UNCOV
337
QVariant QLCInputProfile::channelExtraParams(const QLCInputChannel* channel) const
×
338
{
UNCOV
339
    if (channel == NULL)
×
340
        return QVariant();
341

342
    switch (m_type)
×
343
    {
UNCOV
344
        case OSC: return channel->name();
×
345
        case MIDI: return channel->lowerChannel();
×
346
        default: return QVariant();
347
    }
348
}
349

350
void QLCInputProfile::destroyChannels()
135✔
351
{
352
    /* Delete existing channels but leave the pointers there */
353
    QMutableMapIterator <quint32,QLCInputChannel*> it(m_channels);
135✔
354
    while (it.hasNext() == true)
12,322✔
355
        delete it.next().value();
12,187✔
356

357
    /* Clear the list of freed pointers */
358
    m_channels.clear();
135✔
359
}
135✔
360

361
bool QLCInputProfile::hasColorTable()
1✔
362
{
363
    return m_colorTable.isEmpty() ? false : true;
1✔
364
}
365

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

UNCOV
374
void QLCInputProfile::removeColor(uchar value)
×
375
{
UNCOV
376
    m_colorTable.remove(value);
×
377
}
×
378

379
QMap<uchar, QPair<QString, QColor> > QLCInputProfile::colorTable()
1✔
380
{
381
    return m_colorTable;
1✔
382
}
383

384
/********************************************************************
385
 * MIDI Channel table
386
 ********************************************************************/
387

388
bool QLCInputProfile::hasMidiChannelTable()
1✔
389
{
390
    return m_midiChannelTable.isEmpty() ? false : true;
1✔
391
}
392

393
void QLCInputProfile::addMidiChannel(uchar channel, QString label)
57✔
394
{
395
    m_midiChannelTable.insert(channel, label);
57✔
396
}
57✔
397

UNCOV
398
void QLCInputProfile::removeMidiChannel(uchar channel)
×
399
{
UNCOV
400
    m_midiChannelTable.remove(channel);
×
401
}
×
402

403
QMap<uchar, QString> QLCInputProfile::midiChannelTable()
1✔
404
{
405
    return m_midiChannelTable;
1✔
406
}
407

408
/****************************************************************************
409
 * Load & Save
410
 ****************************************************************************/
411

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

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

429
        delete profile;
×
430
        profile = NULL;
431
    }
432
    else
433
    {
434
        profile->m_path = path;
116✔
435
    }
436

437
    QLCFile::releaseXMLReader(doc);
116✔
438

439
    return profile;
116✔
440
}
441

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

450
    tableRoot.readNextStartElement();
12✔
451

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

469
    return true;
470
}
471

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

480
    tableRoot.readNextStartElement();
6✔
481

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

498
    return true;
499
}
500

501
bool QLCInputProfile::loadXML(QXmlStreamReader& doc)
119✔
502
{
503
    if (doc.readNextStartElement() == false)
119✔
504
        return false;
505

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

561
        return true;
562
    }
563
    else
564
    {
UNCOV
565
        qWarning() << Q_FUNC_INFO << "Input profile not found";
×
UNCOV
566
        return false;
×
567
    }
568
}
569

570
bool QLCInputProfile::saveXML(const QString& fileName)
2✔
571
{
572
    QFile file(fileName);
2✔
573
    if (file.open(QIODevice::WriteOnly) == false)
2✔
574
    {
575
        qWarning() << Q_FUNC_INFO << "Unable to write to" << fileName;
1✔
576
        return false;
1✔
577
    }
578

579
    QXmlStreamWriter doc(&file);
1✔
580
    doc.setAutoFormatting(true);
1✔
581
    doc.setAutoFormattingIndent(1);
1✔
582
    QLCFile::writeXMLHeader(&doc, KXMLQLCInputProfile);
1✔
583

584
    doc.writeTextElement(KXMLQLCInputProfileManufacturer, m_manufacturer);
1✔
585
    doc.writeTextElement(KXMLQLCInputProfileModel, m_model);
1✔
586
    doc.writeTextElement(KXMLQLCInputProfileType, typeToString(m_type));
1✔
587

588
    if (midiSendNoteOff() == false)
1✔
UNCOV
589
        doc.writeTextElement(KXMLQLCInputProfileMidiSendNoteOff, QString(KXMLQLCFalse));
×
590

591
    /* Write channels to the document */
592
    QMapIterator <quint32, QLCInputChannel*> it(m_channels);
1✔
593
    while (it.hasNext() == true)
4✔
594
    {
595
        it.next();
3✔
596
        it.value()->saveXML(&doc, it.key());
3✔
597
    }
598

599
    if (hasColorTable())
1✔
600
    {
UNCOV
601
        doc.writeStartElement(KXMLQLCInputProfileColorTable);
×
602

UNCOV
603
        QMapIterator <uchar, QPair<QString, QColor>> it(m_colorTable);
×
604
        while (it.hasNext() == true)
×
605
        {
606
            it.next();
×
607
            QPair<QString, QColor> lc = it.value();
UNCOV
608
            doc.writeStartElement(KXMLQLCInputProfileColor);
×
609
            doc.writeAttribute(KXMLQLCInputProfileValue, QString::number(it.key()));
×
UNCOV
610
            doc.writeAttribute(KXMLQLCInputProfileLabel, lc.first);
×
611
            doc.writeAttribute(KXMLQLCInputProfileColorRGB, lc.second.name());
×
612
            doc.writeEndElement();
×
613
        }
614

615
        doc.writeEndElement();
×
616
    }
617

618
    if (hasMidiChannelTable())
1✔
619
    {
UNCOV
620
        doc.writeStartElement(KXMLQLCInputProfileMidiChannelTable);
×
621

UNCOV
622
        QMapIterator <uchar, QString> it(m_midiChannelTable);
×
623
        while (it.hasNext() == true)
×
624
        {
625
            it.next();
×
626
            doc.writeStartElement(KXMLQLCInputProfileMidiChannel);
×
UNCOV
627
            doc.writeAttribute(KXMLQLCInputProfileValue, QString::number(it.key()));
×
628
            doc.writeAttribute(KXMLQLCInputProfileLabel, it.value());
×
629
            doc.writeEndElement();
×
630

631
        }
632
        doc.writeEndElement();
×
633
    }
634

635
    m_path = fileName;
1✔
636

637
    /* End the document and close all the open elements */
638
    doc.writeEndDocument();
1✔
639
    file.close();
1✔
640

641
    return true;
642
}
2✔
643

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