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

mcallegari / qlcplus / 22546895196

01 Mar 2026 03:51PM UTC coverage: 33.989% (+0.02%) from 33.971%
22546895196

Pull #1970

github

web-flow
Merge 02f9e24d3 into 8ea7c9868
Pull Request #1970: ui: add support for frame expand/collapse via external input

29 of 75 new or added lines in 2 files covered. (38.67%)

2 existing lines in 1 file now uncovered.

17676 of 52005 relevant lines covered (33.99%)

19761.2 hits per line

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

44.96
/ui/src/virtualconsole/vcframe.cpp
1
/*
2
  Q Light Controller Plus
3
  vcframe.cpp
4

5
  Copyright (c) Heikki Junnila
6
                Massimo Callegari
7

8
  Licensed under the Apache License, Version 2.0 (the "License");
9
  you may not use this file except in compliance with the License.
10
  You may obtain a copy of the License at
11

12
      http://www.apache.org/licenses/LICENSE-2.0.txt
13

14
  Unless required by applicable law or agreed to in writing, software
15
  distributed under the License is distributed on an "AS IS" BASIS,
16
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
  See the License for the specific language governing permissions and
18
  limitations under the License.
19
*/
20

21
#include <QXmlStreamReader>
22
#include <QXmlStreamWriter>
23
#include <QMapIterator>
24
#include <QMetaObject>
25
#include <QComboBox>
26
#include <QMessageBox>
27
#include <QSettings>
28
#include <QPainter>
29
#include <QAction>
30
#include <QStyle>
31
#include <QDebug>
32
#include <QPoint>
33
#include <QSize>
34
#include <QMenu>
35
#include <QFont>
36
#include <QList>
37

38
#include "vcframepageshortcut.h"
39
#include "vcpropertieseditor.h"
40
#include "vcframeproperties.h"
41
#include "vcaudiotriggers.h"
42
#include "virtualconsole.h"
43
#include "vcsoloframe.h"
44
#include "vcspeeddial.h"
45
#include "vccuelist.h"
46
#include "vcbutton.h"
47
#include "vcslider.h"
48
#include "vcmatrix.h"
49
#include "qlcfile.h"
50
#include "vcframe.h"
51
#include "vclabel.h"
52
#include "vcxypad.h"
53
#include "vcclock.h"
54
#include "apputil.h"
55
#include "doc.h"
56

57
const QSize VCFrame::defaultSize(QSize(200, 200));
58

59
const quint8 VCFrame::nextPageInputSourceId = 0;
60
const quint8 VCFrame::previousPageInputSourceId = 1;
61
const quint8 VCFrame::enableInputSourceId = 2;
62
const quint8 VCFrame::collpseInputSourceId = 3;
63
const quint8 VCFrame::shortcutsBaseInputSourceId = 20;
64

65
VCFrame::VCFrame(QWidget* parent, Doc* doc, bool canCollapse)
95✔
66
    : VCWidget(parent, doc)
67
    , m_hbox(NULL)
95✔
68
    , m_collapseButton(NULL)
95✔
69
    , m_enableButton(NULL)
95✔
70
    , m_label(NULL)
95✔
71
    , m_collapsed(false)
95✔
72
    , m_showHeader(true)
95✔
73
    , m_showEnableButton(true)
95✔
74
    , m_multiPageMode(false)
95✔
75
    , m_currentPage(0)
95✔
76
    , m_totalPagesNumber(1)
95✔
77
    , m_nextPageBtn(NULL)
95✔
78
    , m_prevPageBtn(NULL)
95✔
79
    , m_pageCombo(NULL)
95✔
80
    , m_pagesLoop(false)
95✔
81
{
82
    /* Set the class name "VCFrame" as the object name as well */
83
    setObjectName(VCFrame::staticMetaObject.className());
95✔
84
    setFrameStyle(KVCFrameStyleSunken);
95✔
85
    setAllowChildren(true);
95✔
86
    setType(VCWidget::FrameWidget);
95✔
87

88
    if (canCollapse == true)
95✔
89
        createHeader();
3✔
90

91
    QSettings settings;
95✔
92
    QVariant var = settings.value(SETTINGS_FRAME_SIZE);
95✔
93
    if (var.isValid() == true)
95✔
94
        resize(var.toSize());
×
95
    else
96
        resize(defaultSize);
95✔
97
    m_width = this->width();
95✔
98
    m_height = this->height();
95✔
99
}
95✔
100

101
VCFrame::~VCFrame()
175✔
102
{
103
}
175✔
104

105
bool VCFrame::isBottomFrame() const
13✔
106
{
107
    return (parentWidget() != NULL && qobject_cast<VCFrame*>(parentWidget()) == NULL);
13✔
108
}
109

110
void VCFrame::setDisableState(bool disable)
×
111
{
112
    if (m_enableButton)
×
113
    {
114
        m_enableButton->blockSignals(true);
×
115
        m_enableButton->setChecked(!disable);
×
116
        m_enableButton->blockSignals(false);
×
117
    }
118

119
    foreach (VCWidget* widget, this->findChildren<VCWidget*>())
×
120
    {
121
        widget->setDisableState(disable);
×
122
        if (!disable)
×
123
            widget->adjustIntensity(intensity());
×
124
    }
×
125

126
    m_disableState = disable;
×
127

128
    emit disableStateChanged(disable);
×
129
    updateFeedback();
×
130
}
×
131

132
void VCFrame::setLiveEdit(bool liveEdit)
×
133
{
134
    if (m_doc->mode() == Doc::Design)
×
135
        return;
×
136

137
    m_liveEdit = liveEdit;
×
138

139
    if (!m_disableState)
×
140
        enableWidgetUI(!m_liveEdit);
×
141

142
    updateSubmasterValue();
×
143

144
    unsetCursor();
×
145
    update();
×
146
}
147

148
void VCFrame::setCaption(const QString& text)
5✔
149
{
150
    if (m_label != NULL)
5✔
151
    {
152
        if (!shortcuts().isEmpty() && m_currentPage < shortcuts().length())
1✔
153
        {
154
            // Show caption, if there is no page name
155
            if (m_pageShortcuts.at(m_currentPage)->name() == "")
×
156
                m_label->setText(text);
×
157
            else
158
            {
159
                // Show only page name, if there is no caption
160
                if (text == "")
×
161
                    m_label->setText(m_pageShortcuts.at(m_currentPage)->name());
×
162
                else
163
                    m_label->setText(text + " - " + m_pageShortcuts.at(m_currentPage)->name());
×
164
            }
165
        }
166
        else
167
            m_label->setText(text);
1✔
168
    }
169

170
    VCWidget::setCaption(text);
5✔
171
}
5✔
172

173
void VCFrame::setFont(const QFont &font)
×
174
{
175
    if (m_label != NULL)
×
176
    {
177
        m_label->setFont(font);
×
178
        m_hasCustomFont = true;
×
179
        m_doc->setModified();
×
180
    }
181
}
×
182

183
QFont VCFrame::font() const
×
184
{
185
    if (m_label != NULL)
×
186
        return m_label->font();
×
187
    else
188
        return VCWidget::font();
×
189
}
190

191
void VCFrame::setForegroundColor(const QColor &color)
×
192
{
193
    if (m_label != NULL)
×
194
    {
195
        m_label->setStyleSheet("QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #666666, stop: 1 #000000); "
×
196
                               "color: " + color.name() + "; border-radius: 3px; padding: 3px; margin-left: 2px; }");
×
197
        m_hasCustomForegroundColor = true;
×
198
        m_doc->setModified();
×
199
    }
200
}
×
201

202
QColor VCFrame::foregroundColor() const
×
203
{
204
    if (m_label != NULL)
×
205
        return m_label->palette().color(m_label->foregroundRole());
×
206
    else
207
        return VCWidget::foregroundColor();
×
208
}
209

210
void VCFrame::setHeaderVisible(bool enable)
2✔
211
{
212
    m_showHeader = enable;
2✔
213

214
    if (m_hbox == NULL)
2✔
215
        createHeader();
1✔
216

217
    if (enable == false)
2✔
218
    {
219
        m_collapseButton->hide();
×
220
        m_label->hide();
×
221
        m_enableButton->hide();
×
222
    }
223
    else
224
    {
225
        m_collapseButton->show();
2✔
226
        m_label->show();
2✔
227
        if (m_showEnableButton)
2✔
228
            m_enableButton->show();
2✔
229
    }
230
}
2✔
231

232
bool VCFrame::isHeaderVisible() const
4✔
233
{
234
    return m_showHeader;
4✔
235
}
236

237
void VCFrame::setEnableButtonVisible(bool show)
2✔
238
{
239
    if (show && m_showHeader) m_enableButton->show();
2✔
240
    else m_enableButton->hide();
×
241

242
    m_showEnableButton = show;
2✔
243
}
2✔
244

245
bool VCFrame::isEnableButtonVisible() const
3✔
246
{
247
    return m_showEnableButton;
3✔
248
}
249

250
bool VCFrame::isCollapsed() const
6✔
251
{
252
    return m_collapsed;
6✔
253
}
254

255
QSize VCFrame::originalSize() const
×
256
{
257
    return QSize(m_width, m_height);
×
258
}
259

260
void VCFrame::slotCollapseButtonToggled(bool toggle)
×
261
{
262
    if (toggle == true)
×
263
    {
264
        m_width = this->width();
×
265
        m_height = this->height();
×
266
        if (m_multiPageMode == true)
×
267
        {
268
            if (m_prevPageBtn) m_prevPageBtn->hide();
×
269
            if (m_nextPageBtn) m_nextPageBtn->hide();
×
270
        }
271
        resize(QSize(200, 40));
×
272
        m_collapsed = true;
×
273
    }
274
    else
275
    {
276
        resize(QSize(m_width, m_height));
×
277
        if (m_multiPageMode == true)
×
278
        {
279
            if (m_prevPageBtn) m_prevPageBtn->show();
×
280
            if (m_nextPageBtn) m_nextPageBtn->show();
×
281
        }
282
        m_collapsed = false;
×
283
    }
284
    m_doc->setModified();
×
285
}
×
286

287
void VCFrame::slotEnableButtonClicked(bool checked)
×
288
{
289
    setDisableState(!checked);
×
290
}
×
291

292
void VCFrame::createHeader()
4✔
293
{
294
    if (m_hbox != NULL)
4✔
295
        return;
×
296

297
    QVBoxLayout *vbox = new QVBoxLayout(this);
4✔
298
    /* Main HBox */
299
    m_hbox = new QHBoxLayout();
4✔
300
    m_hbox->setGeometry(QRect(0, 0, 200, 40));
4✔
301

302
    layout()->setSpacing(2);
4✔
303
    layout()->setContentsMargins(4, 4, 4, 4);
4✔
304
    layout()->addItem(m_hbox);
4✔
305
    vbox->addStretch();
4✔
306

307
    m_collapseButton = new QToolButton(this);
4✔
308
    m_collapseButton->setStyle(AppUtil::saneStyle());
4✔
309
    m_collapseButton->setIconSize(QSize(32, 32));
4✔
310
    m_collapseButton->setMinimumSize(QSize(32, 32));
4✔
311
    m_collapseButton->setMaximumSize(QSize(32, 32));
4✔
312
    m_collapseButton->setIcon(QIcon(":/expand.png"));
4✔
313
    m_collapseButton->setCheckable(true);
4✔
314
    QString cBtnSS = "QToolButton { background-color: #E0DFDF; border: 1px solid gray; border-radius: 3px; padding: 3px; } ";
4✔
315
    cBtnSS += "QToolButton:pressed { background-color: #919090; border: 1px solid gray; border-radius: 3px; padding: 3px; } ";
4✔
316
    m_collapseButton->setStyleSheet(cBtnSS);
4✔
317

318
    m_hbox->addWidget(m_collapseButton);
4✔
319
    connect(m_collapseButton, SIGNAL(toggled(bool)), this, SLOT(slotCollapseButtonToggled(bool)));
4✔
320

321
    m_label = new QLabel(this);
4✔
322
    m_label->setText(this->caption());
4✔
323
    QString txtColor = "white";
4✔
324
    if (m_hasCustomForegroundColor)
4✔
325
        txtColor = this->foregroundColor().name();
×
326
    m_label->setStyleSheet("QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #666666, stop: 1 #000000); "
4✔
327
                           "color: " + txtColor + "; border-radius: 3px; padding: 3px; margin-left: 2px; margin-right: 2px; }");
8✔
328

329
    if (m_hasCustomFont)
4✔
330
        m_label->setFont(font());
×
331
    else
332
    {
333
        QFont m_font = QApplication::font();
4✔
334
        m_font.setBold(true);
4✔
335
        m_font.setPixelSize(12);
4✔
336
        m_label->setFont(m_font);
4✔
337
    }
4✔
338
    m_hbox->addWidget(m_label);
4✔
339

340
    m_enableButton = new QToolButton(this);
4✔
341
    m_enableButton->setStyle(AppUtil::saneStyle());
4✔
342
    m_enableButton->setIconSize(QSize(32, 32));
4✔
343
    m_enableButton->setMinimumSize(QSize(32, 32));
4✔
344
    m_enableButton->setMaximumSize(QSize(32, 32));
4✔
345
    m_enableButton->setIcon(QIcon(":/check.png"));
4✔
346
    m_enableButton->setCheckable(true);
4✔
347
    QString eBtnSS = "QToolButton { background-color: #E0DFDF; border: 1px solid gray; border-radius: 3px; padding: 3px; } ";
4✔
348
    eBtnSS += "QToolButton:checked { background-color: #D7DE75; border: 1px solid gray; border-radius: 3px; padding: 3px; } ";
4✔
349
    m_enableButton->setStyleSheet(eBtnSS);
4✔
350
    m_enableButton->setEnabled(true);
4✔
351
    m_enableButton->setChecked(true);
4✔
352
    if (!m_showEnableButton)
4✔
353
        m_enableButton->hide();
×
354

355
    m_hbox->addWidget(m_enableButton);
4✔
356
    connect(m_enableButton, SIGNAL(clicked(bool)), this, SLOT(slotEnableButtonClicked(bool)));
4✔
357
}
4✔
358

359
/*********************************************************************
360
 * Pages
361
 *********************************************************************/
362

363
void VCFrame::setMultipageMode(bool enable)
2✔
364
{
365
    if (m_multiPageMode == enable)
2✔
366
        return;
2✔
367

368
    if (enable == true)
×
369
    {
370
        if (m_prevPageBtn != NULL && m_nextPageBtn != NULL && m_pageCombo != NULL)
×
371
            return;
×
372

373
        QString btnSS = "QToolButton { background-color: #E0DFDF; border: 1px solid gray; border-radius: 3px; padding: 3px; margin-left: 2px; }";
×
374
        btnSS += "QToolButton:pressed { background-color: #919090; border: 1px solid gray; border-radius: 3px; padding: 3px; margin-left: 2px; }";
×
375

376
        m_prevPageBtn = new QToolButton(this);
×
377
        m_prevPageBtn->setStyle(AppUtil::saneStyle());
×
378
        m_prevPageBtn->setIconSize(QSize(32, 32));
×
379
        m_prevPageBtn->setMinimumSize(QSize(32, 32));
×
380
        m_prevPageBtn->setMaximumSize(QSize(32, 32));
×
381
        m_prevPageBtn->setIcon(QIcon(":/back.png"));
×
382
        m_prevPageBtn->setStyleSheet(btnSS);
×
383
        m_hbox->addWidget(m_prevPageBtn);
×
384

385
        m_pageCombo = new QComboBox(this);
×
386
        m_pageCombo->setMaximumWidth(100);
×
387
        m_pageCombo->setFixedHeight(32);
×
388
        m_pageCombo->setFocusPolicy(Qt::NoFocus);
×
389

390
        /** Add a single shortcut until setTotalPagesNumber kicks in */
391
        addShortcut();
×
392

393
        m_pageCombo->setStyleSheet("QComboBox { background-color: black; color: red; margin-left: 2px; padding: 3px; }");
×
394
        if (m_hasCustomFont)
×
395
        {
396
            m_pageCombo->setFont(font());
×
397
        }
398
        else
399
        {
400
            QFont m_font = QApplication::font();
×
401
            m_font.setBold(true);
×
402
            m_font.setPixelSize(12);
×
403
            m_pageCombo->setFont(m_font);
×
404
        }
×
405
        m_hbox->addWidget(m_pageCombo);
×
406

407
        m_nextPageBtn = new QToolButton(this);
×
408
        m_nextPageBtn->setStyle(AppUtil::saneStyle());
×
409
        m_nextPageBtn->setIconSize(QSize(32, 32));
×
410
        m_nextPageBtn->setMinimumSize(QSize(32, 32));
×
411
        m_nextPageBtn->setMaximumSize(QSize(32, 32));
×
412
        m_nextPageBtn->setIcon(QIcon(":/forward.png"));
×
413
        m_nextPageBtn->setStyleSheet(btnSS);
×
414
        m_hbox->addWidget(m_nextPageBtn);
×
415

416
        connect (m_prevPageBtn, SIGNAL(clicked()), this, SLOT(slotPreviousPage()));
×
417
        connect (m_pageCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(slotSetPage(int)));
×
418
        connect (m_nextPageBtn, SIGNAL(clicked()), this, SLOT(slotNextPage()));
×
419

420
        if (this->isCollapsed() == false)
×
421
        {
422
            m_prevPageBtn->show();
×
423
            m_nextPageBtn->show();
×
424
        }
425
        else
426
        {
427
            m_prevPageBtn->hide();
×
428
            m_nextPageBtn->hide();
×
429
        }
430
        m_pageCombo->show();
×
431

432
        if (m_pagesMap.isEmpty())
×
433
        {
434
            QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
×
435
            while (it.hasNext() == true)
×
436
            {
437
                VCWidget* child = it.next();
×
438
                addWidgetToPageMap(child);
×
439
            }
440
        }
×
441
    }
×
442
    else
443
    {
444
        if (m_prevPageBtn == NULL && m_nextPageBtn == NULL && m_pageCombo == NULL)
×
445
            return;
×
446

447
        resetShortcuts();
×
448
        m_hbox->removeWidget(m_prevPageBtn);
×
449
        m_hbox->removeWidget(m_pageCombo);
×
450
        m_hbox->removeWidget(m_nextPageBtn);
×
451
        delete m_prevPageBtn;
×
452
        delete m_pageCombo;
×
453
        delete m_nextPageBtn;
×
454
        m_prevPageBtn = NULL;
×
455
        m_pageCombo = NULL;
×
456
        m_nextPageBtn = NULL;
×
457
        setCaption(caption());
×
458
    }
459

460
    m_multiPageMode = enable;
×
461
}
462

463
bool VCFrame::multipageMode() const
7✔
464
{
465
    return m_multiPageMode;
7✔
466
}
467

468
void VCFrame::setTotalPagesNumber(int num)
2✔
469
{
470
    if (num == m_totalPagesNumber)
2✔
471
        return;
2✔
472

473
    if (num < m_totalPagesNumber)
×
474
    {
475
        for (int i = 0; i < (m_totalPagesNumber - num); i++)
×
476
        {
477
            m_pageShortcuts.removeLast();
×
478
            if (m_pageCombo)
×
479
                m_pageCombo->removeItem(m_pageCombo->count() - 1);
×
480
        }
481
    }
482
    else
483
    {
484
        for (int i = 0; i < (num - m_totalPagesNumber); i++)
×
485
            addShortcut();
×
486
    }
487
    m_totalPagesNumber = num;
×
488
}
489

490
int VCFrame::totalPagesNumber() const
2✔
491
{
492
    return m_totalPagesNumber;
2✔
493
}
494

495
int VCFrame::currentPage() const
17✔
496
{
497
    if (m_multiPageMode == false)
17✔
498
        return 0;
17✔
499
    return m_currentPage;
×
500
}
501

502
void VCFrame::updatePageCombo()
2✔
503
{
504
    if (m_pageCombo == NULL || shortcuts().isEmpty())
2✔
505
        return;
2✔
506

507
    // Save current page to restore it afterwards
508
    int page = currentPage();
×
509
    m_pageCombo->blockSignals(true);
×
510
    m_pageCombo->clear();
×
511
    for (int i = 0; i < m_pageShortcuts.count(); i++)
×
512
        m_pageCombo->addItem(m_pageShortcuts.at(i)->name());
×
513
    m_pageCombo->setCurrentIndex(page);
×
514
    m_pageCombo->blockSignals(false);
×
515
}
516

517
/*********************************************************************
518
 * Shortcuts
519
 *********************************************************************/
520

521
void VCFrame::addShortcut()
×
522
{
523
    int index = m_pageShortcuts.count();
×
524
    m_pageShortcuts.append(new VCFramePageShortcut(index, VCFrame::shortcutsBaseInputSourceId + index));
×
525
    m_pageCombo->addItem(m_pageShortcuts.last()->name());
×
526
}
×
527

528
void VCFrame::setShortcuts(QList<VCFramePageShortcut *> shortcuts)
2✔
529
{
530
    resetShortcuts();
2✔
531
    foreach (VCFramePageShortcut const* shortcut, shortcuts)
2✔
532
    {
533
        m_pageShortcuts.append(new VCFramePageShortcut(*shortcut));
×
534
        if (shortcut->m_inputSource != NULL)
×
535
            setInputSource(shortcut->m_inputSource, shortcut->m_id);
×
536
    }
2✔
537
    updatePageCombo();
2✔
538
}
2✔
539

540
void VCFrame::resetShortcuts()
2✔
541
{
542
    int count = m_pageShortcuts.count();
2✔
543
    for (int i = 0; i < count; i++)
2✔
544
    {
545
        VCFramePageShortcut* shortcut = m_pageShortcuts.takeLast();
×
546
        delete shortcut;
×
547
    }
548
    m_pageShortcuts.clear();
2✔
549
}
2✔
550

551
QList<VCFramePageShortcut*> VCFrame::shortcuts() const
3✔
552
{
553
    return m_pageShortcuts;
3✔
554
}
555

556
void VCFrame::setPagesLoop(bool pagesLoop)
2✔
557
{
558
    m_pagesLoop = pagesLoop;
2✔
559
}
2✔
560

561
bool VCFrame::pagesLoop() const
1✔
562
{
563
    return m_pagesLoop;
1✔
564
}
565

566
void VCFrame::addWidgetToPageMap(VCWidget *widget)
8✔
567
{
568
    m_pagesMap.insert(widget, widget->page());
8✔
569
}
8✔
570

571
void VCFrame::removeWidgetFromPageMap(VCWidget *widget)
×
572
{
573
    m_pagesMap.remove(widget);
×
574
}
×
575

576
void VCFrame::slotPreviousPage()
×
577
{
578
    if (!m_pagesLoop && m_currentPage == 0)
×
579
        return;
×
580

581
    if (m_pagesLoop && m_currentPage == 0)
×
582
        slotSetPage(m_totalPagesNumber - 1);
×
583
    else
584
        slotSetPage(m_currentPage - 1);
×
585

586
    sendFeedback(m_currentPage, previousPageInputSourceId);
×
587
}
588

589
void VCFrame::slotNextPage()
×
590
{
591
    if (!m_pagesLoop && m_currentPage == m_totalPagesNumber - 1)
×
592
        return;
×
593

594
    if (m_pagesLoop && m_currentPage == m_totalPagesNumber - 1)
×
595
        slotSetPage(0);
×
596
    else
597
        slotSetPage(m_currentPage + 1);
×
598

599
    sendFeedback(m_currentPage, nextPageInputSourceId);
×
600
}
601

602
void VCFrame::slotSetPage(int pageNum)
17✔
603
{
604
    if (m_pageCombo)
17✔
605
    {
606
        if (pageNum >= 0 && pageNum < m_totalPagesNumber)
×
607
            m_currentPage = pageNum;
×
608

609
        m_pageCombo->blockSignals(true);
×
610
        m_pageCombo->setCurrentIndex(m_currentPage);
×
611
        m_pageCombo->blockSignals(false);
×
612
        setCaption(caption());
×
613

614
        QMapIterator <VCWidget*, int> it(m_pagesMap);
×
615
        while (it.hasNext() == true)
×
616
        {
617
            it.next();
×
618
            int page = it.value();
×
619
            VCWidget *widget = it.key();
×
620
            if (page == m_currentPage)
×
621
            {
622
                widget->setEnabled(true);
×
623
                widget->show();
×
624
                widget->updateFeedback();
×
625
            }
626
            else
627
            {
628
                widget->setEnabled(false);
×
629
                widget->hide();
×
630
            }
631
        }
632
        m_doc->setModified();
×
633
        emit pageChanged(m_currentPage);
×
634
    }
×
635
    updateFeedback();
17✔
636
}
17✔
637

638
void VCFrame::slotModeChanged(Doc::Mode mode)
21✔
639
{
640
    if (mode == Doc::Operate)
21✔
641
    {
642
        if (isDisabled())
16✔
643
            slotEnableButtonClicked(false);
×
644
        slotSetPage(currentPage());
16✔
645
        updateSubmasterValue();
16✔
646
        updateFeedback();
16✔
647
    }
648

649
    VCWidget::slotModeChanged(mode);
21✔
650
}
21✔
651

652
/*********************************************************************
653
 * Submasters
654
 *********************************************************************/
655

656
void VCFrame::slotSubmasterValueChanged(qreal value)
×
657
{
658
    qDebug() << Q_FUNC_INFO << "val:" << value;
×
659
    VCSlider *submaster = qobject_cast<VCSlider *>(sender());
×
660
    QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
×
661
    while (it.hasNext() == true)
×
662
    {
663
        VCWidget *child = it.next();
×
664
        if (child != NULL && child->parent() == this && child != submaster)
×
665
            child->adjustIntensity(value);
×
666
    }
667
}
×
668

669
void VCFrame::updateSubmasterValue()
16✔
670
{
671
    QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
16✔
672
    while (it.hasNext() == true)
18✔
673
    {
674
        VCWidget* child = it.next();
2✔
675
        if (child != NULL && child->parent() == this && child->type() == SliderWidget)
2✔
676
        {
677
            VCSlider* slider = reinterpret_cast<VCSlider*>(child);
×
678
            if (slider != NULL && slider->sliderMode() == VCSlider::Submaster)
×
679
                slider->emitSubmasterValue();
×
680
        }
681
    }
682
}
16✔
683

684
void VCFrame::adjustIntensity(qreal val)
×
685
{
686
    VCWidget::adjustIntensity(val);
×
687

688
    if (isDisabled())
×
689
        return;
×
690

691
    QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
×
692
    while (it.hasNext() == true)
×
693
    {
694
        VCWidget *child = it.next();
×
695
        if (child != NULL && child->parent() == this)
×
696
            child->adjustIntensity(val);
×
697
    }
698

699
    updateSubmasterValue();
×
700
}
×
701

702
/*****************************************************************************
703
 * Key Sequences
704
 *****************************************************************************/
705

706
void VCFrame::setEnableKeySequence(const QKeySequence &keySequence)
2✔
707
{
708
    m_enableKeySequence = QKeySequence(keySequence);
2✔
709
}
2✔
710

711
QKeySequence VCFrame::enableKeySequence() const
1✔
712
{
713
    return m_enableKeySequence;
1✔
714
}
715

716
void VCFrame::setCollapseKeySequence(const QKeySequence &keySequence)
2✔
717
{
718
    m_collapseKeySequence = QKeySequence(keySequence);
2✔
719
}
2✔
720

721
QKeySequence VCFrame::collapseKeySequence() const
1✔
722
{
723
    return m_collapseKeySequence;
1✔
724
}
725

726
void VCFrame::setNextPageKeySequence(const QKeySequence& keySequence)
2✔
727
{
728
    m_nextPageKeySequence = QKeySequence(keySequence);
2✔
729
}
2✔
730

731
QKeySequence VCFrame::nextPageKeySequence() const
1✔
732
{
733
    return m_nextPageKeySequence;
1✔
734
}
735

736
void VCFrame::setPreviousPageKeySequence(const QKeySequence& keySequence)
2✔
737
{
738
    m_previousPageKeySequence = QKeySequence(keySequence);
2✔
739
}
2✔
740

741
QKeySequence VCFrame::previousPageKeySequence() const
1✔
742
{
743
    return m_previousPageKeySequence;
1✔
744
}
745

746
void VCFrame::slotKeyPressed(const QKeySequence& keySequence)
×
747
{
748
    if (isEnabled() == false)
×
749
        return;
×
750

751
    if (m_enableKeySequence == keySequence)
×
752
        setDisableState(!isDisabled());
×
NEW
753
    else if (m_collapseKeySequence == keySequence && m_collapseButton != NULL)
×
NEW
754
        m_collapseButton->toggle();
×
755
    else if (m_previousPageKeySequence == keySequence)
×
756
        slotPreviousPage();
×
757
    else if (m_nextPageKeySequence == keySequence)
×
758
        slotNextPage();
×
759
    else
760
    {
761
        foreach (VCFramePageShortcut* shortcut, m_pageShortcuts)
×
762
        {
763
            if (shortcut->m_keySequence == keySequence)
×
764
                slotSetPage(shortcut->m_page);
×
765
        }
×
766
    }
767
}
768

769
void VCFrame::updateFeedback()
33✔
770
{
771
    {
772
        QSharedPointer<QLCInputSource> src = inputSource(enableInputSourceId);
33✔
773
        if (!src.isNull() && src->isValid() == true)
33✔
774
        {
NEW
775
            if (m_disableState == false)
×
776
            {
NEW
777
                sendFeedback(src->feedbackValue(QLCInputFeedback::UpperValue), enableInputSourceId);
×
778
            }
779
            else
780
            {
781
                // temporarily revert the disabled state otherwise this
782
                // feedback will never go through (cause of acceptsInput)
NEW
783
                m_disableState = false;
×
NEW
784
                sendFeedback(src->feedbackValue(QLCInputFeedback::LowerValue), enableInputSourceId);
×
NEW
785
                m_disableState = true;
×
786
            }
787
        }
788
    }
33✔
789

790
    {
791
        QSharedPointer<QLCInputSource> src = inputSource(collpseInputSourceId);
33✔
792
        if (!src.isNull() && src->isValid() == true)
33✔
793
        {
NEW
794
            if (m_collapsed == false)
×
795
            {
NEW
796
                sendFeedback(src->feedbackValue(QLCInputFeedback::UpperValue), collpseInputSourceId);
×
797
            }
798
            else
799
            {
800
                // temporarily revert the disabled state otherwise this
801
                // feedback will never go through (cause of acceptsInput)
NEW
802
                if (m_disableState)
×
803
                {
NEW
804
                    m_disableState = false;
×
NEW
805
                    sendFeedback(src->feedbackValue(QLCInputFeedback::LowerValue), collpseInputSourceId);
×
NEW
806
                    m_disableState = true;
×
807
                }
808
                else
809
                {
NEW
810
                    sendFeedback(src->feedbackValue(QLCInputFeedback::LowerValue), collpseInputSourceId);
×
811
                }
812
            }
813
        }
814
    }
33✔
815

816
    foreach (VCFramePageShortcut* shortcut, m_pageShortcuts)
33✔
817
    {
818
        QSharedPointer<QLCInputSource> src = shortcut->m_inputSource;
×
819
        if (!src.isNull() && src->isValid() == true)
×
820
        {
821
            if (m_currentPage == shortcut->m_page)
×
822
                sendFeedback(src->feedbackValue(QLCInputFeedback::UpperValue), src);
×
823
            else
824
                sendFeedback(src->feedbackValue(QLCInputFeedback::LowerValue), src);
×
825
        }
826
    }
33✔
827

828
    QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
33✔
829
    while (it.hasNext() == true)
37✔
830
    {
831
        VCWidget* child = it.next();
4✔
832
        if (child->parent() == this)
4✔
833
            child->updateFeedback();
4✔
834
    }
835
}
33✔
836

837
/*****************************************************************************
838
 * External input
839
 *****************************************************************************/
840

841
void VCFrame::slotInputValueChanged(quint32 universe, quint32 channel, uchar value)
×
842
{
843
    if (isEnabled() == false)
×
844
        return;
×
845

846
    quint32 pagedCh = (page() << 16) | channel;
×
847

848
    if (checkInputSource(universe, pagedCh, value, sender(), enableInputSourceId) && value)
×
849
        setDisableState(!isDisabled());
×
NEW
850
    else if (checkInputSource(universe, pagedCh, value, sender(), collpseInputSourceId) && value && m_collapseButton != NULL)
×
NEW
851
        m_collapseButton->toggle();
×
852
    else if (checkInputSource(universe, pagedCh, value, sender(), previousPageInputSourceId) && value)
×
853
        slotPreviousPage();
×
854
    else if (checkInputSource(universe, pagedCh, value, sender(), nextPageInputSourceId) && value)
×
855
        slotNextPage();
×
856
    else
857
    {
858
        foreach (VCFramePageShortcut* shortcut, m_pageShortcuts)
×
859
        {
860
            if (shortcut->m_inputSource != NULL &&
×
861
                    shortcut->m_inputSource->universe() == universe &&
×
862
                    shortcut->m_inputSource->channel() == pagedCh)
×
863
            {
864
                slotSetPage(shortcut->m_page);
×
865
            }
866
        }
×
867
    }
868
}
869

870
/*****************************************************************************
871
 * Clipboard
872
 *****************************************************************************/
873

874
VCWidget* VCFrame::createCopy(VCWidget* parent) const
1✔
875
{
876
    Q_ASSERT(parent != NULL);
1✔
877

878
    VCFrame* frame = new VCFrame(parent, m_doc, true);
1✔
879
    if (frame->copyFrom(this) == false)
1✔
880
    {
881
        delete frame;
×
882
        frame = NULL;
×
883
    }
884

885
    return frame;
1✔
886
}
887

888
bool VCFrame::copyFrom(const VCWidget* widget)
2✔
889
{
890
    const VCFrame* frame = qobject_cast<const VCFrame*> (widget);
2✔
891
    if (frame == NULL)
2✔
892
        return false;
1✔
893

894
    setHeaderVisible(frame->m_showHeader);
1✔
895
    setEnableButtonVisible(frame->m_showEnableButton);
1✔
896

897
    setMultipageMode(frame->m_multiPageMode);
1✔
898
    setTotalPagesNumber(frame->m_totalPagesNumber);
1✔
899

900
    setPagesLoop(frame->m_pagesLoop);
1✔
901

902
    setEnableKeySequence(frame->m_enableKeySequence);
1✔
903
    setCollapseKeySequence(frame->m_collapseKeySequence);
1✔
904
    setNextPageKeySequence(frame->m_nextPageKeySequence);
1✔
905
    setPreviousPageKeySequence(frame->m_previousPageKeySequence);
1✔
906
    setShortcuts(frame->shortcuts());
1✔
907

908
    QListIterator <VCWidget*> it(widget->findChildren<VCWidget*>());
1✔
909
    while (it.hasNext() == true)
2✔
910
    {
911
        VCWidget* child = it.next();
1✔
912
        VCWidget* childCopy = NULL;
1✔
913

914
        /* findChildren() is recursive, so the list contains all
915
           possible child widgets below this frame. Each frame must
916
           save only its direct children to preserve hierarchy, so
917
           save only such widgets that have this widget as their
918
           direct parent. */
919
        if (child->parentWidget() == widget)
1✔
920
        {
921
            childCopy = child->createCopy(this);
1✔
922
            VirtualConsole::instance()->addWidgetInMap(childCopy);
1✔
923

924
            qDebug() << "Child copy in parent:" << childCopy->caption() << ", page:" << childCopy->page();
1✔
925
        }
926

927
        if (childCopy != NULL)
1✔
928
        {
929
            addWidgetToPageMap(childCopy);
1✔
930

931
            if (childCopy->type() == VCWidget::SliderWidget)
1✔
932
            {
933
                VCSlider *slider = qobject_cast<VCSlider*>(childCopy);
×
934
                // always connect a slider as it it was a submaster
935
                // cause this signal is emitted only when a slider is
936
                // a submaster
937
                connect(slider, SIGNAL(submasterValueChanged(qreal)),
×
938
                        this, SLOT(slotSubmasterValueChanged(qreal)));
939
            }
940
        }
941
    }
942

943
    if (m_multiPageMode)
1✔
944
        slotSetPage(frame->m_currentPage);
×
945

946
    /* Copy common stuff */
947
    return VCWidget::copyFrom(widget);
1✔
948
}
1✔
949

950
/*****************************************************************************
951
 * Properties
952
 *****************************************************************************/
953

954
void VCFrame::applyProperties(VCFrameProperties const& prop)
×
955
{
956
    if (multipageMode() == true && prop.cloneWidgets() == true && m_pagesMap.isEmpty() == false)
×
957
    {
958
        for (int pg = 1; pg < totalPagesNumber(); pg++)
×
959
        {
960
            QListIterator <VCWidget*> it(this->findChildren<VCWidget*>());
×
961
            while (it.hasNext() == true)
×
962
            {
963
                VCWidget* child = it.next();
×
964
                if (child->page() == 0 && child->parentWidget() == this)
×
965
                {
966
                    VCWidget *newWidget = child->createCopy(this);
×
967
                    VirtualConsole::instance()->addWidgetInMap(newWidget);
×
968
                    //qDebug() << "Cloning:" << newWidget->caption() << ", copy page:" << newWidget->page() << ", page to set:" << pg;
969
                    newWidget->setPage(pg);
×
970
                    newWidget->remapInputSources(pg);
×
971
                    newWidget->show();
×
972

973
                    bool multiPageFrame = false;
×
974
                    if (newWidget->type() == VCWidget::FrameWidget || newWidget->type() == VCWidget::SoloFrameWidget)
×
975
                    {
976
                        VCFrame *fr = qobject_cast<VCFrame *>(newWidget);
×
977
                        multiPageFrame = fr->multipageMode();
×
978
                    }
979
                    /** If the cloned widget is again a multipage frame, then there's not much
980
                     *  that can be done to distinguish nested pages, so we leave the children
981
                     *  mapping as it is */
982
                    if (multiPageFrame == false)
×
983
                    {
984
                        /**
985
                         *  Remap input sources to the new page, otherwise
986
                         *  all the cloned widgets would respond to the
987
                         *  same controls
988
                         */
989
                        foreach (VCWidget* widget, newWidget->findChildren<VCWidget*>())
×
990
                        {
991
                            //qDebug() << "Child" << widget->caption() << ", page:" << widget->page() << ", new page:" << pg;
992
                            widget->setPage(pg);
×
993
                            widget->remapInputSources(pg);
×
994
                        }
×
995
                    }
996

997
                    addWidgetToPageMap(newWidget);
×
998
                }
999
            }
1000
        }
×
1001
        slotSetPage(0);
×
1002
    }
1003
    else if (multipageMode() == false)
×
1004
    {
1005
        setTotalPagesNumber(1);
×
1006
        resize(QSize(this->width(), this->height()));
×
1007

1008
        QMapIterator <VCWidget*, int> it(m_pagesMap);
×
1009
        while (it.hasNext() == true)
×
1010
        {
1011
            it.next();
×
1012
            int page = it.value();
×
1013
            VCWidget *widget = it.key();
×
1014
            if (page > 0)
×
1015
            {
1016
                removeWidgetFromPageMap(widget);
×
1017
                delete widget;
×
1018
            }
1019
            else
1020
            {
1021
                widget->setEnabled(true);
×
1022
                widget->show();
×
1023
                widget->updateFeedback();
×
1024
            }
1025
        }
1026
    }
×
1027
    VirtualConsole* vc = VirtualConsole::instance();
×
1028
    if (vc != NULL)
×
1029
        vc->reselectWidgets();
×
1030
}
×
1031

1032
void VCFrame::editProperties()
×
1033
{
1034
    if (isBottomFrame() == true)
×
1035
        return;
×
1036

1037
    VCFrameProperties prop(NULL, this, m_doc);
×
1038
    if (prop.exec() == QDialog::Accepted)
×
1039
    {
1040
        applyProperties(prop);
×
1041
    }
1042
}
×
1043

1044
/*****************************************************************************
1045
 * Load & Save
1046
 *****************************************************************************/
1047

1048
bool VCFrame::loadXML(QXmlStreamReader &root)
4✔
1049
{
1050
    bool disableState = false;
4✔
1051

1052
    if (root.name() != xmlTagName())
4✔
1053
    {
1054
        qWarning() << Q_FUNC_INFO << "Frame node not found";
1✔
1055
        return false;
1✔
1056
    }
1057

1058
    /* Widget commons */
1059
    loadXMLCommon(root);
3✔
1060

1061
    // Sorted list for new shortcuts
1062
    QList<VCFramePageShortcut *> newShortcuts;
3✔
1063

1064
    /* Children */
1065
    while (root.readNextStartElement())
14✔
1066
    {
1067
        /*
1068
        qDebug() << "VC Frame <" << caption() << "> tag:" << root.name();
1069
        if (root.attributes().hasAttribute("Caption"))
1070
            qDebug() << "Widget caption:" << root.attributes().value("Caption").toString();
1071
        */
1072

1073
        if (root.name() == KXMLQLCWindowState)
11✔
1074
        {
1075
            /* Frame geometry (visibility is ignored) */
1076
            int x = 0, y = 0, w = 0, h = 0;
1✔
1077
            bool visible = false;
1✔
1078
            loadXMLWindowState(root, &x, &y, &w, &h, &visible);
1✔
1079
            setGeometry(x, y, w, h);
1✔
1080
            m_width = w;
1✔
1081
            m_height = h;
1✔
1082
        }
1083
        else if (root.name() == KXMLQLCVCWidgetAppearance)
10✔
1084
        {
1085
            /* Frame appearance */
1086
            loadXMLAppearance(root);
×
1087
        }
1088
        else if (root.name() == KXMLQLCVCFrameAllowChildren)
10✔
1089
        {
1090
            /* Allow children */
1091
            if (root.readElementText() == KXMLQLCTrue)
1✔
1092
                setAllowChildren(true);
×
1093
            else
1094
                setAllowChildren(false);
1✔
1095
        }
1096
        else if (root.name() == KXMLQLCVCFrameAllowResize)
9✔
1097
        {
1098
            /* Allow resize */
1099
            if (root.readElementText() == KXMLQLCTrue)
1✔
1100
                setAllowResize(true);
×
1101
            else
1102
                setAllowResize(false);
1✔
1103
        }
1104
        else if (root.name() == KXMLQLCVCFrameIsCollapsed)
8✔
1105
        {
1106
            /* Collapsed */
1107
            if (root.readElementText() == KXMLQLCTrue && m_collapseButton != NULL)
×
1108
                m_collapseButton->toggle();
×
1109
        }
1110
        else if (root.name() == KXMLQLCVCFrameIsDisabled)
8✔
1111
        {
1112
            /* Enabled */
1113
            if (root.readElementText() == KXMLQLCTrue)
×
1114
                disableState = true;
×
1115
        }
1116
        else if (root.name() == KXMLQLCVCFrameShowHeader)
8✔
1117
        {
1118
            if (root.readElementText() == KXMLQLCTrue)
×
1119
                setHeaderVisible(true);
×
1120
            else
1121
                setHeaderVisible(false);
×
1122
        }
1123
        else if (root.name() == KXMLQLCVCFrameShowEnableButton)
8✔
1124
        {
1125
            if (root.readElementText() == KXMLQLCTrue)
×
1126
                setEnableButtonVisible(true);
×
1127
            else
1128
                setEnableButtonVisible(false);
×
1129
        }
1130
        else if (this->type() == SoloFrameWidget && root.name() == KXMLQLCVCSoloFrameMixing)
8✔
1131
        {
1132
            if (root.readElementText() == KXMLQLCTrue)
×
1133
                reinterpret_cast<VCSoloFrame*>(this)->setSoloframeMixing(true);
×
1134
            else
1135
                reinterpret_cast<VCSoloFrame*>(this)->setSoloframeMixing(false);
×
1136
        }
1137
        else if (this->type() == SoloFrameWidget && root.name() == KXMLQLCVCSoloFrameExclude)
8✔
1138
        {
1139
            if (root.readElementText() == KXMLQLCTrue)
×
1140
                reinterpret_cast<VCSoloFrame*>(this)->setExcludeMonitoredFunctions(true);
×
1141
            else
1142
                reinterpret_cast<VCSoloFrame*>(this)->setExcludeMonitoredFunctions(false);
×
1143
        }
1144
        else if (root.name() == KXMLQLCVCFrameMultipage)
8✔
1145
        {
1146
            setMultipageMode(true);
×
1147
            QXmlStreamAttributes attrs = root.attributes();
×
1148
            if (attrs.hasAttribute(KXMLQLCVCFramePagesNumber))
×
1149
                setTotalPagesNumber(attrs.value(KXMLQLCVCFramePagesNumber).toString().toInt());
×
1150

1151
            if (attrs.hasAttribute(KXMLQLCVCFrameCurrentPage))
×
1152
                slotSetPage(attrs.value(KXMLQLCVCFrameCurrentPage).toString().toInt());
×
1153
            root.skipCurrentElement();
×
1154
        }
×
1155
        else if (root.name() == KXMLQLCVCFrameEnableSource)
8✔
1156
        {
1157
            QString str = loadXMLSources(root, enableInputSourceId);
×
1158
            if (str.isEmpty() == false)
×
1159
                setEnableKeySequence(stripKeySequence(QKeySequence(str)));
×
1160
        }
×
1161
        else if (root.name() == KXMLQLCVCFrameCollapseSource)
8✔
1162
        {
NEW
1163
            QString str = loadXMLSources(root, collpseInputSourceId);
×
NEW
1164
            if (str.isEmpty() == false)
×
NEW
1165
                setCollapseKeySequence(stripKeySequence(QKeySequence(str)));
×
NEW
1166
        }
×
1167
        else if (root.name() == KXMLQLCVCFrameNext)
8✔
1168
        {
1169
            QString str = loadXMLSources(root, nextPageInputSourceId);
×
1170
            if (str.isEmpty() == false)
×
1171
                setNextPageKeySequence(stripKeySequence(QKeySequence(str)));
×
1172
        }
×
1173
        else if (root.name() == KXMLQLCVCFramePrevious)
8✔
1174
        {
1175
            QString str = loadXMLSources(root, previousPageInputSourceId);
×
1176
            if (str.isEmpty() == false)
×
1177
                setPreviousPageKeySequence(stripKeySequence(QKeySequence(str)));
×
1178
        }
×
1179
        else if (root.name() == KXMLQLCVCFramePagesLoop)
8✔
1180
        {
1181
            if (root.readElementText() == KXMLQLCTrue)
×
1182
                setPagesLoop(true);
×
1183
            else
1184
                setPagesLoop(false);
×
1185
        }
1186
        else if (root.name() == KXMLQLCVCFramePageShortcut)
8✔
1187
        {
1188
            VCFramePageShortcut *shortcut = new VCFramePageShortcut(0xFF, 0xFF);
×
1189
            if (shortcut->loadXML(root))
×
1190
            {
1191
                shortcut->m_id = VCFrame::shortcutsBaseInputSourceId + shortcut->m_page;
×
1192
                newShortcuts.append(shortcut);
×
1193
            }
1194
        }
1195
        else if (root.name() == KXMLQLCVCFrame)
8✔
1196
        {
1197
            /* Create a new frame into its parent */
1198
            VCFrame* frame = new VCFrame(this, m_doc, true);
1✔
1199
            if (frame->loadXML(root) == false)
1✔
1200
                delete frame;
×
1201
            else
1202
            {
1203
                addWidgetToPageMap(frame);
1✔
1204
                frame->show();
1✔
1205
            }
1206
        }
1207
        else if (root.name() == KXMLQLCVCLabel)
7✔
1208
        {
1209
            /* Create a new label into its parent */
1210
            VCLabel* label = new VCLabel(this, m_doc);
1✔
1211
            if (label->loadXML(root) == false)
1✔
1212
                delete label;
×
1213
            else
1214
            {
1215
                addWidgetToPageMap(label);
1✔
1216
                label->show();
1✔
1217
            }
1218
        }
1219
        else if (root.name() == KXMLQLCVCButton)
6✔
1220
        {
1221
            /* Create a new button into its parent */
1222
            VCButton* button = new VCButton(this, m_doc);
1✔
1223
            if (button->loadXML(root) == false)
1✔
1224
                delete button;
×
1225
            else
1226
            {
1227
                addWidgetToPageMap(button);
1✔
1228
                button->show();
1✔
1229
            }
1230
        }
1231
        else if (root.name() == KXMLQLCVCXYPad)
5✔
1232
        {
1233
            /* Create a new xy pad into its parent */
1234
            VCXYPad* xypad = new VCXYPad(this, m_doc);
1✔
1235
            if (xypad->loadXML(root) == false)
1✔
1236
                delete xypad;
×
1237
            else
1238
            {
1239
                addWidgetToPageMap(xypad);
1✔
1240
                xypad->show();
1✔
1241
            }
1242
        }
1243
        else if (root.name() == KXMLQLCVCSlider)
4✔
1244
        {
1245
            /* Create a new slider into its parent */
1246
            VCSlider* slider = new VCSlider(this, m_doc);
1✔
1247
            if (slider->loadXML(root) == false)
1✔
1248
            {
1249
                delete slider;
×
1250
            }
1251
            else
1252
            {
1253
                addWidgetToPageMap(slider);
1✔
1254
                slider->show();
1✔
1255
                // always connect a slider as if it was a submaster
1256
                // cause this signal is emitted only when a slider is
1257
                // a submaster
1258
                connect(slider, SIGNAL(submasterValueChanged(qreal)),
1✔
1259
                        this, SLOT(slotSubmasterValueChanged(qreal)));
1260
            }
1261
        }
1262
        else if (root.name() == KXMLQLCVCSoloFrame)
3✔
1263
        {
1264
            /* Create a new frame into its parent */
1265
            VCSoloFrame* soloframe = new VCSoloFrame(this, m_doc, true);
1✔
1266
            if (soloframe->loadXML(root) == false)
1✔
1267
                delete soloframe;
×
1268
            else
1269
            {
1270
                if (m_doc->mode() == Doc::Operate)
1✔
1271
                    soloframe->updateChildrenConnection(true);
×
1272
                addWidgetToPageMap(soloframe);
1✔
1273
                soloframe->show();
1✔
1274
            }
1275
        }
1276
        else if (root.name() == KXMLQLCVCCueList)
2✔
1277
        {
1278
            /* Create a new cuelist into its parent */
1279
            VCCueList* cuelist = new VCCueList(this, m_doc);
1✔
1280
            if (cuelist->loadXML(root) == false)
1✔
1281
                delete cuelist;
×
1282
            else
1283
            {
1284
                addWidgetToPageMap(cuelist);
1✔
1285
                cuelist->show();
1✔
1286
            }
1287
        }
1288
        else if (root.name() == KXMLQLCVCSpeedDial)
1✔
1289
        {
1290
            /* Create a new speed dial into its parent */
1291
            VCSpeedDial* dial = new VCSpeedDial(this, m_doc);
×
1292
            if (dial->loadXML(root) == false)
×
1293
                delete dial;
×
1294
            else
1295
            {
1296
                addWidgetToPageMap(dial);
×
1297
                dial->show();
×
1298
            }
1299
        }
1300
        else if (root.name() == KXMLQLCVCAudioTriggers)
1✔
1301
        {
1302
            VCAudioTriggers* triggers = new VCAudioTriggers(this, m_doc);
×
1303
            if (triggers->loadXML(root) == false)
×
1304
                delete triggers;
×
1305
            else
1306
            {
1307
                addWidgetToPageMap(triggers);
×
1308
                triggers->show();
×
1309
            }
1310
        }
1311
        else if (root.name() == KXMLQLCVCClock)
1✔
1312
        {
1313
            /* Create a new VCClock into its parent */
1314
            VCClock* clock = new VCClock(this, m_doc);
×
1315
            if (clock->loadXML(root) == false)
×
1316
                delete clock;
×
1317
            else
1318
            {
1319
                addWidgetToPageMap(clock);
×
1320
                clock->show();
×
1321
            }
1322
        }
1323
        else if (root.name() == KXMLQLCVCMatrix)
1✔
1324
        {
1325
            /* Create a new VCMatrix into its parent */
1326
            VCMatrix* matrix = new VCMatrix(this, m_doc);
×
1327
            if (matrix->loadXML(root) == false)
×
1328
                delete matrix;
×
1329
            else
1330
            {
1331
                addWidgetToPageMap(matrix);
×
1332
                matrix->show();
×
1333
            }
1334
        }
1335
        else
1336
        {
1337
            qWarning() << Q_FUNC_INFO << "Unknown frame tag:" << root.name().toString();
1✔
1338
            root.skipCurrentElement();
1✔
1339
        }
1340
    }
1341

1342
    if (multipageMode() == true)
3✔
1343
    {
1344
        if (newShortcuts.count() == m_totalPagesNumber)
×
1345
            setShortcuts(newShortcuts);
×
1346
        else
1347
            qWarning() << Q_FUNC_INFO << "Shortcut number does not match page number";
×
1348

1349
        // Set page again to update header
1350
        slotSetPage(m_currentPage);
×
1351
    }
1352

1353
    if (disableState == true)
3✔
1354
        setDisableState(true);
×
1355

1356
    return true;
3✔
1357
}
3✔
1358

1359
bool VCFrame::saveXML(QXmlStreamWriter *doc)
3✔
1360
{
1361
    Q_ASSERT(doc != NULL);
3✔
1362

1363
    /* VC Frame entry */
1364
    doc->writeStartElement(xmlTagName());
3✔
1365

1366
    saveXMLCommon(doc);
3✔
1367

1368
    /* Save appearance */
1369
    saveXMLAppearance(doc);
3✔
1370

1371
    if (isBottomFrame() == false)
3✔
1372
    {
1373
        /* Save widget proportions only for child frames */
1374
        if (isCollapsed())
2✔
1375
        {
1376
            resize(QSize(m_width, m_height));
×
1377
            saveXMLWindowState(doc);
×
1378
            resize(QSize(200, 40));
×
1379
        }
1380
        else
1381
            saveXMLWindowState(doc);
2✔
1382

1383
        /* Allow children */
1384
        doc->writeTextElement(KXMLQLCVCFrameAllowChildren, allowChildren() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1385

1386
        /* Allow resize */
1387
        doc->writeTextElement(KXMLQLCVCFrameAllowResize, allowResize() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1388

1389
        /* ShowHeader */
1390
        doc->writeTextElement(KXMLQLCVCFrameShowHeader, isHeaderVisible() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1391

1392
        /* ShowEnableButton */
1393
        doc->writeTextElement(KXMLQLCVCFrameShowEnableButton, isEnableButtonVisible() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1394

1395
        /* Solo frame mixing */
1396
        if (this->type() == SoloFrameWidget)
2✔
1397
        {
1398
            VCSoloFrame *solo = reinterpret_cast<VCSoloFrame*>(this);
×
1399
            if (solo->soloframeMixing())
×
1400
                doc->writeTextElement(KXMLQLCVCSoloFrameMixing, KXMLQLCTrue);
×
1401
            else
1402
                doc->writeTextElement(KXMLQLCVCSoloFrameMixing, KXMLQLCFalse);
×
1403

1404
            if (solo->excludeMonitoredFunctions())
×
1405
                doc->writeTextElement(KXMLQLCVCSoloFrameExclude, KXMLQLCTrue);
×
1406
        }
1407

1408
        /* Collapsed */
1409
        doc->writeTextElement(KXMLQLCVCFrameIsCollapsed, isCollapsed() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1410

1411
        /* Disabled */
1412
        doc->writeTextElement(KXMLQLCVCFrameIsDisabled, isDisabled() ? KXMLQLCTrue : KXMLQLCFalse);
6✔
1413

1414
        /* Enable control */
1415
        {
1416
            QString keySeq = m_enableKeySequence.toString();
2✔
1417
            QSharedPointer<QLCInputSource> enableSrc = inputSource(enableInputSourceId);
2✔
1418

1419
            if (keySeq.isEmpty() == false || (!enableSrc.isNull() && enableSrc->isValid()))
2✔
1420
            {
NEW
1421
                doc->writeStartElement(KXMLQLCVCFrameEnableSource);
×
NEW
1422
                if (keySeq.isEmpty() == false)
×
NEW
1423
                    doc->writeTextElement(KXMLQLCVCWidgetKey, keySeq);
×
NEW
1424
                saveXMLInput(doc, enableSrc);
×
NEW
1425
                doc->writeEndElement();
×
1426
            }
1427
        }
2✔
1428

1429
        /* Collapse control */
1430
        {
1431
            QString keySeq = m_collapseKeySequence.toString();
2✔
1432
            QSharedPointer<QLCInputSource> collapseSrc = inputSource(collpseInputSourceId);
2✔
1433

1434
            if (keySeq.isEmpty() == false || (!collapseSrc.isNull() && collapseSrc->isValid()))
2✔
1435
            {
NEW
1436
                doc->writeStartElement(KXMLQLCVCFrameCollapseSource);
×
NEW
1437
                if (keySeq.isEmpty() == false)
×
NEW
1438
                    doc->writeTextElement(KXMLQLCVCWidgetKey, keySeq);
×
NEW
1439
                saveXMLInput(doc, collapseSrc);
×
NEW
1440
                doc->writeEndElement();
×
1441
            }
1442
        }
2✔
1443

1444
        /* Multipage mode */
1445
        if (multipageMode() == true)
2✔
1446
        {
1447
            doc->writeStartElement(KXMLQLCVCFrameMultipage);
×
1448
            doc->writeAttribute(KXMLQLCVCFramePagesNumber, QString::number(totalPagesNumber()));
×
1449
            doc->writeAttribute(KXMLQLCVCFrameCurrentPage, QString::number(currentPage()));
×
1450
            doc->writeEndElement();
×
1451

1452
            /* Next page */
1453
            {
NEW
1454
                QString keySeq = m_nextPageKeySequence.toString();
×
NEW
1455
                QSharedPointer<QLCInputSource> nextSrc = inputSource(nextPageInputSourceId);
×
1456

NEW
1457
                if (keySeq.isEmpty() == false || (!nextSrc.isNull() && nextSrc->isValid()))
×
1458
                {
NEW
1459
                    doc->writeStartElement(KXMLQLCVCFrameNext);
×
NEW
1460
                    if (keySeq.isEmpty() == false)
×
NEW
1461
                        doc->writeTextElement(KXMLQLCVCWidgetKey, keySeq);
×
NEW
1462
                    saveXMLInput(doc, nextSrc);
×
NEW
1463
                    doc->writeEndElement();
×
1464
                }
UNCOV
1465
            }
×
1466

1467
            /* Previous page */
1468
            {
NEW
1469
                QString keySeq = m_previousPageKeySequence.toString();
×
NEW
1470
                QSharedPointer<QLCInputSource> prevSrc = inputSource(previousPageInputSourceId);
×
1471

NEW
1472
                if (keySeq.isEmpty() == false || (!prevSrc.isNull() && prevSrc->isValid()))
×
1473
                {
NEW
1474
                    doc->writeStartElement(KXMLQLCVCFramePrevious);
×
NEW
1475
                    if (keySeq.isEmpty() == false)
×
NEW
1476
                        doc->writeTextElement(KXMLQLCVCWidgetKey, keySeq);
×
NEW
1477
                    saveXMLInput(doc, prevSrc);
×
NEW
1478
                    doc->writeEndElement();
×
1479
                }
UNCOV
1480
            }
×
1481

1482
            /* Page shortcuts */
1483
            foreach (VCFramePageShortcut *shortcut, shortcuts())
×
1484
                shortcut->saveXML(doc);
×
1485

1486
            /* Pages Loop */
1487
            doc->writeTextElement(KXMLQLCVCFramePagesLoop, m_pagesLoop ? KXMLQLCTrue : KXMLQLCFalse);
×
1488
        }
1489
    }
1490

1491
    /* Save children */
1492
    QListIterator <VCWidget*> it(findChildren<VCWidget*>());
3✔
1493
    while (it.hasNext() == true)
6✔
1494
    {
1495
        VCWidget* widget = it.next();
3✔
1496

1497
        /* findChildren() is recursive, so the list contains all
1498
           possible child widgets below this frame. Each frame must
1499
           save only its direct children to preserve hierarchy, so
1500
           save only such widgets that have this widget as their
1501
           direct parent. */
1502
        if (widget->parentWidget() == this)
3✔
1503
            widget->saveXML(doc);
2✔
1504
    }
1505

1506
    /* End the <Frame> tag */
1507
    doc->writeEndElement();
3✔
1508

1509
    return true;
3✔
1510
}
3✔
1511

1512
void VCFrame::postLoad()
3✔
1513
{
1514
    QListIterator <VCWidget*> it(findChildren<VCWidget*>());
3✔
1515
    while (it.hasNext() == true)
10✔
1516
    {
1517
        VCWidget* widget = it.next();
7✔
1518

1519
        /* findChildren() is recursive, so the list contains all
1520
           possible child widgets below this frame. Each frame must
1521
           save only its direct children to preserve hierarchy, so
1522
           save only such widgets that have this widget as their
1523
           direct parent. */
1524
        if (widget->parentWidget() == this)
7✔
1525
            widget->postLoad();
7✔
1526
    }
1527
}
3✔
1528

1529
QString VCFrame::xmlTagName() const
6✔
1530
{
1531
    return KXMLQLCVCFrame;
6✔
1532
}
1533

1534
/*****************************************************************************
1535
 * Custom menu
1536
 *****************************************************************************/
1537

1538
QMenu* VCFrame::customMenu(QMenu* parentMenu) const
8✔
1539
{
1540
    QMenu* menu = NULL;
8✔
1541
    VirtualConsole* vc = VirtualConsole::instance();
8✔
1542

1543
    if (allowChildren() == true && vc != NULL)
8✔
1544
    {
1545
        /* Basically, just returning VC::addMenu() would suffice here, but
1546
           since the returned menu will be deleted when the current widget
1547
           changes, we have to copy the menu's contents into a new menu. */
1548
        menu = new QMenu(parentMenu);
8✔
1549
        menu->setTitle(tr("Add"));
8✔
1550
        QListIterator <QAction*> it(vc->addMenu()->actions());
8✔
1551
        while (it.hasNext() == true)
144✔
1552
            menu->addAction(it.next());
136✔
1553
    }
8✔
1554

1555
    return menu;
8✔
1556
}
1557

1558
/*****************************************************************************
1559
 * Event handlers
1560
 *****************************************************************************/
1561

1562
void VCFrame::handleWidgetSelection(QMouseEvent* e)
4✔
1563
{
1564
    /* No point coming here if there is no VC */
1565
    VirtualConsole* vc = VirtualConsole::instance();
4✔
1566
    if (vc == NULL)
4✔
1567
        return;
×
1568

1569
    /* Don't allow selection of the bottom frame. Selecting it will always
1570
       actually clear the current selection. */
1571
    if (isBottomFrame() == false)
4✔
1572
        VCWidget::handleWidgetSelection(e);
1✔
1573
    else
1574
        vc->clearWidgetSelection();
3✔
1575
}
1576

1577
void VCFrame::mouseMoveEvent(QMouseEvent* e)
2✔
1578
{
1579
    if (isBottomFrame() == false)
2✔
1580
        VCWidget::mouseMoveEvent(e);
1✔
1581
    else
1582
        QWidget::mouseMoveEvent(e);
1✔
1583

1584
    if (isCollapsed() == false)
2✔
1585
    {
1586
        m_width = this->width();
2✔
1587
        m_height = this->height();
2✔
1588
    }
1589
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc