• 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

0.0
/ui/src/fixturetreewidget.cpp
1
/*
2
  Q Light Controller Plus
3
  fixturetreewidget.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 <QDebug>
21
#include <QHeaderView>
22

23
#include "fixturetreewidget.h"
24
#include "qlcfixturedef.h"
25
#include "fixturegroup.h"
26
#include "qlcchannel.h"
27
#include "fixture.h"
28
#include "doc.h"
29

30
#define KColumnName 0
31

32
FixtureTreeWidget::FixtureTreeWidget(Doc *doc, quint32 flags, QWidget *parent)
×
33
    : QTreeWidget(parent)
34
    , m_doc(doc)
×
35
    , m_universesCount(0)
×
36
    , m_fixturesCount(0)
×
37
    , m_channelsCount(0)
×
38
    , m_uniColumn(-1)
×
39
    , m_addressColumn(-1)
×
40
    , m_typeColumn(-1)
×
41
    , m_headsColumn(-1)
×
42
    , m_manufColumn(-1)
×
43
    , m_modelColumn(-1)
×
44
    , m_showGroups(false)
×
45
    , m_showHeads(false)
×
46
    , m_channelSelection(false)
×
47
{
48
    setFlags(flags);
×
49

50
    setRootIsDecorated(true);
×
51
    setAllColumnsShowFocus(true);
×
52
    setSortingEnabled(true);
×
53
    sortByColumn(KColumnName, Qt::AscendingOrder);
×
54

55
    connect(this, SIGNAL(itemExpanded(QTreeWidgetItem*)),
×
56
            this, SLOT(slotItemExpanded()));
57
    connect(this, SIGNAL(itemCollapsed(QTreeWidgetItem*)),
×
58
            this, SLOT(slotItemExpanded()));
59
}
×
60

61
void FixtureTreeWidget::setFlags(quint32 flags)
×
62
{
63
    // column 0 is always reserved for Fixture name
64
    int columnIdx = 1;
65
    QStringList labels;
66
    labels << tr("Name");
×
67

68
    if (flags & UniverseNumber)
×
69
    {
70
        m_uniColumn = columnIdx++;
×
71
        labels << tr("Universe");
×
72
    }
73
    if (flags & AddressRange)
×
74
    {
75
        m_addressColumn = columnIdx++;
×
76
        labels << tr("Address");
×
77
    }
78
    if (flags & ChannelType)
×
79
    {
80
        m_typeColumn = columnIdx++;
×
81
        labels << tr("Type");
×
82
    }
83
    if (flags & HeadsNumber)
×
84
    {
85
        m_headsColumn = columnIdx++;
×
86
        labels << tr("Heads");
×
87
    }
88
    if (flags & Manufacturer)
×
89
    {
90
        m_manufColumn = columnIdx++;
×
91
        labels << tr("Manufacturer");
×
92
    }
93
    if (flags & Model)
×
94
    {
95
        m_modelColumn = columnIdx++;
×
96
        labels << tr("Model");
×
97
    }
98
    if (flags & ShowGroups)
×
99
        m_showGroups = true;
×
100

101
    if (flags & ShowHeads)
×
102
        m_showHeads = true;
×
103

104
    if (flags & ChannelSelection)
×
105
        m_channelSelection = true;
×
106

107
    setHeaderLabels(labels);
×
108
}
×
109

110
/****************************************************************************
111
 * Disabled items
112
 ****************************************************************************/
113

114
void FixtureTreeWidget::setDisabledFixtures(const QList <quint32>& disabled)
×
115
{
116
    m_disabledHeads.clear();
×
117
    m_disabledFixtures = disabled;
×
118
}
×
119

120
void FixtureTreeWidget::setDisabledHeads(const QList <GroupHead>& disabled)
×
121
{
122
    m_disabledFixtures.clear();
×
123
    m_disabledHeads = disabled;
×
124
}
×
125

126
void FixtureTreeWidget::setChannelsMask(QByteArray channels)
×
127
{
128
    m_channelsMask = channels;
×
129
}
×
130

131
/****************************************************************************
132
 * Tree rendering
133
 ****************************************************************************/
134

135
QTreeWidgetItem *FixtureTreeWidget::fixtureItem(quint32 id) const
×
136
{
137
    for (int i = 0; i < topLevelItemCount(); i++)
×
138
    {
139
        QTreeWidgetItem *tItem = topLevelItem(i);
×
140
        if (tItem->childCount() > 0)
×
141
        {
142
            for (int c = 0; c < tItem->childCount(); c++)
×
143
            {
144
                QTreeWidgetItem *cItem = tItem->child(c);
×
145
                QVariant var = cItem->data(KColumnName, PROP_ID);
×
146
                if (var.isValid() == true && var.toUInt() == id)
×
147
                    return cItem;
148
            }
×
149
        }
150
    }
151

152
    return NULL;
153
}
154

155
QTreeWidgetItem *FixtureTreeWidget::groupItem(quint32 id) const
×
156
{
157
    for (int i = 0; i < topLevelItemCount(); i++)
×
158
    {
159
        QTreeWidgetItem *item = topLevelItem(i);
×
160
        QVariant var = item->data(KColumnName, PROP_GROUP);
×
161
        if (var.isValid() == true && var.toUInt() == id)
×
162
            return item;
163
    }
×
164

165
    return NULL;
166
}
167

168
void FixtureTreeWidget::updateFixtureItem(QTreeWidgetItem* item, Fixture* fixture)
×
169
{
170
    Q_ASSERT(item != NULL);
171
    if (fixture == NULL)
×
172
        return;
173

174
    item->setText(KColumnName, fixture->name());
×
175
    item->setIcon(KColumnName, fixture->getIconFromType());
×
176
    item->setData(KColumnName, PROP_ID, QString::number(fixture->id()));
×
177
    if (m_channelSelection)
×
178
    {
179
        item->setFlags(item->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
×
180
        item->setCheckState(KColumnName, Qt::Unchecked);
×
181
    }
182
    if (m_disabledFixtures.contains(fixture->id()) == true)
×
183
    {
184
        // Disable selection
185
        item->setFlags(Qt::NoItemFlags);
×
186
    }
187

188
    if (m_uniColumn > 0)
×
189
    {
190
        item->setText(m_uniColumn, QString("%1").arg(fixture->universe() + 1));
×
191
        item->setTextAlignment(m_uniColumn, Qt::AlignHCenter | Qt::AlignVCenter);
×
192
    }
193

194
    if (m_addressColumn)
×
195
    {
196
        QString s;
197
        if (fixture->channels() > 1)
×
198
        {
199
            item->setText(m_addressColumn, s.asprintf("%.3d - %.3d", fixture->address() + 1,
×
200
                                                      fixture->address() + fixture->channels()));
×
201
        }
202
        else
203
        {
204
            item->setText(m_addressColumn, s.asprintf("%.3d", fixture->address() + 1));
×
205
        }
206
    }
×
207

208
    if (m_headsColumn > 0)
×
209
        item->setText(m_headsColumn, QString::number(fixture->heads()));
×
210

211
    if (m_manufColumn > 0)
×
212
    {
213
        if (fixture->fixtureDef() == NULL)
×
214
            item->setText(m_manufColumn, tr("Generic"));
×
215
        else
216
            item->setText(m_manufColumn, fixture->fixtureDef()->manufacturer());
×
217
    }
218

219
    if (m_modelColumn > 0)
×
220
    {
221
        if (fixture->fixtureDef() == NULL)
×
222
            item->setText(m_modelColumn, tr("Generic"));
×
223
        else
224
            item->setText(m_modelColumn, fixture->fixtureDef()->model());
×
225
    }
226

227
    if (m_showHeads == true)
×
228
    {
229
        int disabled = 0;
230

231
        for (int i = 0; i < fixture->heads(); i++)
×
232
        {
233
            QTreeWidgetItem* headItem = new QTreeWidgetItem(item);
×
234
            headItem->setText(KColumnName, QString("%1 %2").arg(tr("Head")).arg(i + 1, 3, 10, QChar('0')));
×
235
            headItem->setData(KColumnName, PROP_HEAD, i);
×
236
            if (m_disabledHeads.contains(GroupHead(fixture->id(), i)) == true)
×
237
            {
238
                headItem->setFlags(Qt::NoItemFlags); // Disable selection
×
239
                disabled++;
×
240
            }
241
        }
242

243
        // Disable the whole fixture if all heads are disabled
244
        if (disabled == fixture->heads())
×
245
            item->setFlags(Qt::NoItemFlags);
×
246
    }
247

248
    if (m_channelSelection == true)
×
249
    {
250
        quint32 baseAddress = fixture->universeAddress();
×
251
        for (quint32 c = 0; c < fixture->channels(); c++)
×
252
        {
253
            const QLCChannel* channel = fixture->channel(c);
×
254
            QTreeWidgetItem *cItem = new QTreeWidgetItem(item);
×
255
            cItem->setText(KColumnName, QString("%1:%2").arg(c + 1)
×
256
                          .arg(channel->name()));
×
257
            cItem->setIcon(KColumnName, channel->getIcon());
×
258
            cItem->setData(KColumnName, PROP_CHANNEL, c);
×
259
            if (m_typeColumn > 0)
×
260
            {
261
                if (channel->group() == QLCChannel::Intensity &&
×
262
                    channel->colour() != QLCChannel::NoColour)
×
263
                    cItem->setText(m_typeColumn, QLCChannel::colourToString(channel->colour()));
×
264
                else
265
                    cItem->setText(m_typeColumn, QLCChannel::groupToString(channel->group()));
×
266
            }
267

268
            cItem->setFlags(cItem->flags() | Qt::ItemIsUserCheckable);
×
269
            if (m_channelsMask.length() > (int)(baseAddress + c) &&
×
270
                m_channelsMask.at(baseAddress + c) == 1)
271
                    cItem->setCheckState(KColumnName, Qt::Checked);
×
272
            else
273
                cItem->setCheckState(KColumnName, Qt::Unchecked);
×
274
        }
275
    }
276
}
277

278
void FixtureTreeWidget::updateGroupItem(QTreeWidgetItem* item, const FixtureGroup* grp)
×
279
{
280
    Q_ASSERT(item != NULL);
281
    Q_ASSERT(grp != NULL);
282

283
    item->setText(KColumnName, grp->name());
×
284
    item->setIcon(KColumnName, QIcon(":/group.png"));
×
285
    item->setData(KColumnName, PROP_GROUP, grp->id());
×
286

287
    // This should be a safe check because simultaneous add/removal is not possible,
288
    // which could result in changes in fixtures but with the same fixture count.
289
    if (item->childCount() != grp->fixtureList().size())
×
290
    {
291
        // Remove existing children
292
        while (item->childCount() > 0)
×
293
            delete item->child(0);
×
294

295
        // Add group's children
296
        foreach (quint32 id, grp->fixtureList())
×
297
        {
298
            QTreeWidgetItem* grpItem = new QTreeWidgetItem(item);
×
299
            updateFixtureItem(grpItem, m_doc->fixture(id));
×
300
        }
301
    }
302
}
×
303

304
int FixtureTreeWidget::universeCount()
×
305
{
306
    return m_universesCount;
×
307
}
308

309
int FixtureTreeWidget::fixturesCount()
×
310
{
311
    return m_fixturesCount;
×
312
}
313

314
int FixtureTreeWidget::channelsCount()
×
315
{
316
    return m_channelsCount;
×
317
}
318

319
QList<quint32> FixtureTreeWidget::selectedFixtures()
×
320
{
321
    updateSelections();
×
322
    return m_selectedFixtures;
×
323
}
324

325
QList<GroupHead> FixtureTreeWidget::selectedHeads()
×
326
{
327
    updateSelections();
×
328
    return m_selectedHeads;
×
329
}
330

331
void FixtureTreeWidget::updateSelections()
×
332
{
333
    m_selectedFixtures.clear();
×
334
    m_selectedHeads.clear();
×
335

336
    QListIterator <QTreeWidgetItem*> it(selectedItems());
×
337
    while (it.hasNext() == true)
×
338
    {
339
        QTreeWidgetItem *item = it.next();
×
340
        // A selected item can be:
341
        // 1) a fixture
342
        // 2) a group
343
        // 3) a head
344
        // 4) a universe
345

346
        QVariant fxIDVar = item->data(KColumnName, PROP_ID);
×
347
        QVariant grpIDVar = item->data(KColumnName, PROP_GROUP);
×
348
        QVariant headVar = item->data(KColumnName, PROP_HEAD);
×
349
        QVariant uniIDVar = item->data(KColumnName, PROP_UNIVERSE);
×
350

351
        qDebug() << "uni ID:" << uniIDVar;
352

353
        // Case 1: is there a valid fixture ID ?
354
        if (fxIDVar.isValid())
×
355
        {
356
            quint32 fxi = fxIDVar.toUInt();
×
357
            m_selectedFixtures << fxi;
358

359
            // fill also the non-diabled heads, if present
360
            if (m_showHeads && item->childCount() > 0)
×
361
            {
362
                for (int h = 0; h < item->childCount(); h++)
×
363
                {
364
                    QTreeWidgetItem *hItem = item->child(h);
×
365
                    if (hItem->isDisabled() == false)
×
366
                    {
367
                        QVariant chHeadVar = hItem->data(KColumnName, PROP_HEAD);
×
368
                        if (chHeadVar.isValid())
×
369
                        {
370
                            GroupHead gh(fxi, chHeadVar.toInt());
×
371
                            if (m_selectedHeads.contains(gh) == false)
×
372
                                m_selectedHeads << gh;
373
                        }
×
374
                    }
×
375
                }
376
            }
377
        }
378
        // Case 2: is there a valid group ID ?
379
        else if (grpIDVar.isValid())
×
380
        {
381
            // in this case cycle through the children and get each
382
            // fixture ID
383
            for (int i = 0; i < item->childCount(); i++)
×
384
            {
385
                QTreeWidgetItem *child = item->child(i);
×
386
                QVariant chFxIDVar = child->data(KColumnName, PROP_ID);
×
387
                if (chFxIDVar.isValid() && child->isDisabled() == false)
×
388
                    m_selectedFixtures << chFxIDVar.toUInt();
×
389
            }
×
390
        }
391
        // Case 3: is there a valid head index ?
392
        else if (headVar.isValid())
×
393
        {
394
            Q_ASSERT(item->parent() != NULL);
395
            quint32 fxi = item->parent()->data(KColumnName, PROP_ID).toUInt();
×
396
            GroupHead gh(fxi, headVar.toInt());
×
397
            if (m_selectedHeads.contains(gh) == false)
×
398
                m_selectedHeads << gh;
399
        }
×
400
        // Case 4: is there a valid universe index ?
401
        else if (uniIDVar.isValid())
×
402
        {
403
            qDebug() << "Valid universe....";
404
            // in this case cycle through the children and get each
405
            // fixture ID
406
            for (int i = 0; i < item->childCount(); i++)
×
407
            {
408
                QTreeWidgetItem *child = item->child(i);
×
409
                QVariant chFxIDVar = child->data(KColumnName, PROP_ID);
×
410
                if (chFxIDVar.isValid() && child->isDisabled() == false)
×
411
                    m_selectedFixtures << chFxIDVar.toUInt();
×
412
            }
×
413
        }
414
    }
×
415
}
×
416

417
void FixtureTreeWidget::slotItemExpanded()
×
418
{
419
    header()->resizeSections(QHeaderView::ResizeToContents);
×
420
}
×
421

422
void FixtureTreeWidget::updateTree()
×
423
{
424
    clear();
×
425
    m_universesCount = 0;
×
426
    m_fixturesCount = 0;
×
427
    m_channelsCount = 0;
×
428

429
    if (m_showGroups == true)
×
430
    {
431
        foreach (FixtureGroup* grp, m_doc->fixtureGroups())
×
432
        {
433
            QTreeWidgetItem* grpItem = new QTreeWidgetItem(this);
×
434
            updateGroupItem(grpItem, grp);
×
435
        }
436
    }
437

438
    foreach (Fixture* fixture, m_doc->fixtures())
×
439
    {
440
        Q_ASSERT(fixture != NULL);
441

442
        QTreeWidgetItem *topItem = NULL;
443
        quint32 uni = fixture->universe();
×
444
        for (int i = 0; i < topLevelItemCount(); i++)
×
445
        {
446
            QTreeWidgetItem* tItem = topLevelItem(i);
×
447
            QVariant tVar = tItem->data(KColumnName, PROP_UNIVERSE);
×
448
            if (tVar.isValid())
×
449
            {
450
                quint32 tUni = tVar.toUInt();
×
451
                if (tUni == uni)
×
452
                {
453
                    topItem = tItem;
454
                    break;
455
                }
456
            }
457
        }
×
458
        // Haven't found this universe node ? Create it.
459
        if (topItem == NULL)
×
460
        {
461
            topItem = new QTreeWidgetItem(this);
×
462
            topItem->setText(KColumnName, m_doc->inputOutputMap()->getUniverseNameByID(uni));
×
463
            topItem->setIcon(KColumnName, QIcon(":/group.png"));
×
464
            topItem->setData(KColumnName, PROP_UNIVERSE, uni);
×
465
            topItem->setExpanded(true);
×
466
            if (m_channelSelection)
×
467
            {
468
                topItem->setFlags(topItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsAutoTristate);
×
469
                topItem->setCheckState(KColumnName, Qt::Unchecked);
×
470
            }
471
            m_universesCount++;
×
472
        }
473

474
        QTreeWidgetItem *fItem = new QTreeWidgetItem(topItem);
×
475
        updateFixtureItem(fItem, fixture);
×
476
        m_fixturesCount++;
×
477
        m_channelsCount += fixture->channels();
×
478
    }
479

480
    header()->resizeSections(QHeaderView::ResizeToContents);
×
481
}
×
482

483

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