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

mcallegari / qlcplus / 25128119917

29 Apr 2026 07:00PM UTC coverage: 34.05% (+0.002%) from 34.048%
25128119917

Pull #1998

github

web-flow
Merge ce41d30f6 into b7c5f4799
Pull Request #1998: Fixed plugin parameters not saved when device is disconnected

4 of 10 new or added lines in 2 files covered. (40.0%)

17762 of 52165 relevant lines covered (34.05%)

41159.18 hits per line

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

91.78
/engine/src/inputpatch.cpp
1
/*
2
  Q Light Controller
3
  inputpatch.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
#if defined(WIN32) || defined(Q_OS_WIN)
21
#   include <Windows.h>
22
#else
23
#   include <unistd.h>
24
#endif
25

26
#include <QDebug>
27

28
#include "qlcinputchannel.h"
29
#include "qlcioplugin.h"
30
#include "inputpatch.h"
31

32
#define GRACE_MS 1
33

34
/*****************************************************************************
35
 * Initialization
36
 *****************************************************************************/
37

38
InputPatch::InputPatch(QObject *parent)
1✔
39
    : QObject(parent)
40
    , m_universe(UINT_MAX)
1✔
41
    , m_plugin(NULL)
1✔
42
    , m_pluginLine(QLCIOPlugin::invalidLine())
2✔
43
    , m_profile(NULL)
1✔
44
    , m_nextPageCh(USHRT_MAX)
1✔
45
    , m_prevPageCh(USHRT_MAX)
1✔
46
    , m_pageSetCh(USHRT_MAX)
1✔
47
{
48
}
1✔
49

50
InputPatch::InputPatch(quint32 inputUniverse, QObject* parent)
8✔
51
    : QObject(parent)
52
    , m_universe(inputUniverse)
8✔
53
    , m_plugin(NULL)
8✔
54
    , m_pluginLine(QLCIOPlugin::invalidLine())
16✔
55
    , m_profile(NULL)
8✔
56
    , m_nextPageCh(USHRT_MAX)
8✔
57
    , m_prevPageCh(USHRT_MAX)
8✔
58
    , m_pageSetCh(USHRT_MAX)
8✔
59
{
60
}
8✔
61

62
InputPatch::~InputPatch()
16✔
63
{
64
    if (m_plugin != NULL)
9✔
65
        m_plugin->closeInput(m_pluginLine, m_universe);
6✔
66
}
16✔
67

68
/*****************************************************************************
69
 * Properties
70
 *****************************************************************************/
71

72
bool InputPatch::set(QLCIOPlugin* plugin, quint32 input, QLCInputProfile* profile)
8✔
73
{
74
    bool result = false;
8✔
75

76
    qDebug() << "InputPatch::set - plugin:" << ((plugin == NULL)?"None":plugin->name())
16✔
77
             << ", line:" << input
8✔
78
             << ", profile:" << ((profile == NULL)?"None":profile->name());
8✔
79

80
    if (m_plugin != NULL && m_pluginLine != QLCIOPlugin::invalidLine())
8✔
81
    {
82
        disconnect(m_plugin, SIGNAL(valueChanged(quint32,quint32,quint32,uchar,QString)),
2✔
83
                   this, SLOT(slotValueChanged(quint32,quint32,quint32,uchar,QString)));
84
        m_plugin->closeInput(m_pluginLine, m_universe);
2✔
85
    }
86

87
    m_plugin = plugin;
8✔
88
    m_pluginLine = input;
8✔
89
    m_profile = profile;
8✔
90

91
    if (m_plugin != NULL)
8✔
92
    {
93
        emit pluginNameChanged();
8✔
94
        if (m_pluginLine != QLCIOPlugin::invalidLine())
8✔
95
            emit inputNameChanged();
8✔
96
        if (m_profile != NULL)
8✔
97
            emit profileNameChanged();
4✔
98
    }
99

100
    /* Open the assigned plugin input */
101
    if (m_plugin != NULL && m_pluginLine != QLCIOPlugin::invalidLine())
8✔
102
    {
103
        connect(m_plugin, SIGNAL(valueChanged(quint32,quint32,quint32,uchar,QString)),
8✔
104
                this, SLOT(slotValueChanged(quint32,quint32,quint32,uchar,QString)));
105
        result = m_plugin->openInput(m_pluginLine, m_universe);
8✔
106

107
        if (m_profile != NULL)
8✔
108
            setProfilePageControls();
4✔
109
    }
110
    return result;
8✔
111
}
112

113
bool InputPatch::set(QLCInputProfile *profile)
2✔
114
{
115
    if (m_plugin == NULL || m_pluginLine == QLCIOPlugin::invalidLine())
2✔
116
        return false;
1✔
117

118
    m_profile = profile;
1✔
119

120
    if (m_profile != NULL)
1✔
121
        setProfilePageControls();
1✔
122

123
    emit profileNameChanged();
1✔
124

125
    return true;
1✔
126
}
127

128
bool InputPatch::reconnect()
1✔
129
{
130
    if (m_plugin != NULL && m_pluginLine != QLCIOPlugin::invalidLine())
1✔
131
    {
132
        m_plugin->closeInput(m_pluginLine, m_universe);
1✔
133
#if defined(WIN32) || defined(Q_OS_WIN)
134
        Sleep(GRACE_MS);
135
#else
136
        usleep(GRACE_MS * 1000);
1✔
137
#endif
138
        bool ret = m_plugin->openInput(m_pluginLine, m_universe);
1✔
139
        if (ret == true)
1✔
140
        {
141
            QMap<QString, QVariant>::iterator it = m_parametersCache.begin();
1✔
142
            for (; it != m_parametersCache.end(); it++)
1✔
143
            {
144
                qDebug() << "[InputPatch] restoring parameter:" << it.key() << it.value();
×
145
                m_plugin->setParameter(m_universe, m_pluginLine, QLCIOPlugin::Input, it.key(), it.value());
×
146
            }
147
        }
148
        return ret;
1✔
149
    }
150
    return false;
×
151
}
152

153
QLCIOPlugin* InputPatch::plugin() const
12✔
154
{
155
    return m_plugin;
12✔
156
}
157

158
QString InputPatch::pluginName() const
17✔
159
{
160
    if (m_plugin != NULL)
17✔
161
        return m_plugin->name();
15✔
162
    else
163
        return KInputNone;
2✔
164
}
165

166
quint32 InputPatch::input() const
20✔
167
{
168
    return m_pluginLine;
20✔
169
}
170

171
QString InputPatch::inputName() const
6✔
172
{
173
    if (m_plugin != NULL && m_pluginLine != QLCIOPlugin::invalidLine() &&
10✔
174
            m_pluginLine < quint32(m_plugin->inputs().count()))
10✔
175
        return m_plugin->inputs()[m_pluginLine];
4✔
176
    else
177
        return KInputNone;
2✔
178
}
179

180
QLCInputProfile* InputPatch::profile() const
12✔
181
{
182
    return m_profile;
12✔
183
}
184

185
QString InputPatch::profileName() const
9✔
186
{
187
    if (m_profile != NULL)
9✔
188
        return m_profile->name();
6✔
189
    else
190
        return KInputNone;
3✔
191
}
192

193
bool InputPatch::isPatched() const
3✔
194
{
195
    return input() != QLCIOPlugin::invalidLine();
3✔
196
}
197

198
void InputPatch::setPluginParameter(QString prop, QVariant value)
1✔
199
{
200
    qDebug() << "[InputPatch] caching parameter:" << prop << value;
1✔
201
    m_parametersCache[prop] = value;
1✔
202
    if (m_plugin != NULL)
1✔
203
        m_plugin->setParameter(m_universe, m_pluginLine, QLCIOPlugin::Input, prop, value);
1✔
204
}
1✔
205

206
QMap<QString, QVariant> InputPatch::getPluginParameters()
3✔
207
{
208
    if (m_plugin != NULL)
3✔
209
    {
210
        const auto params = m_plugin->getParameters(m_universe, m_pluginLine, QLCIOPlugin::Input);
3✔
211
        if (!params.isEmpty())
3✔
212
            return params;
3✔
213
    }
3✔
NEW
214
    return m_parametersCache;
×
215
}
216

217
void InputPatch::slotValueChanged(quint32 universe, quint32 input, quint32 channel,
6✔
218
                                  uchar value, const QString& key)
219
{
220
    // In case we have several lines connected to the same plugin, emit only
221
    // such values that belong to this particular patch.
222
    if (input == m_pluginLine)
6✔
223
    {
224
        if (universe == UINT_MAX || universe == m_universe)
4✔
225
        {
226
            QMutexLocker inputBufferLocker(&m_inputBufferMutex);
4✔
227
            InputValue val(value, key);
4✔
228
            if (m_inputBuffer.contains(channel))
4✔
229
            {
230
                InputValue const& curVal = m_inputBuffer.value(channel);
1✔
231
                if (curVal.value != val.value)
1✔
232
                {
233
                    // Every ON/OFF changes must pass through
234
                    if (curVal.value == 0 || val.value == 0)
1✔
235
                    {
236
                        emit inputValueChanged(m_universe, channel, curVal.value, curVal.key);
1✔
237
                    }
238
                    m_inputBuffer.insert(channel, val);
1✔
239
                }
240
            }
1✔
241
            else
242
            {
243
                m_inputBuffer.insert(channel, val);
3✔
244
            }
245
        }
4✔
246
    }
247
}
6✔
248

249
void InputPatch::setProfilePageControls()
5✔
250
{
251
    if (m_profile != NULL)
5✔
252
    {
253
        if (m_plugin != NULL)
5✔
254
        {
255
            QMap<QString, QVariant> settings = m_profile->globalSettings();
5✔
256
            if (settings.isEmpty() == false)
5✔
257
            {
258
                QMapIterator <QString,QVariant> it(settings);
×
259
                while (it.hasNext() == true)
×
260
                {
261
                    it.next();
×
262
                    m_plugin->setParameter(m_universe, m_pluginLine, QLCIOPlugin::Input, it.key(), it.value());
×
263
                }
264
            }
×
265
        }
5✔
266
        QMapIterator <quint32,QLCInputChannel*> it(m_profile->channels());
5✔
267
        while (it.hasNext() == true)
261✔
268
        {
269
            it.next();
256✔
270
            QLCInputChannel *ch = it.value();
256✔
271
            if (ch != NULL)
256✔
272
            {
273
                if (m_nextPageCh == USHRT_MAX && ch->type() == QLCInputChannel::NextPage)
256✔
274
                    m_nextPageCh = m_profile->channelNumber(ch);
×
275
                else if (m_prevPageCh == USHRT_MAX && ch->type() == QLCInputChannel::PrevPage)
256✔
276
                    m_prevPageCh = m_profile->channelNumber(ch);
×
277
                else if (m_pageSetCh == USHRT_MAX && ch->type() == QLCInputChannel::PageSet)
256✔
278
                    m_pageSetCh = m_profile->channelNumber(ch);
×
279
            }
280
        }
281
    }
5✔
282
}
5✔
283

284
void InputPatch::flush(quint32 universe)
5✔
285
{
286
    if (universe == UINT_MAX || universe == m_universe)
5✔
287
    {
288
        QMutexLocker inputBufferLocker(&m_inputBufferMutex);
5✔
289
        for (QHash<quint32, InputValue>::const_iterator it = m_inputBuffer.begin(); it != m_inputBuffer.end(); ++it)
8✔
290
        {
291
            emit inputValueChanged(m_universe, it.key(), it.value().value, it.value().key);
3✔
292
        }
293
        m_inputBuffer.clear();
5✔
294
    }
5✔
295
}
5✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc