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

mcallegari / qlcplus / 10668847825

02 Sep 2024 02:18PM UTC coverage: 31.426% (-0.07%) from 31.498%
10668847825

push

github

web-flow
Merge pull request #1610 from Ledjlale/fix/qt6_rebase2

qmltoqt6 rebasing

25 of 290 new or added lines in 19 files covered. (8.62%)

25 existing lines in 11 files now uncovered.

15012 of 47769 relevant lines covered (31.43%)

19745.74 hits per line

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

0.0
/ui/src/fixturemanager.cpp
1
/*
2
  Q Light Controller
3
  fixturemanager.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 <QTreeWidgetItem>
23
#include <QTextBrowser>
24
#include <QVBoxLayout>
25
#include <QTreeWidget>
26
#include <QScrollArea>
27
#include <QMessageBox>
28
#include <QToolButton>
29
#include <QFileDialog>
30
#include <QTabWidget>
31
#include <QSplitter>
32
#include <QToolBar>
33
#include <QAction>
34
#include <QString>
35
#include <QDebug>
36
#include <QIcon>
37
#include <QMenu>
38
#include <QtGui>
39

40
#include "qlcfixturemode.h"
41
#include "qlcfixturedef.h"
42
#include "qlcchannel.h"
43
#include "qlcfile.h"
44

45
#include "createfixturegroup.h"
46
#include "fixturegroupeditor.h"
47
#include "fixturetreewidget.h"
48
#include "channelsselection.h"
49
#include "addchannelsgroup.h"
50
#include "fixturemanager.h"
51
#include "fixtureremap.h"
52
#include "addrgbpanel.h"
53
#include "addfixture.h"
54
#include "rdmmanager.h"
55
#include "universe.h"
56
#include "fixture.h"
57
#include "apputil.h"
58
#include "doc.h"
59

60
#define SETTINGS_SPLITTER "fixturemanager/splitterstate"
61

62
// List view column numbers
63
#define KColumnName     0
64
#define KColumnChannels 1
65
#define KColumnAddress  2
66

67
#define KXMLQLCFixturesList QString("FixtureList")
68

69
FixtureManager* FixtureManager::s_instance = NULL;
70

71
/*****************************************************************************
72
 * Initialization
73
 *****************************************************************************/
74

75
FixtureManager::FixtureManager(QWidget* parent, Doc* doc)
×
76
    : QWidget(parent)
77
    , m_doc(doc)
78
    , m_splitter(NULL)
79
    , m_fixtures_tree(NULL)
80
    , m_channel_groups_tree(NULL)
81
    , m_rdmManager(NULL)
82
    , m_info(NULL)
83
    , m_groupEditor(NULL)
84
    , m_currentTabIndex(0)
85
    , m_addAction(NULL)
86
    , m_addRGBAction(NULL)
87
    , m_removeAction(NULL)
88
    , m_propertiesAction(NULL)
89
    , m_fadeConfigAction(NULL)
90
    , m_remapAction(NULL)
91
    , m_groupAction(NULL)
92
    , m_unGroupAction(NULL)
93
    , m_newGroupAction(NULL)
94
    , m_moveUpAction(NULL)
95
    , m_moveDownAction(NULL)
96
    , m_importAction(NULL)
97
    , m_exportAction(NULL)
98
    , m_groupMenu(NULL)
×
99
{
100
    Q_ASSERT(s_instance == NULL);
×
101
    s_instance = this;
×
102

103
    Q_ASSERT(doc != NULL);
×
104

105
    new QVBoxLayout(this);
×
106
    layout()->setContentsMargins(0, 0, 0, 0);
×
107
    layout()->setSpacing(0);
×
108

109
    initActions();
×
110
    initToolBar();
×
111
    initDataView();
×
112
    updateView();
×
113
    updateChannelsGroupView();
×
114

115
    QTreeWidgetItem* grpItem = m_fixtures_tree->topLevelItem(0);
×
116
    if (grpItem != NULL)
×
117
        grpItem->setExpanded(true);
×
118

119
    /* Connect fixture list change signals from the new document object */
120
    connect(m_doc, SIGNAL(fixtureRemoved(quint32)),
×
121
            this, SLOT(slotFixtureRemoved(quint32)));
122

123
    connect(m_doc, SIGNAL(channelsGroupRemoved(quint32)),
×
124
            this, SLOT(slotChannelsGroupRemoved(quint32)));
125

126
    connect(m_doc, SIGNAL(modeChanged(Doc::Mode)),
×
127
            this, SLOT(slotModeChanged(Doc::Mode)));
128

129
    connect(m_doc, SIGNAL(fixtureGroupRemoved(quint32)),
×
130
            this, SLOT(slotFixtureGroupRemoved(quint32)));
131

132
    connect(m_doc, SIGNAL(fixtureGroupChanged(quint32)),
×
133
            this, SLOT(slotFixtureGroupChanged(quint32)));
134

135
    connect(m_doc, SIGNAL(loaded()),
×
136
            this, SLOT(slotDocLoaded()));
137

138
    slotModeChanged(m_doc->mode());
×
139

140
    QSettings settings;
×
141
    QVariant var = settings.value(SETTINGS_SPLITTER);
×
142
    if (var.isValid() == true)
×
143
        m_splitter->restoreState(var.toByteArray());
×
144
    else
145
        m_splitter->setSizes(QList <int> () << int(this->width() / 2) << int(this->width() / 2));
×
146
}
×
147

148
FixtureManager::~FixtureManager()
×
149
{
150
    QSettings settings;
×
151
    settings.setValue(SETTINGS_SPLITTER, m_splitter->saveState());
×
152
    FixtureManager::s_instance = NULL;
×
153

154
    s_instance = NULL;
×
155
}
×
156

157
FixtureManager* FixtureManager::instance()
×
158
{
159
    return s_instance;
×
160
}
161

162
/*****************************************************************************
163
 * Doc signal handlers
164
 *****************************************************************************/
165

166
void FixtureManager::slotFixtureRemoved(quint32 id)
×
167
{
168
    QList<QTreeWidgetItem*> groupsToDelete;
×
169

170
    for (int i = 0; i < m_fixtures_tree->topLevelItemCount(); i++)
×
171
    {
172
        QTreeWidgetItem* grpItem = m_fixtures_tree->topLevelItem(i);
×
173
        Q_ASSERT(grpItem != NULL);
×
174
        for (int j = 0; j < grpItem->childCount(); j++)
×
175
        {
176
            QTreeWidgetItem* fxiItem = grpItem->child(j);
×
177
            Q_ASSERT(fxiItem != NULL);
×
178
            QVariant var = fxiItem->data(KColumnName, PROP_ID);
×
179
            if (var.isValid() == true && var.toUInt() == id)
×
180
            {
181
                delete fxiItem;
×
182
                break;
×
183
            }
184
        }
185
        if (grpItem->childCount() == 0)
×
186
            groupsToDelete << grpItem;
×
187
    }
188
    foreach (QTreeWidgetItem* groupToDelete, groupsToDelete)
×
189
    {
190
        QVariant var = groupToDelete->data(KColumnName, PROP_GROUP);
×
191
        // If the group is a fixture group, delete it from doc.
192
        // If not, it is a universe, just "hide" it from the ui.
193
        if (var.isValid() == true)
×
194
            m_doc->deleteFixtureGroup(groupToDelete->data(KColumnName, PROP_GROUP).toUInt());
×
195
        else
196
            delete groupToDelete;
×
197
    }
198
}
×
199

200
void FixtureManager::slotChannelsGroupRemoved(quint32 id)
×
201
{
202
    qDebug() << "Channel group removed: " << id;
×
203
    for (int i = 0; i < m_channel_groups_tree->topLevelItemCount(); i++)
×
204
    {
205
        QTreeWidgetItem* grpItem = m_channel_groups_tree->topLevelItem(i);
×
206
        Q_ASSERT(grpItem != NULL);
×
207
        QVariant var = grpItem->data(KColumnName, PROP_ID);
×
208
        if (var.isValid() == true && var.toUInt() == id)
×
209
            delete grpItem;
×
210
    }
211
}
×
212

213
void FixtureManager::slotModeChanged(Doc::Mode mode)
×
214
{
215
    if (mode == Doc::Design)
×
216
    {
217
        int selected = m_fixtures_tree->selectedItems().size();
×
218

219
        QTreeWidgetItem* item = m_fixtures_tree->currentItem();
×
220
        if (item == NULL)
×
221
        {
222
            m_addAction->setEnabled(true);
×
223
            m_addRGBAction->setEnabled(true);
×
224
            m_removeAction->setEnabled(false);
×
225
            m_propertiesAction->setEnabled(false);
×
226
            m_groupAction->setEnabled(false);
×
227
            m_unGroupAction->setEnabled(false);
×
228
            m_importAction->setEnabled(true);
×
229
        }
230
        else if (item->data(KColumnName, PROP_ID).isValid() == true)
×
231
        {
232
            // Fixture selected
233
            m_addAction->setEnabled(true);
×
234
            m_addRGBAction->setEnabled(true);
×
235
            m_removeAction->setEnabled(true);
×
236
            if (selected == 1)
×
237
                m_propertiesAction->setEnabled(true);
×
238
            else
239
                m_propertiesAction->setEnabled(false);
×
240
            m_groupAction->setEnabled(true);
×
241

242
            // Don't allow ungrouping from the "All fixtures" group
243
            if (item->parent()->data(KColumnName, PROP_GROUP).isValid() == true)
×
244
                m_unGroupAction->setEnabled(true);
×
245
            else
246
                m_unGroupAction->setEnabled(false);
×
247
        }
248
        else if (item->data(KColumnName, PROP_GROUP).isValid() == true)
×
249
        {
250
            // Fixture group selected
251
            m_addAction->setEnabled(true);
×
252
            m_addRGBAction->setEnabled(true);
×
253
            m_removeAction->setEnabled(true);
×
254
            m_propertiesAction->setEnabled(false);
×
255
            m_groupAction->setEnabled(false);
×
256
            m_unGroupAction->setEnabled(false);
×
257
        }
258
        else
259
        {
260
            // All fixtures selected
261
            m_addAction->setEnabled(true);
×
262
            m_addRGBAction->setEnabled(true);
×
263
            m_removeAction->setEnabled(false);
×
264
            m_propertiesAction->setEnabled(false);
×
265
            m_groupAction->setEnabled(false);
×
266
            m_unGroupAction->setEnabled(false);
×
267
        }
268
        if (m_doc->fixtures().count() > 0)
×
269
            m_fadeConfigAction->setEnabled(true);
×
270
        else
271
            m_fadeConfigAction->setEnabled(false);
×
272
    }
273
    else
274
    {
275
        m_addAction->setEnabled(false);
×
276
        m_addRGBAction->setEnabled(false);
×
277
        m_removeAction->setEnabled(false);
×
278
        m_propertiesAction->setEnabled(false);
×
279
        m_fadeConfigAction->setEnabled(false);
×
280
        m_groupAction->setEnabled(false);
×
281
        m_unGroupAction->setEnabled(false);
×
282
    }
283
}
×
284

285
void FixtureManager::slotFixtureGroupRemoved(quint32 id)
×
286
{
287
    for (int i = 0; i < m_fixtures_tree->topLevelItemCount(); i++)
×
288
    {
289
        QTreeWidgetItem* item = m_fixtures_tree->topLevelItem(i);
×
290
        Q_ASSERT(item != NULL);
×
291
        QVariant var = item->data(KColumnName, PROP_GROUP);
×
292
        if (var.isValid() && var.toUInt() == id)
×
293
        {
294
            delete item;
×
295
            break;
×
296
        }
297
    }
298

299
    updateGroupMenu();
×
300
}
×
301

302
void FixtureManager::slotFixtureGroupChanged(quint32 id)
×
303
{
304
    QTreeWidgetItem* item = m_fixtures_tree->groupItem(id);
×
305
    if (item == NULL)
×
306
        return;
×
307

308
    FixtureGroup* grp = m_doc->fixtureGroup(id);
×
309
    Q_ASSERT(grp != NULL);
×
310
    m_fixtures_tree->updateGroupItem(item, grp);
×
311
    updateGroupMenu();
×
312
}
313

314
void FixtureManager::slotDocLoaded()
×
315
{
316
    slotTabChanged(m_currentTabIndex);
×
317
}
×
318

319
/*****************************************************************************
320
 * Data view
321
 *****************************************************************************/
322

323
void FixtureManager::initDataView()
×
324
{
325
    // Create a splitter to divide list view and text view
326
    m_splitter = new QSplitter(Qt::Horizontal, this);
×
327
    layout()->addWidget(m_splitter);
×
328
    m_splitter->setSizePolicy(QSizePolicy::Expanding,
×
329
                              QSizePolicy::Expanding);
330

331
    QTabWidget *tabs = new QTabWidget(this);
×
332
    m_splitter->addWidget(tabs);
×
333

334
    /* Create a tree widget to the left part of the splitter */
335
    quint32 treeFlags = FixtureTreeWidget::UniverseNumber |
×
336
                        FixtureTreeWidget::AddressRange |
337
                        FixtureTreeWidget::ShowGroups;
338

339
    m_fixtures_tree = new FixtureTreeWidget(m_doc, treeFlags, this);
×
340
    m_fixtures_tree->setIconSize(QSize(32, 32));
×
341
    m_fixtures_tree->setContextMenuPolicy(Qt::CustomContextMenu);
×
342
    m_fixtures_tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
×
343
    m_fixtures_tree->sortByColumn(KColumnAddress, Qt::AscendingOrder);
×
344

345
    connect(m_fixtures_tree, SIGNAL(itemSelectionChanged()),
×
346
            this, SLOT(slotSelectionChanged()));
347

348
    connect(m_fixtures_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
×
349
            this, SLOT(slotDoubleClicked(QTreeWidgetItem*)));
350

351
    connect(m_fixtures_tree, SIGNAL(customContextMenuRequested(const QPoint&)),
×
352
            this, SLOT(slotContextMenuRequested(const QPoint&)));
353

354
    connect(m_fixtures_tree, SIGNAL(expanded(QModelIndex)),
×
355
            this, SLOT(slotFixtureItemExpanded()));
356

357
    connect(m_fixtures_tree, SIGNAL(collapsed(QModelIndex)),
×
358
            this, SLOT(slotFixtureItemExpanded()));
359

360
    tabs->addTab(m_fixtures_tree, tr("Fixture Groups"));
×
361

362
    m_channel_groups_tree = new QTreeWidget(this);
×
363
    QStringList chan_labels;
×
364
    chan_labels << tr("Name") << tr("Channels");
×
365
    m_channel_groups_tree->setHeaderLabels(chan_labels);
×
366
    m_channel_groups_tree->setRootIsDecorated(false);
×
367
    m_channel_groups_tree->setAllColumnsShowFocus(true);
×
368
    m_channel_groups_tree->setIconSize(QSize(32, 32));
×
369
    m_channel_groups_tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
×
370

371
    connect(m_channel_groups_tree, SIGNAL(itemSelectionChanged()),
×
372
            this, SLOT(slotChannelsGroupSelectionChanged()));
373
    connect(m_channel_groups_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
×
374
            this, SLOT(slotChannelsGroupDoubleClicked(QTreeWidgetItem*)));
375

376
    tabs->addTab(m_channel_groups_tree, tr("Channel Groups"));
×
377
/*
378
    m_rdmManager = new RDMManager(this, m_doc);
379
    tabs->addTab(m_rdmManager, "RDM");
380
    connect(m_rdmManager, SIGNAL(fixtureInfoReady(QString&)),
381
            this, SLOT(slotDisplayFixtureInfo(QString&)));
382
*/
383
    connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(slotTabChanged(int)));
×
384

385
    /* Create the text view */
386
    createInfo();
×
387

388
    slotSelectionChanged();
×
389
}
×
390

391
void FixtureManager::updateView()
×
392
{
393
    // Record which top level items are open
394
    QList <QVariant> openGroups;
×
395
    for (int i = 0; i < m_fixtures_tree->topLevelItemCount(); i++)
×
396
    {
397
        QTreeWidgetItem* item = m_fixtures_tree->topLevelItem(i);
×
398
        if (item->isExpanded() == true)
×
399
            openGroups << item->data(KColumnName, PROP_GROUP);
×
400
    }
401

402
    if (m_doc->fixtures().count() > 0)
×
403
    {
404
        m_exportAction->setEnabled(true);
×
405
        m_remapAction->setEnabled(true);
×
406
        m_fadeConfigAction->setEnabled(true);
×
407
    }
408
    else
409
    {
410
        m_exportAction->setEnabled(false);
×
411
        m_fadeConfigAction->setEnabled(false);
×
412
        m_remapAction->setEnabled(false);
×
413
    }
414
    m_addRGBAction->setEnabled(true);
×
415
    m_importAction->setEnabled(true);
×
416
    m_moveUpAction->setEnabled(false);
×
417
    m_moveDownAction->setEnabled(false);
×
418

419
    m_fixtures_tree->updateTree();
×
420

421
    // Reopen groups that were open before update
422
    for (int i = 0; i < m_fixtures_tree->topLevelItemCount(); i++)
×
423
    {
424
        QTreeWidgetItem* item = m_fixtures_tree->topLevelItem(i);
×
425
        QVariant var = item->data(KColumnName, PROP_GROUP);
×
426
        if (openGroups.contains(var) == true)
×
427
        {
428
            item->setExpanded(true);
×
429
            openGroups.removeAll(var);
×
430
        }
431
    }
432

433
    updateGroupMenu();
×
434
    slotModeChanged(m_doc->mode());
×
435

436
    m_fixtures_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
437
}
×
438

439
void FixtureManager::updateChannelsGroupView()
×
440
{
441
    quint32 selGroupID = ChannelsGroup::invalidId();
×
442

443
    if (m_channel_groups_tree->selectedItems().size() > 0)
×
444
    {
445
        QTreeWidgetItem *item = m_channel_groups_tree->selectedItems().first();
×
446
        selGroupID = item->data(KColumnName, PROP_ID).toUInt();
×
447
    }
448

449
    if (m_channel_groups_tree->topLevelItemCount() > 0)
×
450
        for (int i = m_channel_groups_tree->topLevelItemCount() - 1; i >= 0; i--)
×
451
            m_channel_groups_tree->takeTopLevelItem(i);
×
452

453
    foreach (ChannelsGroup *grp, m_doc->channelsGroups())
×
454
    {
455
        QTreeWidgetItem *grpItem = new QTreeWidgetItem(m_channel_groups_tree);
×
456
        grpItem->setText(KColumnName, grp->name());
×
457
        grpItem->setData(KColumnName, PROP_ID, grp->id());
×
458
        grpItem->setText(KColumnChannels, QString("%1").arg(grp->getChannels().count()));
×
459
        if (grp->getChannels().count() > 0)
×
460
        {
461
            SceneValue scv = grp->getChannels().at(0);
×
462
            Fixture *fxi = m_doc->fixture(scv.fxi);
×
463
            if (fxi == NULL)
×
464
                continue;
×
465

466
            const QLCChannel *ch = fxi->channel(scv.channel);
×
467
            if (ch != NULL)
×
468
                grpItem->setIcon(KColumnName, ch->getIcon());
×
469
        }
470
        if (selGroupID == grp->id())
×
471
            grpItem->setSelected(true);
×
472
    }
473
    m_addRGBAction->setEnabled(false);
×
474
    m_propertiesAction->setEnabled(false);
×
475
    m_groupAction->setEnabled(false);
×
476
    m_unGroupAction->setEnabled(false);
×
477
    m_fadeConfigAction->setEnabled(false);
×
478
    m_exportAction->setEnabled(false);
×
479
    m_importAction->setEnabled(false);
×
480
    m_remapAction->setEnabled(false);
×
481

482
    m_channel_groups_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
483
}
×
484

485
void FixtureManager::updateRDMView()
×
486
{
487
    m_addRGBAction->setEnabled(false);
×
488
    m_propertiesAction->setEnabled(false);
×
489
    m_groupAction->setEnabled(false);
×
490
    m_unGroupAction->setEnabled(false);
×
491
    m_fadeConfigAction->setEnabled(false);
×
492
    m_exportAction->setEnabled(false);
×
493
    m_importAction->setEnabled(false);
×
494
    m_remapAction->setEnabled(false);
×
495
}
×
496

497
void FixtureManager::fixtureSelected(quint32 id)
×
498
{
499
    Fixture* fxi = m_doc->fixture(id);
×
500
    if (fxi == NULL)
×
501
        return;
×
502

503
    if (m_info == NULL)
×
504
        createInfo();
×
505

506
    m_info->setText(QString("%1<BODY>%2</BODY></HTML>")
×
507
                    .arg(fixtureInfoStyleSheetHeader())
×
508
                    .arg(fxi->status()));
×
509

510
    // Enable/disable actions
511
    slotModeChanged(m_doc->mode());
×
512
}
513

514
void FixtureManager::fixtureGroupSelected(FixtureGroup* grp)
×
515
{
516
    QByteArray state = m_splitter->saveState();
×
517

518
    if (m_info != NULL)
×
519
    {
520
        delete m_info;
×
521
        m_info = NULL;
×
522
    }
523

524
    if (m_groupEditor != NULL)
×
525
    {
526
        delete m_groupEditor;
×
527
        m_groupEditor = NULL;
×
528
    }
529

530
    m_groupEditor = new FixtureGroupEditor(grp, m_doc, this);
×
531
    m_splitter->addWidget(m_groupEditor);
×
532

533
    m_splitter->restoreState(state);
×
534
}
×
535

536
void FixtureManager::createInfo()
×
537
{
538
    QByteArray state = m_splitter->saveState();
×
539

540
    if (m_info != NULL)
×
541
    {
542
        delete m_info;
×
543
        m_info = NULL;
×
544
    }
545

546
    if (m_groupEditor != NULL)
×
547
    {
548
        delete m_groupEditor;
×
549
        m_groupEditor = NULL;
×
550
    }
551

552
    m_info = new QTextBrowser(this);
×
553
    m_splitter->addWidget(m_info);
×
554

555
    m_splitter->restoreState(state);
×
556
}
×
557

558
void FixtureManager::slotSelectionChanged()
×
559
{
560
    int selectedCount = m_fixtures_tree->selectedItems().size();
×
561
    if (selectedCount == 1)
×
562
    {
563
        QTreeWidgetItem* item = m_fixtures_tree->selectedItems().first();
×
564
        Q_ASSERT(item != NULL);
×
565

566
        // Set the text view's contents
567
        QVariant fxivar = item->data(KColumnName, PROP_ID);
×
568
        QVariant grpvar = item->data(KColumnName, PROP_GROUP);
×
569
        if (fxivar.isValid() == true)
×
570
        {
571
            // Selected a fixture
572
            fixtureSelected(fxivar.toUInt());
×
573
        }
574
        else if (grpvar.isValid() == true)
×
575
        {
576
            FixtureGroup* grp = m_doc->fixtureGroup(grpvar.toUInt());
×
577
            Q_ASSERT(grp != NULL);
×
578
            fixtureGroupSelected(grp);
×
579
        }
580
        else
581
        {
582
            QString info = "<HTML><BODY>";
×
583
            QString uniName;
×
584
            double totalWeight = 0;
×
585
            int totalPower = 0;
×
586
            QVariant uniID = item->data(KColumnName, PROP_UNIVERSE);
×
587
            if (uniID.isValid() == true)
×
588
                uniName = m_doc->inputOutputMap()->getUniverseNameByID(uniID.toUInt());
×
589

590
            foreach (Fixture *fixture, m_doc->fixtures())
×
591
            {
592
                if (fixture == NULL || fixture->universe() != uniID.toUInt() || fixture->fixtureMode() == NULL)
×
593
                    continue;
×
594

595
                QLCFixtureMode *mode = fixture->fixtureMode();
×
596
                totalWeight += mode->physical().weight();
×
597
                totalPower += mode->physical().powerConsumption();
×
598
            }
599

600
            if (m_info == NULL)
×
601
                createInfo();
×
602

603
            info += QString("<H1>%1</H1><P>%2 <B>%3</B></P>")
×
604
                    .arg(uniName).arg(tr("This group contains all fixtures of"))
×
605
                    .arg(uniName);
×
606

607
            info += QString("<BR><P><B>%1</B>: %2Kg<BR><B>%3</B>: %4W</P>")
×
608
                    .arg(tr("Total estimated weight")).arg(QString::number(totalWeight))
×
609
                    .arg(tr("Maximum estimated power consumption")).arg(totalPower);
×
610

611
            info += "</BODY></HTML>";
×
612

613
            m_info->setText(info);
×
614
        }
615
    }
616
    else
617
    {
618
        // More than one or less than one selected
619
        QString info = "<HTML><BODY>";
×
620
        if (selectedCount > 1)
×
621
        {
622
            // Enable removal of multiple items in design mode
623
            if (m_doc->mode() == Doc::Design)
×
624
            {
625
                double totalWeight = 0;
×
626
                int totalPower = 0;
×
627

628
                info += tr("<H1>Multiple fixtures selected</H1>" \
×
629
                          "<P>Click <IMG SRC=\"" ":/edit_remove.png\">" \
630
                          " to remove the selected fixtures.</P>");
×
631

632
                foreach (QTreeWidgetItem *item, m_fixtures_tree->selectedItems())
×
633
                {
634
                    QVariant fxID = item->data(KColumnName, PROP_ID);
×
635
                    if (fxID.isValid() == false)
×
636
                        continue;
×
637

638
                    Fixture *fixture = m_doc->fixture(fxID.toUInt());
×
639

640
                    if (fixture == NULL || fixture->fixtureMode() == NULL)
×
641
                        continue;
×
642

643
                    QLCFixtureMode *mode = fixture->fixtureMode();
×
644
                    totalWeight += mode->physical().weight();
×
645
                    totalPower += mode->physical().powerConsumption();
×
646
                }
647

648
                info += QString("<BR><P><B>%1</B>: %2Kg<BR><B>%3</B>: %4W</P>")
×
649
                        .arg(tr("Total estimated weight")).arg(QString::number(totalWeight))
×
650
                        .arg(tr("Maximum estimated power consumption")).arg(totalPower);
×
651
            }
652
            else
653
            {
654
                info += tr("<H1>Multiple fixtures selected</H1>" \
×
655
                          "<P>Fixture list modification is not permitted" \
656
                          " in operate mode.</P>");
×
657
            }
658
        }
659
        else
660
        {
661
            if (m_fixtures_tree->topLevelItemCount() <= 0)
×
662
            {
663
                info += tr("<H1>No fixtures</H1>" \
×
664
                          "<P>Click <IMG SRC=\"" ":/edit_add.png\">" \
665
                          " to add fixtures.</P>");
×
666
            }
667
            else
668
            {
669
                info += tr("<H1>Nothing selected</H1>" \
×
670
                          "<P>Select a fixture from the list or " \
671
                          "click <IMG SRC=\"" ":/edit_add.png\">" \
672
                          " to add fixtures.</P>");
×
673
            }
674
        }
675
        info += "</BODY></HTML>";
×
676

677
        if (m_info == NULL)
×
678
            createInfo();
×
679
        m_info->setText(info);
×
680
    }
681

682
    // Enable/disable actions
683
    slotModeChanged(m_doc->mode());
×
684
}
×
685

686
void FixtureManager::slotChannelsGroupSelectionChanged()
×
687
{
688
    if (m_info == NULL)
×
689
        createInfo();
×
690

691
    int selectedCount = m_channel_groups_tree->selectedItems().size();
×
692

693
    if (selectedCount == 1)
×
694
    {
695
        QTreeWidgetItem* item = m_channel_groups_tree->selectedItems().first();
×
696
        Q_ASSERT(item != NULL);
×
697

698
        // Set the text view's contents
699
        QVariant grpvar = item->data(KColumnName, PROP_ID);
×
700
        if (grpvar.isValid() == true)
×
701
        {
702
            ChannelsGroup *chGroup = m_doc->channelsGroup(grpvar.toUInt());
×
703
            if (chGroup != NULL)
×
704
                m_info->setText(QString("%1<BODY>%2</BODY></HTML>")
×
705
                                .arg(channelsGroupInfoStyleSheetHeader())
×
706
                                .arg(chGroup->status(m_doc)));
×
707
        }
708
        m_removeAction->setEnabled(true);
×
709
        m_propertiesAction->setEnabled(true);
×
710
        int selIdx = m_channel_groups_tree->currentIndex().row();
×
711
        if (selIdx == 0)
×
712
            m_moveUpAction->setEnabled(false);
×
713
        else
714
            m_moveUpAction->setEnabled(true);
×
715
        if (selIdx == m_channel_groups_tree->topLevelItemCount() - 1)
×
716
            m_moveDownAction->setEnabled(false);
×
717
        else
718
            m_moveDownAction->setEnabled(true);
×
719
    }
720
    else if (selectedCount > 1)
×
721
    {
722
        m_info->setText(tr("<HTML><BODY><H1>Multiple groups selected</H1>" \
×
723
                  "<P>Click <IMG SRC=\"" ":/edit_remove.png\">" \
724
                  " to remove the selected groups.</P></BODY></HTML>"));
725
        m_removeAction->setEnabled(true);
×
726
        m_propertiesAction->setEnabled(false);
×
727
    }
728
    else
729
    {
730
        m_info->setText(tr("<HTML><BODY><H1>Nothing selected</H1>" \
×
731
                  "<P>Select a channel group from the list or " \
732
                  "click <IMG SRC=\"" ":/edit_add.png\">" \
733
                  " to add a new channels group.</P></BODY></HTML>"));
734
        m_removeAction->setEnabled(false);
×
735
        m_propertiesAction->setEnabled(false);
×
736
    }
737
}
×
738

739
void FixtureManager::slotDoubleClicked(QTreeWidgetItem* item)
×
740
{
741
    if (item != NULL && m_doc->mode() != Doc::Operate)
×
742
        slotProperties();
×
743
}
×
744

745
void FixtureManager::slotChannelsGroupDoubleClicked(QTreeWidgetItem*)
×
746
{
747
    slotChannelsGroupSelectionChanged();
×
748
    editChannelGroupProperties();
×
749
}
×
750

751
void FixtureManager::slotTabChanged(int index)
×
752
{
753
    if (index == 1)
×
754
    {
755
        m_addAction->setToolTip(tr("Add group..."));
×
756
        updateChannelsGroupView();
×
757
        slotChannelsGroupSelectionChanged();
×
758
    }
759
    else if (index == 2)
×
760
    {
761
        m_addAction->setToolTip(tr("Add fixture..."));
×
762
        updateRDMView();
×
763
    }
764
    else
765
    {
766
        m_addAction->setToolTip(tr("Add fixture..."));
×
767
        updateView();
×
768
        slotSelectionChanged();
×
769
    }
770

771
    m_currentTabIndex = index;
×
772
}
×
773

774
void FixtureManager::slotFixtureItemExpanded()
×
775
{
776
    m_fixtures_tree->header()->resizeSections(QHeaderView::ResizeToContents);
×
777
}
×
778

779
void FixtureManager::slotDisplayFixtureInfo(QString &info)
×
780
{
781
    m_info->setText(info);
×
782
}
×
783

784
void FixtureManager::selectGroup(quint32 id)
×
785
{
786
    for (int i = 0; i < m_fixtures_tree->topLevelItemCount(); i++)
×
787
    {
788
        QTreeWidgetItem* item = m_fixtures_tree->topLevelItem(i);
×
789
        QVariant var = item->data(KColumnName, PROP_GROUP);
×
790
        if (var.isValid() == false)
×
791
            continue;
×
792

793
        if (var.toUInt() == id)
×
794
        {
795
            m_fixtures_tree->setCurrentItem(item);
×
796
            slotSelectionChanged();
×
797
            break;
×
798
        }
799
    }
800
}
×
801

802
QString FixtureManager::fixtureInfoStyleSheetHeader()
×
803
{
804
    QString info;
×
805

806
    QPalette pal;
×
807
    QColor hlBack(pal.color(QPalette::Highlight));
×
808
    QColor hlText(pal.color(QPalette::HighlightedText));
×
809

810
    info += "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
×
811
    info += "<HTML><HEAD></HEAD><STYLE>";
×
812
    info += QString(".hilite {" \
×
813
                    "        background-color: %1;" \
814
                    "        color: %2;" \
815
                    "        font-size: x-large;" \
816
                    "}").arg(hlBack.name()).arg(hlText.name());
×
817
    info += QString(".subhi {" \
×
818
                    "        background-color: %1;" \
819
                    "        color: %2;" \
820
                    "        font-weight: bold;" \
821
                    "}").arg(hlBack.name()).arg(hlText.name());
×
822
    info += QString(".emphasis {" \
×
823
                    "        font-weight: bold;" \
824
                    "}");
×
825
    info += QString(".tiny {"\
×
826
                    "   font-size: small;" \
827
                    "}");
×
828
    info += QString(".author {" \
×
829
                    "        font-weight: light;" \
830
                    "        font-style: italic;" \
831
                    "   text-align: right;" \
832
                    "   font-size: small;"  \
833
                    "}");
×
834
    info += "</STYLE>";
×
835
    return info;
×
836
}
837

838
QString FixtureManager::channelsGroupInfoStyleSheetHeader()
×
839
{
840
    QString info;
×
841

842
    QPalette pal;
×
843
    QColor hlBack(pal.color(QPalette::Highlight));
×
844
    QColor hlBackSmall(pal.color(QPalette::Shadow));
×
845
    QColor hlText(pal.color(QPalette::HighlightedText));
×
846

847
    info += "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">";
×
848
    info += "<HTML><HEAD></HEAD><STYLE>";
×
849
    info += QString(".hilite {" \
×
850
                    "        background-color: %1;" \
851
                    "        color: %2;" \
852
                    "        font-size: x-large;" \
853
                    "}").arg(hlBack.name()).arg(hlText.name());
×
854
    info += QString(".subhi {" \
×
855
                    "        background-color: %1;" \
856
                    "        color: %2;" \
857
                    "        font-weight: bold;" \
858
                    "}").arg(hlBackSmall.name()).arg(hlText.name());
×
859
    info += QString(".emphasis {" \
×
860
                    "        font-weight: bold;" \
861
                    "}");
×
862
    info += QString(".tiny {"\
×
863
                    "   font-size: small;" \
864
                    "}");
×
865
    info += "</STYLE>";
×
866
    return info;
×
867
}
868

869
/*****************************************************************************
870
 * Menu, toolbar and actions
871
 *****************************************************************************/
872

873
void FixtureManager::initActions()
×
874
{
875
    // Fixture actions
876
    m_addAction = new QAction(QIcon(":/edit_add.png"),
×
877
                              tr("Add fixture..."), this);
×
878
    connect(m_addAction, SIGNAL(triggered(bool)),
×
879
            this, SLOT(slotAdd()));
880

881
    m_addRGBAction = new QAction(QIcon(":/rgbpanel.png"),
×
882
                              tr("Add RGB panel..."), this);
×
883
    connect(m_addRGBAction, SIGNAL(triggered(bool)),
×
884
            this, SLOT(slotAddRGBPanel()));
885

886
    m_removeAction = new QAction(QIcon(":/edit_remove.png"),
×
887
                                 tr("Delete items"), this);
×
888
    connect(m_removeAction, SIGNAL(triggered(bool)),
×
889
            this, SLOT(slotRemove()));
890

891
    m_propertiesAction = new QAction(QIcon(":/configure.png"),
×
892
                                     tr("Properties..."), this);
×
893
    connect(m_propertiesAction, SIGNAL(triggered(bool)),
×
894
            this, SLOT(slotProperties()));
895

896
    m_fadeConfigAction = new QAction(QIcon(":/fade.png"),
×
897
                                     tr("Channels Fade Configuration..."), this);
×
898
    connect(m_fadeConfigAction, SIGNAL(triggered(bool)),
×
899
            this, SLOT(slotFadeConfig()));
900

901
    // Group actions
902
    m_groupAction = new QAction(QIcon(":/group.png"),
×
903
                                tr("Add fixture to group..."), this);
×
904

905
    m_unGroupAction = new QAction(QIcon(":/ungroup.png"),
×
906
                                tr("Remove fixture from group"), this);
×
907
    connect(m_unGroupAction, SIGNAL(triggered(bool)),
×
908
            this, SLOT(slotUnGroup()));
909

910
    m_newGroupAction = new QAction(tr("New Group..."), this);
×
911

912
    m_moveUpAction = new QAction(QIcon(":/up.png"),
×
NEW
913
                                 tr("Move channel group up..."), this);
×
914
    m_moveUpAction->setEnabled(false);
×
915
    connect(m_moveUpAction, SIGNAL(triggered(bool)),
×
916
            this, SLOT(slotMoveGroupUp()));
917

918
    m_moveDownAction = new QAction(QIcon(":/down.png"),
×
NEW
919
                                 tr("Move channel group down..."), this);
×
920
    m_moveDownAction->setEnabled(false);
×
921
    connect(m_moveDownAction, SIGNAL(triggered(bool)),
×
922
            this, SLOT(slotMoveGroupDown()));
923

924
    m_importAction = new QAction(QIcon(":/fileimport.png"),
×
925
                                 tr("Import fixtures..."), this);
×
926
    connect(m_importAction, SIGNAL(triggered(bool)),
×
927
            this, SLOT(slotImport()));
928

929
    m_exportAction = new QAction(QIcon(":/fileexport.png"),
×
930
                                 tr("Export fixtures..."), this);
×
931

932
    connect(m_exportAction, SIGNAL(triggered(bool)),
×
933
            this, SLOT(slotExport()));
934

935
    m_remapAction = new QAction(QIcon(":/remap.png"),
×
936
                               tr("Remap fixtures..."), this);
×
937
    connect(m_remapAction, SIGNAL(triggered(bool)),
×
938
            this, SLOT(slotRemap()));
939
}
×
940

941
void FixtureManager::updateGroupMenu()
×
942
{
943
    if (m_groupMenu == NULL)
×
944
    {
945
        m_groupMenu = new QMenu(this);
×
946
        connect(m_groupMenu, SIGNAL(triggered(QAction*)),
×
947
                this, SLOT(slotGroupSelected(QAction*)));
948
    }
949

950
    foreach (QAction* a, m_groupMenu->actions())
×
951
        m_groupMenu->removeAction(a);
×
952

953
    // Put all known fixture groups to the menu
954
    foreach (FixtureGroup* grp, m_doc->fixtureGroups())
×
955
    {
956
        QAction* a = m_groupMenu->addAction(grp->name());
×
957
        a->setData((qulonglong) grp);
×
958
    }
959

960
    // Put a new group action to the group menu
961
    m_groupMenu->addAction(m_newGroupAction);
×
962

963
    // Put the group menu to the group action
964
    m_groupAction->setMenu(m_groupMenu);
×
965
}
×
966

967
void FixtureManager::initToolBar()
×
968
{
969
    QToolBar* toolbar = new QToolBar(tr("Fixture manager"), this);
×
970
    toolbar->setFloatable(false);
×
971
    toolbar->setMovable(false);
×
972
    layout()->setMenuBar(toolbar);
×
973
    toolbar->addAction(m_addAction);
×
974
    toolbar->addAction(m_addRGBAction);
×
975
    toolbar->addAction(m_removeAction);
×
976
    toolbar->addAction(m_propertiesAction);
×
977
    toolbar->addAction(m_fadeConfigAction);
×
978
    toolbar->addSeparator();
×
979
    toolbar->addAction(m_groupAction);
×
980
    toolbar->addAction(m_unGroupAction);
×
981
    toolbar->addSeparator();
×
982
    toolbar->addAction(m_moveUpAction);
×
983
    toolbar->addAction(m_moveDownAction);
×
984
    toolbar->addSeparator();
×
985
    toolbar->addAction(m_importAction);
×
986
    toolbar->addAction(m_exportAction);
×
987
    toolbar->addAction(m_remapAction);
×
988

989
    QToolButton* btn = qobject_cast<QToolButton*> (toolbar->widgetForAction(m_groupAction));
×
990
    Q_ASSERT(btn != NULL);
×
991
    btn->setPopupMode(QToolButton::InstantPopup);
×
992
}
×
993

994
void FixtureManager::addFixture()
×
995
{
996
    AddFixture af(this, m_doc);
×
997
    if (af.exec() == QDialog::Rejected)
×
998
        return;
×
999

1000
    if (af.invalidAddress())
×
1001
    {
1002
        QMessageBox msg(QMessageBox::Critical, tr("Error"),
×
1003
                tr("Please enter a valid address"), QMessageBox::Ok);
×
1004
        msg.exec();
×
1005
        return;
×
1006
    }
1007

1008
    quint32 latestFxi = Fixture::invalidId();
×
1009

1010
    QString name = af.name();
×
1011
    quint32 address = af.address();
×
1012
    quint32 universe = af.universe();
×
1013
    quint32 channels = af.channels();
×
1014
    int gap = af.gap();
×
1015

1016
    QLCFixtureDef* fixtureDef = af.fixtureDef();
×
1017
    QLCFixtureMode* mode = af.mode();
×
1018

1019
    FixtureGroup* addToGroup = NULL;
×
1020
    QTreeWidgetItem* current = m_fixtures_tree->currentItem();
×
1021
    if (current != NULL)
×
1022
    {
1023
        if (current->parent() != NULL)
×
1024
        {
1025
            // Fixture selected
1026
            QVariant var = current->parent()->data(KColumnName, PROP_GROUP);
×
1027
            if (var.isValid() == true)
×
1028
                addToGroup = m_doc->fixtureGroup(var.toUInt());
×
1029
        }
1030
        else
1031
        {
1032
            // Group selected
1033
            QVariant var = current->data(KColumnName, PROP_GROUP);
×
1034
            if (var.isValid() == true)
×
1035
                addToGroup = m_doc->fixtureGroup(var.toUInt());
×
1036
        }
1037
    }
1038

1039
    /* If an empty name was given use the model instead */
1040
    if (name.simplified().isEmpty())
×
1041
    {
1042
        if (fixtureDef != NULL)
×
1043
            name = fixtureDef->model();
×
1044
        else
1045
            name = tr("Generic Dimmer");
×
1046
    }
1047

1048
    /* Add the rest (if any) WITH address gap */
1049
    for (int i = 0; i < af.amount(); i++)
×
1050
    {
1051
        QString modname;
×
1052

1053
        /* If we're adding more than one fixture,
1054
           append a number to the end of the name */
1055
        if (af.amount() > 1)
×
1056
            modname = QString("%1 #%2").arg(name).arg(i + 1, AppUtil::digits(af.amount()), 10, QChar('0'));
×
1057
        else
1058
            modname = name;
×
1059

1060
        /* Create the fixture */
1061
        Fixture* fxi = new Fixture(m_doc);
×
1062

1063
        /* Assign the next address AFTER the previous fixture
1064
           address space plus gap. */
1065
        fxi->setAddress(address + (i * channels) + (i * gap));
×
1066
        fxi->setUniverse(universe);
×
1067
        fxi->setName(modname);
×
1068
        /* Set a fixture definition & mode if they were
1069
           selected. Otherwise create a fixture definition
1070
           and mode for a generic dimmer. */
1071
        if (fixtureDef != NULL && mode != NULL)
×
1072
        {
1073
            fxi->setFixtureDefinition(fixtureDef, mode);
×
1074
        }
1075
        else
1076
        {
1077
            QLCFixtureDef* genericDef = fxi->genericDimmerDef(channels);
×
1078
            QLCFixtureMode* genericMode = fxi->genericDimmerMode(genericDef, channels);
×
1079
            fxi->setFixtureDefinition(genericDef, genericMode);
×
1080
        }
1081

1082
        m_doc->addFixture(fxi);
×
1083
        latestFxi = fxi->id();
×
1084
        if (addToGroup != NULL)
×
1085
            addToGroup->assignFixture(latestFxi);
×
1086
    }
1087

1088
    QTreeWidgetItem* selectItem = m_fixtures_tree->fixtureItem(latestFxi);
×
1089
    if (selectItem != NULL)
×
1090
        m_fixtures_tree->setCurrentItem(selectItem);
×
1091

1092
    updateView();
×
1093
}
1094

1095
void FixtureManager::addChannelsGroup()
×
1096
{
1097
    ChannelsGroup *group = new ChannelsGroup(m_doc);
×
1098

1099
    AddChannelsGroup cs(this, m_doc, group);
×
1100
    if (cs.exec() == QDialog::Accepted)
×
1101
    {
1102
        qDebug() << "Channels group added. Count: " << group->getChannels().count();
×
1103
        m_doc->addChannelsGroup(group, group->id());
×
1104
        updateChannelsGroupView();
×
1105
    }
1106
    else
1107
        delete group;
×
1108
}
×
1109

1110
void FixtureManager::slotAdd()
×
1111
{
1112
    if (m_currentTabIndex == 1)
×
1113
        addChannelsGroup();
×
1114
    else
1115
        addFixture();
×
1116
}
×
1117

1118
void FixtureManager::slotAddRGBPanel()
×
1119
{
1120
    AddRGBPanel rgb(this, m_doc);
×
1121
    if (rgb.exec() == QDialog::Accepted)
×
1122
    {
1123
        int rows = rgb.rows();
×
1124
        int columns = rgb.columns();
×
1125
        Fixture::Components components = rgb.components();
×
1126

1127
        FixtureGroup *grp = new FixtureGroup(m_doc);
×
1128
        Q_ASSERT(grp != NULL);
×
1129
        grp->setName(rgb.name());
×
1130
        QSize panelSize(columns, rows);
×
1131
        grp->setSize(panelSize);
×
1132
        m_doc->addFixtureGroup(grp);
×
1133
        updateGroupMenu();
×
1134

1135
        int transpose = 0;
×
1136
        if (rgb.direction() == AddRGBPanel::Vertical)
×
1137
        {
1138
                int tmp = columns;
×
1139
                columns = rows;
×
1140
                rows = tmp;
×
1141
                transpose = 1;
×
1142
        }
1143

1144
        QLCFixtureDef *rowDef = NULL;
×
1145
        QLCFixtureMode *rowMode = NULL;
×
1146
        quint32 address = (quint32)rgb.address();
×
1147
        int uniIndex = rgb.universeIndex();
×
1148
        int currRow = 0;
×
1149
        int rowInc = 1;
×
1150
        int xPosStart = 0;
×
1151
        int xPosEnd = columns - 1;
×
1152
        int xPosInc = 1;
×
1153

1154
        quint32 phyWidth = rgb.physicalWidth();
×
1155
        quint32 phyHeight = rgb.physicalHeight() / rows;
×
1156

1157
        if (transpose)
×
1158
        {
1159
                        if (rgb.orientation() == AddRGBPanel::TopRight ||
×
1160
                                rgb.orientation() == AddRGBPanel::BottomRight)
×
1161
                        {
1162
                                currRow = rows -1;
×
1163
                                rowInc = -1;
×
1164
                        }
1165
                        if (rgb.orientation() == AddRGBPanel::BottomRight ||
×
1166
                                rgb.orientation() == AddRGBPanel::BottomLeft)
×
1167
                        {
1168
                                xPosStart = columns - 1;
×
1169
                                xPosEnd = 0;
×
1170
                                xPosInc = -1;
×
1171
                        }
1172
        }
1173
        else
1174
        {
1175
                        if (rgb.orientation() == AddRGBPanel::BottomLeft ||
×
1176
                                rgb.orientation() == AddRGBPanel::BottomRight)
×
1177
                        {
1178
                                currRow = rows -1;
×
1179
                                rowInc = -1;
×
1180
                        }
1181
                        if (rgb.orientation() == AddRGBPanel::TopRight ||
×
1182
                                rgb.orientation() == AddRGBPanel::BottomRight)
×
1183
                        {
1184
                                xPosStart = columns - 1;
×
1185
                                xPosEnd = 0;
×
1186
                                xPosInc = -1;
×
1187
                        }
1188
        }
1189

1190
        for (int i = 0; i < rows; i++)
×
1191
        {
1192
            Fixture *fxi = new Fixture(m_doc);
×
1193
            Q_ASSERT(fxi != NULL);
×
1194
            fxi->setName(tr("%1 - Row %2").arg(rgb.name()).arg(i + 1));
×
1195
            if (rowDef == NULL)
×
1196
                rowDef = fxi->genericRGBPanelDef(columns, components);
×
1197
            if (rowMode == NULL)
×
1198
                rowMode = fxi->genericRGBPanelMode(rowDef, components, phyWidth, phyHeight);
×
1199
            fxi->setFixtureDefinition(rowDef, rowMode);
×
1200

1201
            // Check universe span
1202
            if (address + fxi->channels() > 512)
×
1203
            {
1204
                uniIndex++;
×
1205
                if (m_doc->inputOutputMap()->getUniverseID(uniIndex) == m_doc->inputOutputMap()->invalidUniverse())
×
1206
                {
1207
                    m_doc->inputOutputMap()->addUniverse();
×
1208
                    m_doc->inputOutputMap()->startUniverses();
×
1209
                }
1210
                address = 0;
×
1211
            }
1212

1213
            fxi->setUniverse(m_doc->inputOutputMap()->getUniverseID(uniIndex));
×
1214
            fxi->setAddress(address);
×
1215
            address += fxi->channels();
×
1216
            m_doc->addFixture(fxi);
×
1217

1218
            if (rgb.type() == AddRGBPanel::ZigZag)
×
1219
            {
1220
                int xPos = xPosStart;
×
1221
                for (int h = 0; h < fxi->heads(); h++)
×
1222
                {
1223
                        if (transpose)
×
1224
                                grp->assignHead(QLCPoint(currRow, xPos), GroupHead(fxi->id(), h));
×
1225
                        else
1226
                                grp->assignHead(QLCPoint(xPos, currRow), GroupHead(fxi->id(), h));
×
1227
                    xPos += xPosInc;
×
1228
                }
1229
            }
1230
            else if (rgb.type() == AddRGBPanel::Snake)
×
1231
            {
1232
                if (i%2 == 0)
×
1233
                {
1234
                    int xPos = xPosStart;
×
1235
                    for (int h = 0; h < fxi->heads(); h++)
×
1236
                    {
1237
                            if (transpose)
×
1238
                                    grp->assignHead(QLCPoint(currRow, xPos), GroupHead(fxi->id(), h));
×
1239
                            else
1240
                                    grp->assignHead(QLCPoint(xPos, currRow), GroupHead(fxi->id(), h));
×
1241
                        xPos += xPosInc;
×
1242
                    }
1243
                }
1244
                else
1245
                {
1246
                    int xPos = xPosEnd;
×
1247
                    for (int h = 0; h < fxi->heads(); h++)
×
1248
                    {
1249
                            if (transpose)
×
1250
                                    grp->assignHead(QLCPoint(currRow, xPos), GroupHead(fxi->id(), h));
×
1251
                            else
1252
                                    grp->assignHead(QLCPoint(xPos, currRow), GroupHead(fxi->id(), h));
×
1253
                        xPos += (-xPosInc);
×
1254
                    }
1255
                }
1256
            }
1257
            currRow += rowInc;
×
1258
        }
1259

1260
        updateView();
×
1261
        m_doc->setModified();
×
1262
    }
1263
}
×
1264

1265
void FixtureManager::removeFixture()
×
1266
{
1267
    // Ask before deletion
1268
    if (QMessageBox::question(this, tr("Delete Fixtures"),
×
1269
                              tr("Do you want to delete the selected items?"),
×
1270
                              QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
×
1271
    {
1272
        return;
×
1273
    }
1274

1275
    QListIterator <QTreeWidgetItem*> it(m_fixtures_tree->selectedItems());
×
1276

1277
    // We put items to delete in sets,
1278
    // so no segfault happens when the same fixture is selected twice
1279
    QSet <quint32> groupsToDelete;
×
1280
    QSet <quint32> fixturesToDelete;
×
1281
    while (it.hasNext() == true)
×
1282
    {
1283
        QTreeWidgetItem* item(it.next());
×
1284
        Q_ASSERT(item != NULL);
×
1285

1286
        // Is the item a fixture ?
1287
        QVariant var = item->data(KColumnName, PROP_ID);
×
1288
        if (var.isValid() == true)
×
1289
            fixturesToDelete << var.toUInt();
×
1290
        else
1291
        {
1292
            // Is the item a fixture group ?
1293
            var = item->data(KColumnName, PROP_GROUP);
×
1294
            if (var.isValid() == true)
×
1295
                groupsToDelete << var.toUInt();
×
1296
        }
1297
    }
1298

1299
    // delete fixture groups
1300
    foreach (quint32 id, groupsToDelete)
×
1301
        m_doc->deleteFixtureGroup(id);
×
1302

1303
    // delete fixtures
1304
    foreach (quint32 id, fixturesToDelete)
×
1305
    {
1306
        /** @todo This is REALLY bogus here, since Fixture or Doc should do
1307
            this. However, FixtureManager is the only place to destroy fixtures,
1308
            so it's rather safe to reset the fixture's address space here. */
1309
        Fixture* fxi = m_doc->fixture(id);
×
1310
        Q_ASSERT(fxi != NULL);
×
1311
        QList<Universe*> ua = m_doc->inputOutputMap()->claimUniverses();
×
1312
        int universe = fxi->universe();
×
1313
        if (universe < ua.count())
×
1314
            ua[universe]->reset(fxi->address(), fxi->channels());
×
1315
        m_doc->inputOutputMap()->releaseUniverses();
×
1316

1317
        m_doc->deleteFixture(id);
×
1318
    }
1319
}
1320

1321
void FixtureManager::removeChannelsGroup()
×
1322
{
1323
    // Ask before deletion
1324
    if (QMessageBox::question(this, tr("Delete Channels Group"),
×
1325
                              tr("Do you want to delete the selected groups?"),
×
1326
                              QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
×
1327
    {
1328
        return;
×
1329
    }
1330

1331
    disconnect(m_channel_groups_tree, SIGNAL(itemSelectionChanged()),
×
1332
            this, SLOT(slotChannelsGroupSelectionChanged()));
1333

1334
    QListIterator <QTreeWidgetItem*> it(m_channel_groups_tree->selectedItems());
×
1335
    while (it.hasNext() == true)
×
1336
    {
1337
        QTreeWidgetItem* item(it.next());
×
1338
        Q_ASSERT(item != NULL);
×
1339

1340
        QVariant var = item->data(KColumnName, PROP_ID);
×
1341
        if (var.isValid() == true)
×
1342
            m_doc->deleteChannelsGroup(var.toUInt());
×
1343
    }
1344
    updateChannelsGroupView();
×
1345

1346
    connect(m_channel_groups_tree, SIGNAL(itemSelectionChanged()),
×
1347
            this, SLOT(slotChannelsGroupSelectionChanged()));
1348
}
1349

1350
void FixtureManager::slotRemove()
×
1351
{
1352
    if (m_currentTabIndex == 1)
×
1353
        removeChannelsGroup();
×
1354
    else
1355
        removeFixture();
×
1356
}
×
1357

1358
void FixtureManager::editFixtureProperties()
×
1359
{
1360
    QTreeWidgetItem* item = m_fixtures_tree->currentItem();
×
1361
    if (item == NULL)
×
1362
        return;
×
1363

1364
    QVariant var = item->data(KColumnName, PROP_ID);
×
1365
    if (var.isValid() == false)
×
1366
        return;
×
1367

1368
    quint32 id = var.toUInt();
×
1369
    Fixture* fxi = m_doc->fixture(id);
×
1370
    if (fxi == NULL)
×
1371
        return;
×
1372

1373
    QString manuf;
×
1374
    QString model;
×
1375
    QString mode;
×
1376

1377
    if (fxi->fixtureDef() != NULL)
×
1378
    {
1379
        manuf = fxi->fixtureDef()->manufacturer();
×
1380
        model = fxi->fixtureDef()->model();
×
1381
        mode = fxi->fixtureMode()->name();
×
1382
    }
1383

1384
    AddFixture af(this, m_doc, fxi);
×
1385
    af.setWindowTitle(tr("Change fixture properties"));
×
1386
    if (af.exec() == QDialog::Accepted)
×
1387
    {
1388
        if (af.invalidAddress() == false)
×
1389
        {
1390
            bool changed = false;
×
1391

1392
            fxi->blockSignals(true);
×
1393
            if (fxi->name() != af.name())
×
1394
            {
1395
                fxi->setName(af.name());
×
1396
                changed = true;
×
1397
            }
1398
            if (fxi->universe() != af.universe())
×
1399
            {
1400
                fxi->setUniverse(af.universe());
×
1401
                changed = true;
×
1402
            }
1403
            if (fxi->address() != af.address())
×
1404
            {
1405
                fxi->setAddress(af.address());
×
1406
                changed = true;
×
1407
            }
1408
            fxi->blockSignals(false);
×
1409

1410
            if (af.fixtureDef() != NULL && af.mode() != NULL)
×
1411
            {
1412
                if (af.fixtureDef()->manufacturer() == KXMLFixtureGeneric &&
×
1413
                    af.fixtureDef()->model() == KXMLFixtureGeneric)
×
1414
                {
1415
                    if (fxi->channels() != af.channels())
×
1416
                    {
1417
                        QLCFixtureDef* fixtureDef = fxi->genericDimmerDef(af.channels());
×
1418
                        QLCFixtureMode* fixtureMode = fxi->genericDimmerMode(fixtureDef, af.channels());
×
1419
                        fxi->setFixtureDefinition(fixtureDef, fixtureMode);
×
1420
                    }
1421
                }
1422
                else
1423
                {
1424
                    fxi->setFixtureDefinition(af.fixtureDef(), af.mode());
×
1425
                }
1426
            }
1427
            else
1428
            {
1429
                /* Generic dimmer */
1430
                fxi->setFixtureDefinition(NULL, NULL);
×
1431
                fxi->setChannels(af.channels());
×
1432
            }
1433

1434
            // Emit changed signal
1435
            if (changed)
×
1436
                fxi->setID(fxi->id());
×
1437

1438
            updateView();
×
1439
            slotSelectionChanged();
×
1440
        }
1441
        else
1442
        {
1443
            QMessageBox msg(QMessageBox::Critical, tr("Error"),
×
1444
                    tr("Please enter a valid address"), QMessageBox::Ok);
×
1445
            msg.exec();
×
1446
        }
1447
    }
1448
}
1449

1450
void FixtureManager::editChannelGroupProperties()
×
1451
{
1452
    int selectedCount = m_channel_groups_tree->selectedItems().size();
×
1453

1454
    if (selectedCount > 0)
×
1455
    {
1456
        QTreeWidgetItem* current = m_channel_groups_tree->selectedItems().first();
×
1457
        QVariant var = current->data(KColumnName, PROP_ID);
×
1458
        if (var.isValid() == true)
×
1459
        {
1460
            ChannelsGroup *group = m_doc->channelsGroup(var.toUInt());
×
1461

1462
            AddChannelsGroup cs(this, m_doc, group);
×
1463
            if (cs.exec() == QDialog::Accepted)
×
1464
            {
1465
                qDebug() << "CHANNEL GROUP MODIFIED. Count: " << group->getChannels().count();
×
1466
                m_doc->addChannelsGroup(group, group->id());
×
1467
                updateChannelsGroupView();
×
1468
            }
1469
        }
1470
    }
1471
}
×
1472

1473
int FixtureManager::headCount(const QList <QTreeWidgetItem*>& items) const
×
1474
{
1475
    int count = 0;
×
1476
    QListIterator <QTreeWidgetItem*> it(items);
×
1477
    while (it.hasNext() == true)
×
1478
    {
1479
        QTreeWidgetItem* item = it.next();
×
1480
        Q_ASSERT(item != NULL);
×
1481

1482
        QVariant var = item->data(KColumnName, PROP_ID);
×
1483
        if (var.isValid() == false)
×
1484
            continue;
×
1485

1486
        Fixture* fxi = m_doc->fixture(var.toUInt());
×
1487
        count += fxi->heads();
×
1488
    }
1489

1490
    return count;
×
1491
}
1492

1493
void FixtureManager::slotProperties()
×
1494
{
1495
    if (m_currentTabIndex == 1)
×
1496
        editChannelGroupProperties();
×
1497
    else
1498
        editFixtureProperties();
×
1499
}
×
1500

1501
void FixtureManager::slotFadeConfig()
×
1502
{
1503
    ChannelsSelection cfg(m_doc, this, ChannelsSelection::ConfigurationMode);
×
1504
    if (cfg.exec() == QDialog::Rejected)
×
1505
        return; // User pressed cancel
×
1506
    m_doc->setModified();
×
1507
}
1508

1509
void FixtureManager::slotRemap()
×
1510
{
1511
    FixtureRemap fxr(m_doc);
×
1512
    if (fxr.exec() == QDialog::Rejected)
×
1513
        return; // User pressed cancel
×
1514

1515
    updateView();
×
1516
}
1517

1518
void FixtureManager::slotUnGroup()
×
1519
{
1520
    if (QMessageBox::question(this, tr("Ungroup fixtures?"),
×
1521
                              tr("Do you want to ungroup the selected fixtures?"),
×
1522
                              QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
×
1523
    {
1524
        return;
×
1525
    }
1526

1527
    // Because FixtureGroup::resignFixture() emits changed(), which makes the tree
1528
    // update its contents in the middle, invalidating m_tree->selectedItems(),
1529
    // we must pick the list of fixtures and groups first and then resign them in
1530
    // one big bunch.
1531
    QList <QPair<quint32,quint32> > resignList;
×
1532

1533
    foreach (QTreeWidgetItem* item, m_fixtures_tree->selectedItems())
×
1534
    {
1535
        if (item->parent() == NULL)
×
1536
            continue;
×
1537

1538
        QVariant var = item->parent()->data(KColumnName, PROP_GROUP);
×
1539
        if (var.isValid() == false)
×
1540
            continue;
×
1541
        quint32 grp = var.toUInt();
×
1542

1543
        var = item->data(KColumnName, PROP_ID);
×
1544
        if (var.isValid() == false)
×
1545
            continue;
×
1546
        quint32 fxi = var.toUInt();
×
1547

1548
        resignList << QPair <quint32,quint32> (grp, fxi);
×
1549
    }
1550

1551
    QListIterator <QPair<quint32,quint32> > it(resignList);
×
1552
    while (it.hasNext() == true)
×
1553
    {
1554
        QPair <quint32,quint32> pair(it.next());
×
1555
        FixtureGroup* grp = m_doc->fixtureGroup(pair.first);
×
1556
        Q_ASSERT(grp != NULL);
×
1557
        grp->resignFixture(pair.second);
×
1558
    }
1559
}
1560

1561
void FixtureManager::slotGroupSelected(QAction* action)
×
1562
{
1563
    FixtureGroup* grp = NULL;
×
1564

1565
    if (action->data().isValid() == true)
×
1566
    {
1567
        // Existing group selected
1568
        grp = (FixtureGroup*) (action->data().toULongLong());
×
1569
        Q_ASSERT(grp != NULL);
×
1570
    }
1571
    else
1572
    {
1573
        // New Group selected.
1574

1575
        // Suggest an equilateral grid
1576
        qreal side = sqrt(headCount(m_fixtures_tree->selectedItems()));
×
1577
        if (side != floor(side))
×
1578
            side += 1; // Fixture number doesn't provide a full square
×
1579

1580
        CreateFixtureGroup cfg(this);
×
1581
        cfg.setSize(QSize(side, side));
×
1582
        if (cfg.exec() != QDialog::Accepted)
×
1583
            return; // User pressed cancel
×
1584

1585
        grp = new FixtureGroup(m_doc);
×
1586
        Q_ASSERT(grp != NULL);
×
1587
        grp->setName(cfg.name());
×
1588
        grp->setSize(cfg.size());
×
1589
        m_doc->addFixtureGroup(grp);
×
1590
        updateGroupMenu();
×
1591
    }
1592

1593
    // Assign selected fixture items to the group
1594
    foreach (QTreeWidgetItem* item, m_fixtures_tree->selectedItems())
×
1595
    {
1596
        QVariant var = item->data(KColumnName, PROP_ID);
×
1597
        if (var.isValid() == false)
×
1598
            continue;
×
1599

1600
        grp->assignFixture(var.toUInt());
×
1601
    }
1602

1603
    updateView();
×
1604
}
1605

1606
void FixtureManager::slotMoveGroupUp()
×
1607
{
1608
    if (m_channel_groups_tree->selectedItems().size() > 0)
×
1609
    {
1610
        QTreeWidgetItem* item = m_channel_groups_tree->selectedItems().first();
×
1611
        quint32 grpID = item->data(KColumnName, PROP_ID).toUInt();
×
1612
        m_doc->moveChannelGroup(grpID, -1);
×
1613
        updateChannelsGroupView();
×
1614
    }
1615
}
×
1616

1617
void FixtureManager::slotMoveGroupDown()
×
1618
{
1619
    if (m_channel_groups_tree->selectedItems().size() > 0)
×
1620
    {
1621
        QTreeWidgetItem* item = m_channel_groups_tree->selectedItems().first();
×
1622
        quint32 grpID = item->data(KColumnName, PROP_ID).toUInt();
×
1623
        m_doc->moveChannelGroup(grpID, 1);
×
1624
        updateChannelsGroupView();
×
1625
    }
1626
}
×
1627

1628
QString FixtureManager::createDialog(bool import)
×
1629
{
1630
    QString fileName;
×
1631

1632
    /* Create a file save dialog */
1633
    QFileDialog dialog(this);
×
1634
    if (import == true)
×
1635
    {
1636
        dialog.setWindowTitle(tr("Import Fixtures List"));
×
1637
        dialog.setAcceptMode(QFileDialog::AcceptOpen);
×
1638
    }
1639
    else
1640
    {
1641
        dialog.setWindowTitle(tr("Export Fixtures List As"));
×
1642
        dialog.setAcceptMode(QFileDialog::AcceptSave);
×
1643
    }
1644

1645
    /* Append file filters to the dialog */
1646
    QStringList filters;
×
1647
    filters << tr("Fixtures List (*%1)").arg(KExtFixtureList);
×
1648
#if defined(WIN32) || defined(Q_OS_WIN)
1649
    filters << tr("All Files (*.*)");
1650
#else
1651
    filters << tr("All Files (*)");
×
1652
#endif
1653
    dialog.setNameFilters(filters);
×
1654

1655
    /* Append useful URLs to the dialog */
1656
    QList <QUrl> sidebar;
×
1657
    sidebar.append(QUrl::fromLocalFile(QDir::homePath()));
×
1658
    sidebar.append(QUrl::fromLocalFile(QDir::rootPath()));
×
1659
    dialog.setSidebarUrls(sidebar);
×
1660

1661
    /* Get file name */
1662
    if (dialog.exec() != QDialog::Accepted)
×
1663
        return "";
×
1664

1665
    fileName = dialog.selectedFiles().first();
×
1666
    if (fileName.isEmpty() == true)
×
1667
        return "";
×
1668

1669
    /* Always use the fixture definition suffix */
1670
    if (import == false && fileName.right(5) != KExtFixtureList)
×
1671
        fileName += KExtFixtureList;
×
1672

1673
    return fileName;
×
1674
}
1675

1676
void FixtureManager::slotImport()
×
1677
{
1678
    QString fileName = createDialog(true);
×
1679

1680
    QXmlStreamReader *doc = QLCFile::getXMLReader(fileName);
×
1681
    if (doc == NULL || doc->device() == NULL || doc->hasError())
×
1682
    {
1683
        qWarning() << Q_FUNC_INFO << "Unable to read from" << fileName;
×
1684
        return;
×
1685
    }
1686

1687
    while (!doc->atEnd())
×
1688
    {
1689
        if (doc->readNext() == QXmlStreamReader::DTD)
×
1690
            break;
×
1691
    }
1692
    if (doc->hasError())
×
1693
    {
1694
        QLCFile::releaseXMLReader(doc);
×
1695
        return;
×
1696
    }
1697

1698
    if (doc->dtdName() == KXMLQLCFixturesList)
×
1699
    {
1700
        doc->readNextStartElement();
×
1701
        if (doc->name() != KXMLQLCFixturesList)
×
1702
        {
1703
            qWarning() << Q_FUNC_INFO << "Fixture Definition node not found";
×
1704
            QLCFile::releaseXMLReader(doc);
×
1705
            return;
×
1706
        }
1707

1708
        while (doc->readNextStartElement())
×
1709
        {
1710
            if (doc->name() == KXMLFixture)
×
1711
            {
1712
                Fixture* fxi = new Fixture(m_doc);
×
1713
                Q_ASSERT(fxi != NULL);
×
1714

1715
                if (fxi->loadXML(*doc, m_doc, m_doc->fixtureDefCache()) == true)
×
1716
                {
1717
                    if (m_doc->addFixture(fxi /*, fxi->id()*/) == true)
×
1718
                    {
1719
                        /* Success */
1720
                        qWarning() << Q_FUNC_INFO << "Fixture" << fxi->name() << "successfully created.";
×
1721
                    }
1722
                    else
1723
                    {
1724
                        /* Doc is full */
1725
                        qWarning() << Q_FUNC_INFO << "Fixture" << fxi->name() << "cannot be created.";
×
1726
                        delete fxi;
×
1727
                    }
1728
                }
1729
                else
1730
                {
1731
                    qWarning() << Q_FUNC_INFO << "Fixture" << fxi->name() << "cannot be loaded.";
×
1732
                    delete fxi;
×
1733
                }
1734
            }
1735
            else if (doc->name() == KXMLQLCFixtureGroup)
×
1736
            {
1737
                FixtureGroup* grp = new FixtureGroup(m_doc);
×
1738
                Q_ASSERT(grp != NULL);
×
1739

1740
                if (grp->loadXML(*doc) == true)
×
1741
                {
1742
                    m_doc->addFixtureGroup(grp, grp->id());
×
1743
                }
1744
                else
1745
                {
1746
                    qWarning() << Q_FUNC_INFO << "FixtureGroup" << grp->name() << "cannot be loaded.";
×
1747
                    delete grp;
×
1748
                }
1749
            }
1750
            else
1751
            {
1752
                qWarning() << Q_FUNC_INFO << "Unknown label tag:" << doc->name().toString();
×
1753
                doc->skipCurrentElement();
×
1754
            }
1755
        }
1756
        updateView();
×
1757
    }
1758
    QLCFile::releaseXMLReader(doc);
×
1759
}
1760

1761
void FixtureManager::slotExport()
×
1762
{
1763
    QString fileName = createDialog(false);
×
1764

1765
    QFile file(fileName);
×
1766
    if (file.open(QIODevice::WriteOnly) == false)
×
1767
        return;
×
1768

1769
    QXmlStreamWriter doc(&file);
×
1770
    doc.setAutoFormatting(true);
×
1771
    doc.setAutoFormattingIndent(1);
×
1772
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1773
    doc.setCodec("UTF-8");
1774
#endif
1775
    QLCFile::writeXMLHeader(&doc, KXMLQLCFixturesList);
×
1776

1777
    QListIterator <Fixture*> fxit(m_doc->fixtures());
×
1778
    while (fxit.hasNext() == true)
×
1779
    {
1780
        Fixture* fxi(fxit.next());
×
1781
        Q_ASSERT(fxi != NULL);
×
1782
        fxi->saveXML(&doc);
×
1783
    }
1784

1785
    QListIterator <FixtureGroup*>grpit(m_doc->fixtureGroups());
×
1786
    while (grpit.hasNext() == true)
×
1787
    {
1788
        FixtureGroup *fxgrp(grpit.next());
×
1789
        Q_ASSERT(fxgrp != NULL);
×
1790
        fxgrp->saveXML(&doc);
×
1791
    }
1792

1793
    doc.writeEndDocument();
×
1794
    file.close();
×
1795
}
1796

1797
void FixtureManager::slotContextMenuRequested(const QPoint&)
×
1798
{
1799
    QMenu menu(this);
×
1800
    menu.addAction(m_addAction);
×
1801
    menu.addAction(m_addRGBAction);
×
1802
    menu.addAction(m_propertiesAction);
×
1803
    menu.addAction(m_removeAction);
×
1804
    menu.addSeparator();
×
1805
    menu.addAction(m_groupAction);
×
1806
    menu.addAction(m_unGroupAction);
×
1807
    menu.exec(QCursor::pos());
×
1808
}
×
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