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

mcallegari / qlcplus / 19144422256

06 Nov 2025 05:33PM UTC coverage: 34.256% (-0.1%) from 34.358%
19144422256

push

github

mcallegari
Back to 5.1.0 debug

17718 of 51723 relevant lines covered (34.26%)

19528.23 hits per line

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

77.78
/engine/src/sequence.cpp
1
/*
2
  Q Light Controller Plus
3
  sequence.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
#include <QXmlStreamReader>
21
#include <QXmlStreamWriter>
22
#include <QDebug>
23

24
#include "sequence.h"
25

26
#define KXMLQLCSequenceBoundScene QStringLiteral("BoundScene")
27

28
Sequence::Sequence(Doc* doc)
10✔
29
    : Chaser(doc)
30
    , m_boundSceneID(Function::invalidId())
20✔
31
    , m_needFixup(true)
10✔
32
{
33
    m_type = Function::SequenceType;
10✔
34
    setName(tr("New Sequence"));
10✔
35
}
10✔
36

37
Sequence::~Sequence()
17✔
38
{
39
}
17✔
40

41
QIcon Sequence::getIcon() const
×
42
{
43
    return QIcon(":/sequence.png");
×
44
}
45

46
Function *Sequence::createCopy(Doc *doc, bool addToDoc)
1✔
47
{
48
    Q_ASSERT(doc != NULL);
1✔
49

50
    Function* copy = new Sequence(doc);
1✔
51
    if (copy->copyFrom(this) == false)
1✔
52
    {
53
        delete copy;
×
54
        copy = NULL;
×
55
    }
56
    if (addToDoc == true && doc->addFunction(copy) == false)
1✔
57
    {
58
        delete copy;
×
59
        copy = NULL;
×
60
    }
61

62
    return copy;
1✔
63
}
64

65
bool Sequence::copyFrom(const Function *function)
1✔
66
{
67
    const Sequence* sequence = qobject_cast<const Sequence*> (function);
1✔
68
    if (sequence == NULL)
1✔
69
        return false;
×
70

71
    // Copy sequence stuff
72
    m_steps = sequence->m_steps;
1✔
73
    m_fadeInMode = sequence->m_fadeInMode;
1✔
74
    m_fadeOutMode = sequence->m_fadeOutMode;
1✔
75
    m_holdMode = sequence->m_holdMode;
1✔
76
    m_boundSceneID = sequence->m_boundSceneID;
1✔
77

78
    // Copy common function stuff
79
    return Function::copyFrom(function);
1✔
80
}
81

82
void Sequence::setBoundSceneID(quint32 sceneID)
6✔
83
{
84
    m_boundSceneID = sceneID;
6✔
85
}
6✔
86

87
quint32 Sequence::boundSceneID() const
23✔
88
{
89
    return m_boundSceneID;
23✔
90
}
91

92
QList<quint32> Sequence::components()
×
93
{
94
    QList<quint32> ids;
×
95
    if (m_boundSceneID != Function::invalidId())
×
96
        ids.append(m_boundSceneID);
×
97
    return ids;
×
98
}
×
99

100
/*****************************************************************************
101
 * Save & Load
102
 *****************************************************************************/
103

104
bool Sequence::saveXML(QXmlStreamWriter *doc)
1✔
105
{
106
    Q_ASSERT(doc != NULL);
1✔
107

108
    /* Function tag */
109
    doc->writeStartElement(KXMLQLCFunction);
2✔
110

111
    /* Common attributes */
112
    saveXMLCommon(doc);
1✔
113

114
    doc->writeAttribute(KXMLQLCSequenceBoundScene, QString::number(boundSceneID()));
2✔
115

116
    /* Tempo type */
117
    saveXMLTempoType(doc);
1✔
118

119
    /* Speed */
120
    saveXMLSpeed(doc);
1✔
121

122
    /* Direction */
123
    saveXMLDirection(doc);
1✔
124

125
    /* Run order */
126
    saveXMLRunOrder(doc);
1✔
127

128
    /* Speed modes */
129
    doc->writeStartElement(KXMLQLCChaserSpeedModes);
2✔
130
    doc->writeAttribute(KXMLQLCFunctionSpeedFadeIn, speedModeToString(fadeInMode()));
2✔
131
    doc->writeAttribute(KXMLQLCFunctionSpeedFadeOut, speedModeToString(fadeOutMode()));
2✔
132
    doc->writeAttribute(KXMLQLCFunctionSpeedDuration, speedModeToString(durationMode()));
2✔
133
    doc->writeEndElement();
1✔
134

135
    /* Steps */
136
    for (int i = 0; i < m_steps.count(); i++)
4✔
137
        m_steps.at(i).saveXML(doc, i, true);
3✔
138

139
    /* End the <Function> tag */
140
    doc->writeEndElement();
1✔
141

142
    return true;
1✔
143
}
144

145
bool Sequence::loadXML(QXmlStreamReader &root)
4✔
146
{
147
    if (root.name() != KXMLQLCFunction)
4✔
148
    {
149
        qWarning() << Q_FUNC_INFO << "Function node not found";
1✔
150
        return false;
1✔
151
    }
152

153
    QXmlStreamAttributes funcAttrs = root.attributes();
3✔
154

155
    if (funcAttrs.value(KXMLQLCFunctionType).toString() != typeToString(Function::SequenceType))
6✔
156
    {
157
        qWarning() << Q_FUNC_INFO << funcAttrs.value(KXMLQLCFunctionType).toString()
3✔
158
                   << "is not a Sequence";
1✔
159
        return false;
1✔
160
    }
161

162
    if (funcAttrs.hasAttribute(KXMLQLCSequenceBoundScene) == false)
2✔
163
    {
164
        qWarning() << Q_FUNC_INFO << "Sequence doesn't have a bound Scene ID";
×
165
        return false;
×
166
    }
167

168
    setBoundSceneID(funcAttrs.value(KXMLQLCSequenceBoundScene).toString().toUInt());
2✔
169

170
    Scene *scene = qobject_cast<Scene *>(doc()->function(boundSceneID()));
2✔
171
    QList<SceneValue> sceneValues;
2✔
172
    if (scene != NULL)
2✔
173
    {
174
        sceneValues = scene->values();
1✔
175
        std::sort(sceneValues.begin(), sceneValues.end());
1✔
176
        m_needFixup = false;
1✔
177
    }
178

179
    /* Load Sequence contents */
180
    while (root.readNextStartElement())
16✔
181
    {
182
        if (root.name() == KXMLQLCFunctionSpeed)
14✔
183
        {
184
            loadXMLSpeed(root);
2✔
185
        }
186
        else if (root.name() == KXMLQLCFunctionDirection)
12✔
187
        {
188
            loadXMLDirection(root);
2✔
189
        }
190
        else if (root.name() == KXMLQLCFunctionRunOrder)
10✔
191
        {
192
            loadXMLRunOrder(root);
2✔
193
        }
194
        else if (root.name() == KXMLQLCFunctionTempoType)
8✔
195
        {
196
            loadXMLTempoType(root);
×
197
        }
198
        else if (root.name() == KXMLQLCChaserSpeedModes)
8✔
199
        {
200
            loadXMLSpeedModes(root);
2✔
201
        }
202
        else if (root.name() == KXMLQLCFunctionStep)
6✔
203
        {
204
            //! @todo stepNumber is useless if the steps are in the wrong order
205
            ChaserStep step;
6✔
206
            int stepNumber = -1;
6✔
207

208
            if (sceneValues.isEmpty() == false)
6✔
209
                step.values = sceneValues;
3✔
210

211
            if (step.loadXML(root, stepNumber, doc()) == true)
6✔
212
            {
213
                step.fid = boundSceneID();
6✔
214

215
                if (stepNumber >= m_steps.size())
6✔
216
                    m_steps.append(step);
6✔
217
                else
218
                    m_steps.insert(stepNumber, step);
×
219
            }
220
        }
6✔
221
        else
222
        {
223
            qWarning() << Q_FUNC_INFO << "Unknown Sequence tag:" << root.name();
×
224
            root.skipCurrentElement();
×
225
        }
226
    }
227

228
    return true;
2✔
229
}
3✔
230

231
void Sequence::postLoad()
1✔
232
{
233
    if (m_needFixup == false)
1✔
234
        return;
×
235

236
    Doc* doc = this->doc();
1✔
237
    Q_ASSERT(doc != NULL);
1✔
238

239
    Scene *scene = qobject_cast<Scene *>(doc->function(boundSceneID()));
1✔
240
    QList<SceneValue> sceneValues;
1✔
241
    if (scene != NULL)
1✔
242
    {
243
        sceneValues = scene->values();
1✔
244

245
        if (sceneValues.count() == 0)
1✔
246
        {
247
            qDebug() << "The bound Scene is empty ! This should never happen. Trying to fix it...";
×
248
            if (stepsCount())
×
249
            {
250
                foreach (SceneValue value, m_steps.at(0).values)
×
251
                {
252
                    value.value = 0;
×
253
                    if (doc->fixture(value.fxi) != NULL)
×
254
                        scene->setValue(value);
×
255
                }
×
256
            }
257
            m_needFixup = false;
×
258
            return;
×
259
        }
260

261
        std::sort(sceneValues.begin(), sceneValues.end());
1✔
262
    }
263

264
    int stepIndex = 0;
1✔
265

266
    QMutableListIterator <ChaserStep> it(m_steps);
1✔
267
    while (it.hasNext() == true)
4✔
268
    {
269
        ChaserStep step(it.next());
3✔
270
        if (sceneValues.count() == step.values.count())
3✔
271
        {
272
            stepIndex++;
×
273
            continue;
×
274
        }
275

276
        QList <SceneValue> tmpList = step.values;
3✔
277
        step.values = sceneValues;
3✔
278
        for (int i = 0; i < tmpList.count(); i++)
21✔
279
        {
280
            int tmpIndex = step.values.indexOf(tmpList.at(i));
18✔
281
            if (tmpIndex == -1)
18✔
282
                continue;
×
283
            step.values.replace(tmpIndex, tmpList.at(i));
18✔
284
        }
285

286
        replaceStep(step, stepIndex);
3✔
287
        stepIndex++;
3✔
288
    }
3✔
289
    m_needFixup = false;
1✔
290

291
    qDebug() << "Sequence" << name() << "steps fixed. Values:" << sceneValues.count();
1✔
292
}
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