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

mcallegari / qlcplus / 7252848206

18 Dec 2023 07:26PM UTC coverage: 32.067% (+0.001%) from 32.066%
7252848206

push

github

mcallegari
Code style review #1427

199 of 628 new or added lines in 101 files covered. (31.69%)

8 existing lines in 2 files now uncovered.

15169 of 47304 relevant lines covered (32.07%)

23733.74 hits per line

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

0.0
/ui/src/functionmanager.cpp
1
/*
2
  Q Light Controller
3
  functionmanager.cpp
4

5
  Copyright (C) Heikki Junnila
6
  Copyright (C) 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 <QTreeWidgetItemIterator>
22
#include <QTreeWidgetItem>
23
#include <QInputDialog>
24
#include <QTreeWidget>
25
#include <QHeaderView>
26
#include <QMessageBox>
27
#include <QVBoxLayout>
28
#include <QFileDialog>
29
#include <QCheckBox>
30
#include <QSplitter>
31
#include <QSettings>
32
#include <QToolBar>
33
#include <QMenuBar>
34
#include <QPixmap>
35
#include <QDebug>
36
#include <QMenu>
37
#include <QList>
38
#include <QIcon>
39

40
#include "functionstreewidget.h"
41
#include "functionselection.h"
42
#include "collectioneditor.h"
43
#include "audioplugincache.h"
44
#include "functionmanager.h"
45
#include "rgbmatrixeditor.h"
46
#include "functionwizard.h"
47
#include "chasereditor.h"
48
#include "scripteditor.h"
49
#include "sceneeditor.h"
50
#include "audioeditor.h"
51
#include "videoeditor.h"
52
#include "showeditor.h"
53
#include "collection.h"
54
#include "efxeditor.h"
55
#include "rgbmatrix.h"
56
#include "function.h"
57
#include "sequence.h"
58
#include "chaser.h"
59
#include "script.h"
60
#include "scene.h"
61
#include "audio.h"
62
#include "video.h"
63
#include "show.h"
64
#include "doc.h"
65
#include "efx.h"
66

67
#define COL_NAME 0
68
#define COL_PATH 1
69

70
#define SETTINGS_SPLITTER "functionmanager/splitter"
71

72
FunctionManager* FunctionManager::s_instance = NULL;
73

74
/*****************************************************************************
75
 * Initialization
76
 *****************************************************************************/
77

78
FunctionManager::FunctionManager(QWidget* parent, Doc* doc)
×
79
    : QWidget(parent)
80
    , m_doc(doc)
81
    , m_hsplitter(NULL)
82
    , m_vsplitter(NULL)
83
    , m_tree(NULL)
84
    , m_toolbar(NULL)
85
    , m_addSceneAction(NULL)
86
    , m_addChaserAction(NULL)
87
    , m_addCollectionAction(NULL)
88
    , m_addEFXAction(NULL)
89
    , m_addRGBMatrixAction(NULL)
90
    , m_addScriptAction(NULL)
91
    , m_addAudioAction(NULL)
92
    , m_addVideoAction(NULL)
93
    , m_autostartAction(NULL)
94
    , m_wizardAction(NULL)
95
    , m_addFolderAction(NULL)
96
    , m_cloneAction(NULL)
97
    , m_deleteAction(NULL)
98
    , m_selectAllAction(NULL)
99
    , m_editor(NULL)
100
    , m_scene_editor(NULL)
×
101
{
102
    Q_ASSERT(s_instance == NULL);
×
103
    s_instance = this;
×
104

105
    Q_ASSERT(doc != NULL);
×
106

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

111
    initActions();
×
112
    initToolbar();
×
113
    initSplitterView();
×
114
    updateActionStatus();
×
115

116
    connect(m_doc, SIGNAL(modeChanged(Doc::Mode)), this, SLOT(slotModeChanged()));
×
117
    m_tree->updateTree();
×
118

119
    connect(m_doc, SIGNAL(clearing()), this, SLOT(slotDocClearing()));
×
120
    connect(m_doc, SIGNAL(loading()), this, SLOT(slotDocLoading()));
×
121
    connect(m_doc, SIGNAL(loaded()), this, SLOT(slotDocLoaded()));
×
122
    connect(m_doc, SIGNAL(functionNameChanged(quint32)), this, SLOT(slotFunctionNameChanged(quint32)));
×
123
    connect(m_doc, SIGNAL(functionAdded(quint32)), this, SLOT(slotFunctionAdded(quint32)));
×
124

125
    QSettings settings;
×
126
    QVariant var = settings.value(SETTINGS_SPLITTER);
×
127
    if (var.isValid() == true)
×
128
        m_hsplitter->restoreState(var.toByteArray());
×
129
    else
130
        m_hsplitter->setSizes(QList <int> () << int(this->width() / 2) << int(this->width() / 2));
×
131
}
×
132

133
FunctionManager::~FunctionManager()
×
134
{
135
    QSettings settings;
×
136
    settings.setValue(SETTINGS_SPLITTER, m_hsplitter->saveState());
×
137

138
    FunctionManager::s_instance = NULL;
×
139
}
×
140

141
FunctionManager* FunctionManager::instance()
×
142
{
143
    return s_instance;
×
144
}
145

146
void FunctionManager::slotModeChanged()
×
147
{
148
    updateActionStatus();
×
149
}
×
150

151
void FunctionManager::slotDocClearing()
×
152
{
153
    deleteCurrentEditor(false); // Synchronous delete
×
154
    m_tree->clearTree();
×
155
}
×
156

157
void FunctionManager::slotDocLoading()
×
158
{
159
    disconnect(m_doc, SIGNAL(functionAdded(quint32)), this, SLOT(slotFunctionAdded(quint32)));
×
160
}
×
161

162
void FunctionManager::slotDocLoaded()
×
163
{
164
    connect(m_doc, SIGNAL(functionAdded(quint32)), this, SLOT(slotFunctionAdded(quint32)));
×
165

166
    m_tree->updateTree();
×
167
}
×
168

169
void FunctionManager::slotFunctionNameChanged(quint32 id)
×
170
{
171
    m_tree->functionNameChanged(id);
×
172
}
×
173

174
void FunctionManager::slotFunctionAdded(quint32 id)
×
175
{
176
    m_tree->addFunction(id);
×
177
}
×
178

179
void FunctionManager::showEvent(QShowEvent* ev)
×
180
{
181
    qDebug() << Q_FUNC_INFO;
×
182
    emit functionManagerActive(true);
×
183
    QWidget::showEvent(ev);
×
184
}
×
185

186
void FunctionManager::hideEvent(QHideEvent* ev)
×
187
{
188
    qDebug() << Q_FUNC_INFO;
×
189
    emit functionManagerActive(false);
×
190
    QWidget::hideEvent(ev);
×
191
}
×
192

193
/*****************************************************************************
194
 * Menu, toolbar and actions
195
 *****************************************************************************/
196

197
void FunctionManager::initActions()
×
198
{
199
    /* Manage actions */
200
    m_addSceneAction = new QAction(QIcon(":/scene.png"),
×
201
                                   tr("New &scene"), this);
×
202
    m_addSceneAction->setShortcut(QKeySequence("CTRL+1"));
×
203
    connect(m_addSceneAction, SIGNAL(triggered(bool)),
×
204
            this, SLOT(slotAddScene()));
205

206
    m_addChaserAction = new QAction(QIcon(":/chaser.png"),
×
207
                                    tr("New c&haser"), this);
×
208
    m_addChaserAction->setShortcut(QKeySequence("CTRL+2"));
×
209
    connect(m_addChaserAction, SIGNAL(triggered(bool)),
×
210
            this, SLOT(slotAddChaser()));
211

212
    m_addSequenceAction = new QAction(QIcon(":/sequence.png"),
×
213
                                    tr("New se&quence"), this);
×
214
    m_addSequenceAction->setShortcut(QKeySequence("CTRL+3"));
×
215
    connect(m_addSequenceAction, SIGNAL(triggered(bool)),
×
216
            this, SLOT(slotAddSequence()));
217

218
    m_addEFXAction = new QAction(QIcon(":/efx.png"),
×
219
                                 tr("New E&FX"), this);
×
220
    m_addEFXAction->setShortcut(QKeySequence("CTRL+4"));
×
221
    connect(m_addEFXAction, SIGNAL(triggered(bool)),
×
222
            this, SLOT(slotAddEFX()));
223

224
    m_addCollectionAction = new QAction(QIcon(":/collection.png"),
×
225
                                        tr("New c&ollection"), this);
×
226
    m_addCollectionAction->setShortcut(QKeySequence("CTRL+5"));
×
227
    connect(m_addCollectionAction, SIGNAL(triggered(bool)),
×
228
            this, SLOT(slotAddCollection()));
229

230
    m_addRGBMatrixAction = new QAction(QIcon(":/rgbmatrix.png"),
×
231
                                 tr("New &RGB Matrix"), this);
×
232
    m_addRGBMatrixAction->setShortcut(QKeySequence("CTRL+6"));
×
233
    connect(m_addRGBMatrixAction, SIGNAL(triggered(bool)),
×
234
            this, SLOT(slotAddRGBMatrix()));
235

236
    m_addScriptAction = new QAction(QIcon(":/script.png"),
×
237
                                 tr("New scrip&t"), this);
×
238
    m_addScriptAction->setShortcut(QKeySequence("CTRL+7"));
×
239
    connect(m_addScriptAction, SIGNAL(triggered(bool)),
×
240
            this, SLOT(slotAddScript()));
241

242
    m_addAudioAction = new QAction(QIcon(":/audio.png"),
×
243
                                   tr("New au&dio"), this);
×
244
    m_addAudioAction->setShortcut(QKeySequence("CTRL+8"));
×
245
    connect(m_addAudioAction, SIGNAL(triggered(bool)),
×
246
            this, SLOT(slotAddAudio()));
247

248
    m_addVideoAction = new QAction(QIcon(":/video.png"),
×
249
                                   tr("New vid&eo"), this);
×
250
    m_addVideoAction->setShortcut(QKeySequence("CTRL+9"));
×
251
    connect(m_addVideoAction, SIGNAL(triggered(bool)),
×
252
            this, SLOT(slotAddVideo()));
253

254
    m_addFolderAction = new QAction(QIcon(":/folder.png"),
×
255
                                   tr("New fo&lder"), this);
×
256
    m_addFolderAction->setShortcut(QKeySequence("CTRL+L"));
×
257
    connect(m_addFolderAction, SIGNAL(triggered(bool)),
×
258
            this, SLOT(slotAddFolder()));
259

260
    m_autostartAction = new QAction(QIcon(":/autostart.png"),
×
261
                                    tr("Select Startup Function"), this);
×
262
    connect(m_autostartAction, SIGNAL(triggered(bool)),
×
263
            this, SLOT(slotSelectAutostartFunction()));
264

265
    m_wizardAction = new QAction(QIcon(":/wizard.png"),
×
266
                                 tr("Function &Wizard"), this);
×
267
    m_wizardAction->setShortcut(QKeySequence("CTRL+W"));
×
268
    connect(m_wizardAction, SIGNAL(triggered(bool)),
×
269
            this, SLOT(slotWizard()));
270

271
    /* Edit actions */
272
    m_cloneAction = new QAction(QIcon(":/editcopy.png"),
×
273
                                tr("&Clone"), this);
×
274
    m_cloneAction->setShortcut(QKeySequence("CTRL+C"));
×
275
    connect(m_cloneAction, SIGNAL(triggered(bool)),
×
276
            this, SLOT(slotClone()));
277

278
    m_deleteAction = new QAction(QIcon(":/editdelete.png"),
×
279
                                 tr("&Delete"), this);
×
280
    m_deleteAction->setShortcut(QKeySequence("Delete"));
×
281
    connect(m_deleteAction, SIGNAL(triggered(bool)),
×
282
            this, SLOT(slotDelete()));
283

284
    m_selectAllAction = new QAction(QIcon(":/selectall.png"),
×
285
                                    tr("Select &all"), this);
×
286
    m_selectAllAction->setShortcut(QKeySequence("CTRL+A"));
×
287
    connect(m_selectAllAction, SIGNAL(triggered(bool)),
×
288
            this, SLOT(slotSelectAll()));
289
}
×
290

291
void FunctionManager::initToolbar()
×
292
{
293
    // Add a toolbar to the dock area
294
    m_toolbar = new QToolBar("Function Manager", this);
×
295
    m_toolbar->setFloatable(false);
×
296
    m_toolbar->setMovable(false);
×
297
    layout()->addWidget(m_toolbar);
×
298
    m_toolbar->addAction(m_addSceneAction);
×
299
    m_toolbar->addAction(m_addChaserAction);
×
300
    m_toolbar->addAction(m_addSequenceAction);
×
301
    m_toolbar->addAction(m_addEFXAction);
×
302
    m_toolbar->addAction(m_addCollectionAction);
×
303
    m_toolbar->addAction(m_addRGBMatrixAction);
×
304
    m_toolbar->addAction(m_addScriptAction);
×
305
    m_toolbar->addAction(m_addAudioAction);
×
306
    m_toolbar->addAction(m_addVideoAction);
×
307
    m_toolbar->addSeparator();
×
308
    m_toolbar->addAction(m_addFolderAction);
×
309
    m_toolbar->addSeparator();
×
310
    m_toolbar->addAction(m_autostartAction);
×
311
    m_toolbar->addAction(m_wizardAction);
×
312
    m_toolbar->addSeparator();
×
313
    m_toolbar->addAction(m_cloneAction);
×
314
    m_toolbar->addSeparator();
×
315
    m_toolbar->addAction(m_deleteAction);
×
316
}
×
317

318
void FunctionManager::slotAddScene()
×
319
{
320
    Function* f = new Scene(m_doc);
×
321
    if (m_doc->addFunction(f) == true)
×
322
    {
323
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
324
        Q_ASSERT(item != NULL);
×
325
        f->setName(QString("%1 %2").arg(tr("New Scene")).arg(f->id()));
×
326
        m_tree->scrollToItem(item);
×
327
        m_tree->setCurrentItem(item);
×
328
    }
329
}
×
330

331
void FunctionManager::slotAddChaser()
×
332
{
333
    Function* f = new Chaser(m_doc);
×
334
    if (m_doc->addFunction(f) == true)
×
335
    {
336
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
337
        Q_ASSERT(item != NULL);
×
338
        f->setName(QString("%1 %2").arg(tr("New Chaser")).arg(f->id()));
×
339
        m_tree->scrollToItem(item);
×
340
        m_tree->setCurrentItem(item);
×
341
    }
342
}
×
343

344
void FunctionManager::slotAddSequence()
×
345
{
346
    // a Sequence depends on a Scene, so let's create
347
    // a new hidden Scene first
348
    Function *scene = new Scene(m_doc);
×
349
    scene->setVisible(false);
×
350

351
    if (m_doc->addFunction(scene) == true)
×
352
    {
353
        Function* f = new Sequence(m_doc);
×
354
        Sequence *sequence = qobject_cast<Sequence *>(f);
×
355
        sequence->setBoundSceneID(scene->id());
×
356

357
        if (m_doc->addFunction(sequence) == true)
×
358
        {
359
            QTreeWidgetItem* item = m_tree->functionItem(f);
×
360
            Q_ASSERT(item != NULL);
×
361
            f->setName(QString("%1 %2").arg(tr("New Sequence")).arg(f->id()));
×
362
            m_tree->scrollToItem(item);
×
363
            m_tree->setCurrentItem(item);
×
364
        }
365
    }
366
}
×
367

368
void FunctionManager::slotAddCollection()
×
369
{
370
    Function* f = new Collection(m_doc);
×
371
    if (m_doc->addFunction(f) == true)
×
372
    {
373
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
374
        Q_ASSERT(item != NULL);
×
375
        f->setName(QString("%1 %2").arg(tr("New Collection")).arg(f->id()));
×
376
        m_tree->scrollToItem(item);
×
377
        m_tree->setCurrentItem(item);
×
378
    }
379
}
×
380

381
void FunctionManager::slotAddEFX()
×
382
{
383
    Function* f = new EFX(m_doc);
×
384
    if (m_doc->addFunction(f) == true)
×
385
    {
386
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
387
        Q_ASSERT(item != NULL);
×
388
        f->setName(QString("%1 %2").arg(tr("New EFX")).arg(f->id()));
×
389
        m_tree->scrollToItem(item);
×
390
        m_tree->setCurrentItem(item);
×
391
    }
392
}
×
393

394
void FunctionManager::slotAddRGBMatrix()
×
395
{
396
    Function* f = new RGBMatrix(m_doc);
×
397
    if (m_doc->addFunction(f) == true)
×
398
    {
399
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
400
        Q_ASSERT(item != NULL);
×
401
        f->setName(QString("%1 %2").arg(tr("New RGB Matrix")).arg(f->id()));
×
402
        m_tree->scrollToItem(item);
×
403
        m_tree->setCurrentItem(item);
×
404
    }
405
}
×
406

407
void FunctionManager::slotAddScript()
×
408
{
409
    Function* f = new Script(m_doc);
×
410
    if (m_doc->addFunction(f) == true)
×
411
    {
412
        QTreeWidgetItem* item = m_tree->functionItem(f);
×
413
        Q_ASSERT(item != NULL);
×
414
        f->setName(QString("%1 %2").arg(tr("New Script")).arg(f->id()));
×
415
        m_tree->scrollToItem(item);
×
416
        m_tree->setCurrentItem(item);
×
417
    }
418
}
×
419

420
void FunctionManager::slotAddAudio()
×
421
{
422
    /* Create a file open dialog */
423
    QFileDialog dialog(this);
×
424
    dialog.setWindowTitle(tr("Open Audio File"));
×
425
    dialog.setAcceptMode(QFileDialog::AcceptOpen);
×
426
    dialog.setFileMode(QFileDialog::ExistingFiles);
×
427

428
    /* Append file filters to the dialog */
429
    QStringList extList = m_doc->audioPluginCache()->getSupportedFormats();
×
430

431
    QStringList filters;
×
432
    qDebug() << Q_FUNC_INFO << "Extensions: " << extList.join(" ");
×
433
    filters << tr("Audio Files (%1)").arg(extList.join(" "));
×
434
#if defined(WIN32) || defined(Q_OS_WIN)
435
    filters << tr("All Files (*.*)");
436
#else
437
    filters << tr("All Files (*)");
×
438
#endif
439
    dialog.setNameFilters(filters);
×
440

441
    /* Append useful URLs to the dialog */
442
    QList <QUrl> sidebar;
×
443
    sidebar.append(QUrl::fromLocalFile(QDir::homePath()));
×
444
    sidebar.append(QUrl::fromLocalFile(QDir::rootPath()));
×
445
    dialog.setSidebarUrls(sidebar);
×
446

447
    /* Get file name */
448
    if (dialog.exec() != QDialog::Accepted)
×
449
        return;
×
450

451
    foreach (QString fn, dialog.selectedFiles())
×
452
    {
453
        Function* f = new Audio(m_doc);
×
454
        Audio *audio = qobject_cast<Audio*> (f);
×
455
        if (audio->setSourceFileName(fn) == false)
×
456
        {
457
            QMessageBox::warning(this, tr("Unsupported audio file"), tr("This audio file cannot be played with QLC+. Sorry."));
×
458
            return;
×
459
        }
460
        if (m_doc->addFunction(f) == true)
×
461
        {
462
            QTreeWidgetItem* item = m_tree->functionItem(f);
×
463
            Q_ASSERT(item != NULL);
×
464
            if (fn == dialog.selectedFiles().last())
×
465
            {
466
                m_tree->scrollToItem(item);
×
467
                m_tree->setCurrentItem(item);
×
468
            }
469
        }
470
    }
471
}
472

473
void FunctionManager::slotAddVideo()
×
474
{
475
    /* Create a file open dialog */
476
    QFileDialog dialog(this);
×
477
    dialog.setWindowTitle(tr("Open Video File"));
×
478
    dialog.setAcceptMode(QFileDialog::AcceptOpen);
×
479
    dialog.setFileMode(QFileDialog::ExistingFiles);
×
480

481
    /* Append file filters to the dialog */
482
    QStringList extList = Video::getVideoCapabilities();
×
483

484
    QStringList filters;
×
485
    qDebug() << Q_FUNC_INFO << "Extensions: " << extList.join(" ");
×
486
    filters << tr("Video Files (%1)").arg(extList.join(" "));
×
487
#if defined(WIN32) || defined(Q_OS_WIN)
488
    filters << tr("All Files (*.*)");
489
#else
490
    filters << tr("All Files (*)");
×
491
#endif
492
    dialog.setNameFilters(filters);
×
493

494
    /* Append useful URLs to the dialog */
495
    QList <QUrl> sidebar;
×
496
    sidebar.append(QUrl::fromLocalFile(QDir::homePath()));
×
497
    sidebar.append(QUrl::fromLocalFile(QDir::rootPath()));
×
498
    dialog.setSidebarUrls(sidebar);
×
499

500
    /* Get file name */
501
    if (dialog.exec() != QDialog::Accepted)
×
502
        return;
×
503

504
    foreach (QString fn, dialog.selectedFiles())
×
505
    {
506
        Function* f = new Video(m_doc);
×
507
        Video *video = qobject_cast<Video*> (f);
×
508
        if (video->setSourceUrl(fn) == false)
×
509
        {
510
            QMessageBox::warning(this, tr("Unsupported video file"), tr("This video file cannot be played with QLC+. Sorry."));
×
511
            return;
×
512
        }
513
        if (m_doc->addFunction(f) == true)
×
514
        {
515
            QTreeWidgetItem* item = m_tree->functionItem(f);
×
516
            Q_ASSERT(item != NULL);
×
517
            if (fn == dialog.selectedFiles().last())
×
518
            {
519
                m_tree->scrollToItem(item);
×
520
                m_tree->setCurrentItem(item);
×
521
            }
522
        }
523
    }
524
}
525

526
void FunctionManager::slotAddFolder()
×
527
{
528
    m_tree->addFolder();
×
529
    m_doc->setModified();
×
530
}
×
531

532
void FunctionManager::slotSelectAutostartFunction()
×
533
{
534
    FunctionSelection fs(this, m_doc);
×
535
    fs.setMultiSelection(false);
×
536
    fs.showNone(true);
×
537
    QList<quint32> currentStartupSelection;
×
538
    currentStartupSelection.append(m_doc->startupFunction());
×
539
    fs.setSelection(currentStartupSelection);
×
540

541
    if (fs.exec() == QDialog::Accepted && fs.selection().size() > 0)
×
542
    {
543
        quint32 startID = fs.selection().first();
×
544
        m_doc->setStartupFunction(startID);
×
545
        m_doc->setModified();
×
546
    }
547
}
×
548

549
void FunctionManager::slotWizard()
×
550
{
551
    FunctionWizard fw(this, m_doc);
×
552
    if (fw.exec() == QDialog::Accepted)
×
553
        m_tree->updateTree();
×
554
}
×
555

556
void FunctionManager::slotClone()
×
557
{
558
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
559
    while (it.hasNext() == true)
×
560
    {
561
        QTreeWidgetItem* item = it.next();
×
562
        quint32 fid = item->data(COL_NAME, Qt::UserRole).toUInt();
×
563
        if (fid == Function::invalidId())
×
564
            continue;
×
565
        copyFunction(m_tree->itemFunctionId(item));
×
566
    }
567
}
×
568

569
void FunctionManager::slotDelete()
×
570
{
571
    bool isFolder = false;
×
572
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
573
    if (it.hasNext() == false)
×
574
        return;
×
575

576
    QString msg;
×
577
    QTreeWidgetItem *firstItem = m_tree->selectedItems().first();
×
578

579
    if (firstItem->childCount() > 0 || firstItem->text(COL_PATH).isEmpty() == false)
×
580
        isFolder = true;
×
581

582
    if (isFolder == true)
×
583
        msg = tr("Do you want to DELETE folder:") + QString("\n");
×
584
    else
585
        msg = tr("Do you want to DELETE functions:") + QString("\n");
×
586

587
    // Append functions' names to the message
588
    while (it.hasNext() == true)
×
589
    {
590
        QTreeWidgetItem *item = it.next();
×
591
        msg.append(item->text(COL_NAME));
×
592
        if (it.hasNext())
×
593
            msg.append(", ");
×
594

595
        if (item->childCount() > 0)
×
596
        {
597
            msg.append("\n" + tr("(This will also DELETE: "));
×
NEW
598
            for (int i = 0; i < item->childCount(); i++)
×
599
            {
600
                QTreeWidgetItem *child = item->child(i);
×
601
                if (i > 0) msg.append(", ");
×
602
                msg.append(child->text(COL_NAME));
×
603
            }
604
            msg.append(")");
×
605
        }
606
    }
607

608
    // Ask for user's confirmation
609
    if (QMessageBox::question(this, tr("Delete Functions"), msg,
×
610
                              QMessageBox::Yes, QMessageBox::No)
611
            == QMessageBox::Yes)
×
612
    {
613
        if (isFolder)
×
614
        {
615
            m_tree->deleteFolder(m_tree->selectedItems().first());
×
616
            m_doc->setModified();
×
617
        }
618
        else
619
            deleteSelectedFunctions();
×
620
        updateActionStatus();
×
621
        deleteCurrentEditor();
×
622
    }
623
}
624

625
void FunctionManager::slotSelectAll()
×
626
{
627
    /* This has to be done thru an intermediary slot because the tree
628
       widget hasn't been created when actions are being created and
629
       so a direct slot collection to m_tree is not possible. */
630
    m_tree->selectAll();
×
631
}
×
632

633
void FunctionManager::updateActionStatus()
×
634
{
635
    bool validSelection = false;
×
636
    m_cloneAction->setEnabled(false);
×
637

638
    if (m_tree->selectedItems().isEmpty() == false)
×
639
    {
640
        QTreeWidgetItem *firstItem = m_tree->selectedItems().first();
×
641
        quint32 fid = m_tree->itemFunctionId(firstItem);
×
642
        if (fid != Function::invalidId())
×
643
        {
644
            m_cloneAction->setEnabled(true);
×
645
            validSelection = true;
×
646
        }
647

648
        // check if this is a folder
649
        if (m_tree->selectedItems().count() == 1 && m_tree->indexOfTopLevelItem(firstItem) < 0)
×
650
            validSelection = true;
×
651

652
        m_addFolderAction->setEnabled(true);
×
653
    }
654
    else
655
        m_addFolderAction->setEnabled(false);
×
656

657
    if (validSelection == true)
×
658
    {
659
        /* At least one function has been selected, so
660
           editing is possible. */
661
        m_selectAllAction->setEnabled(true);
×
662
        if (m_doc->mode() == Doc::Operate)
×
663
            m_deleteAction->setEnabled(false);
×
664
        else
665
            m_deleteAction->setEnabled(true);
×
666
    }
667
    else
668
    {
669
        /* No functions selected */
670
        m_selectAllAction->setEnabled(false);
×
671
        m_deleteAction->setEnabled(false);
×
672
    }
673
}
×
674

675
/****************************************************************************
676
 * Function tree
677
 ****************************************************************************/
678

679
void FunctionManager::initSplitterView()
×
680
{
681
    m_vsplitter = new QSplitter(Qt::Vertical, this);
×
682
    layout()->addWidget(m_vsplitter);
×
683
    // add container for tree view + right editor
684
    QWidget* gcontainer = new QWidget(this);
×
685
    m_vsplitter->addWidget(gcontainer);
×
686
    gcontainer->setLayout(new QVBoxLayout);
×
687
    gcontainer->layout()->setContentsMargins(0, 0, 0, 0);
×
688

689
    // add container for scene editor
690
    QWidget* scontainer = new QWidget(this);
×
691
    m_vsplitter->addWidget(scontainer);
×
692
    scontainer->setLayout(new QVBoxLayout);
×
693
    scontainer->layout()->setContentsMargins(0, 0, 0, 0);
×
694
    scontainer->hide();
×
695

696
    m_hsplitter = new QSplitter(Qt::Horizontal, this);
×
697
    //layout()->addWidget(m_hsplitter);
698
    m_vsplitter->widget(0)->layout()->addWidget(m_hsplitter);
×
699
    initTree();
×
700

701
    QWidget* container = new QWidget(this);
×
702
    m_hsplitter->addWidget(container);
×
703
    container->setLayout(new QVBoxLayout);
×
704
    container->layout()->setContentsMargins(0, 0, 0, 0);
×
705
    container->hide();
×
706
}
×
707

708
void FunctionManager::initTree()
×
709
{
710
    m_tree = new FunctionsTreeWidget(m_doc, this);
×
711
    Q_ASSERT(m_hsplitter != NULL);
×
712
    m_hsplitter->addWidget(m_tree);
×
713

714
    QStringList labels;
×
715
    labels << tr("Function"); // << "Path";
×
716
    m_tree->setHeaderLabels(labels);
×
717
    m_tree->setRootIsDecorated(true);
×
718
    m_tree->setAllColumnsShowFocus(true);
×
719
    m_tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
×
720
    m_tree->setContextMenuPolicy(Qt::CustomContextMenu);
×
721
    m_tree->setSortingEnabled(true);
×
722
    m_tree->sortByColumn(COL_NAME, Qt::AscendingOrder);
×
723
    m_tree->setDragEnabled(true);
×
724
    m_tree->setAcceptDrops(true);
×
725
    m_tree->setDragDropMode(QAbstractItemView::InternalMove);
×
726

727
    // Catch selection changes
728
    connect(m_tree, SIGNAL(itemSelectionChanged()),
×
729
            this, SLOT(slotTreeSelectionChanged()));
730

731
    // Catch right-mouse clicks
732
    connect(m_tree, SIGNAL(customContextMenuRequested(const QPoint&)),
×
733
            this, SLOT(slotTreeContextMenuRequested()));
734
}
×
735

736
void FunctionManager::selectFunction(quint32 id)
×
737
{
738
    Function* function = m_doc->function(id);
×
739
    if (function == NULL)
×
740
        return;
×
741
    QTreeWidgetItem* item = m_tree->functionItem(function);
×
742
    if (item != NULL)
×
743
        m_tree->setCurrentItem(item);
×
744
}
745

746
void FunctionManager::deleteSelectedFunctions()
×
747
{
748
    QListIterator <QTreeWidgetItem*> it(m_tree->selectedItems());
×
749
    while (it.hasNext() == true)
×
750
    {
751
        QTreeWidgetItem* item(it.next());
×
752
        quint32 fid = m_tree->itemFunctionId(item);
×
753
        Function *func = m_doc->function(fid);
×
754
        if (func == NULL)
×
755
            continue;
×
756

757
        // Stop running tests before deleting function
758
        if (m_editor != NULL)
×
759
        {
760
            if (func->type() == Function::RGBMatrixType)
×
761
                static_cast<RGBMatrixEditor*>(m_editor)->stopTest();
×
762
            else if (func->type() == Function::EFXType)
×
763
                static_cast<EFXEditor*>(m_editor)->stopTest();
×
764
            else if (func->type() == Function::ChaserType || func->type() == Function::SequenceType)
×
765
                static_cast<ChaserEditor*>(m_editor)->stopTest();
×
766
        }
767

768
        /* When deleting a Sequence, check if the bound Scene ID is still used
769
         * in the Doc. If not, get rid of it cause otherwise it would stay in the project
770
         * forever since bound Scenes are hidden and users cannot delete them */
771
        if (func->type() == Function::SequenceType)
×
772
        {
773
            Sequence *seq = qobject_cast<Sequence *>(func);
×
774
            quint32 boundSceneID = seq->boundSceneID();
×
775
            m_doc->deleteFunction(fid);
×
776

777
            if (m_doc->getUsage(boundSceneID).count() == 0)
×
778
                m_doc->deleteFunction(boundSceneID);
×
779
        }
780
        else
781
        {
782
            m_doc->deleteFunction(fid);
×
783
        }
784

785
        QTreeWidgetItem* parent = item->parent();
×
786
        delete item;
×
787
        if (parent != NULL && parent->childCount() == 0)
×
788
        {
789
            if (m_tree->indexOfTopLevelItem(parent) >= 0)
×
790
                m_tree->deleteFolder(parent);
×
791
        }
792
    }
793
}
×
794

795
void FunctionManager::slotTreeSelectionChanged()
×
796
{
797
    updateActionStatus();
×
798

799
    QList <QTreeWidgetItem*> selection(m_tree->selectedItems());
×
800
    if (selection.size() == 1)
×
801
    {
802
        Function* function = m_doc->function(m_tree->itemFunctionId(selection.first()));
×
803
        editFunction(function);
×
804
    }
805
    else
806
    {
807
        editFunction(NULL);
×
808
    }
809
}
×
810

811
void FunctionManager::slotTreeContextMenuRequested()
×
812
{
813
    QMenu menu(this);
×
814
    menu.addAction(m_cloneAction);
×
815
    menu.addAction(m_selectAllAction);
×
816
    menu.addSeparator();
×
817
    menu.addAction(m_deleteAction);
×
818
    menu.addSeparator();
×
819
    menu.addAction(m_addSceneAction);
×
820
    menu.addAction(m_addChaserAction);
×
821
    menu.addAction(m_addEFXAction);
×
822
    menu.addAction(m_addCollectionAction);
×
823
    menu.addAction(m_addRGBMatrixAction);
×
824
    menu.addAction(m_addScriptAction);
×
825
    menu.addAction(m_addAudioAction);
×
826
    menu.addAction(m_addVideoAction);
×
827
    menu.addSeparator();
×
828
    menu.addAction(m_addFolderAction);
×
829
    menu.addSeparator();
×
830
    menu.addAction(m_wizardAction);
×
831

832
    updateActionStatus();
×
833

834
    menu.exec(QCursor::pos());
×
835
}
×
836

837
/*****************************************************************************
838
 * Helpers
839
 *****************************************************************************/
840

841
void FunctionManager::copyFunction(quint32 fid)
×
842
{
843
    Function* function = m_doc->function(fid);
×
844
    Q_ASSERT(function != NULL);
×
845

846
    /* Attempt to create a copy of the function to Doc */
847
    Function* copy = function->createCopy(m_doc);
×
848
    if (copy != NULL)
×
849
    {
850
        copy->setName(copy->name() + tr(" (Copy)"));
×
851

852
        /* If the cloned Function is a Sequence,
853
         * clone the bound Scene too */
854
        if (function->type() == Function::SequenceType)
×
855
        {
856
            Sequence *sequence = qobject_cast<Sequence *>(copy);
×
857
            quint32 sceneID = sequence->boundSceneID();
×
858
            Function *scene = m_doc->function(sceneID);
×
859
            if (scene != NULL)
×
860
            {
861
                Function *sceneCopy = scene->createCopy(m_doc);
×
862
                if (sceneCopy != NULL)
×
863
                    sequence->setBoundSceneID(sceneCopy->id());
×
864
            }
865
        }
866

867
        QTreeWidgetItem* item = m_tree->functionItem(copy);
×
868
        m_tree->setCurrentItem(item);
×
869
    }
870
}
×
871

872
void FunctionManager::editFunction(Function* function)
×
873
{
874
    deleteCurrentEditor();
×
875

876
    if (function == NULL)
×
877
        return;
×
878

879
    // Choose the editor by the selected function's type
880
    if (function->type() == Function::SceneType)
×
881
    {
882
        m_scene_editor = new SceneEditor(m_vsplitter->widget(1), qobject_cast<Scene*> (function), m_doc, true);
×
883
        connect(this, SIGNAL(functionManagerActive(bool)),
×
884
                m_scene_editor, SLOT(slotFunctionManagerActive(bool)));
×
885
    }
886
    else if (function->type() == Function::ChaserType)
×
887
    {
888
        Chaser *chaser = qobject_cast<Chaser*> (function);
×
889
        m_editor = new ChaserEditor(m_hsplitter->widget(1), chaser, m_doc);
×
890
        connect(this, SIGNAL(functionManagerActive(bool)),
×
891
                m_editor, SLOT(slotFunctionManagerActive(bool)));
×
892
    }
893
    else if (function->type() == Function::SequenceType)
×
894
    {
895
        Sequence *sequence = qobject_cast<Sequence*> (function);
×
896
        Function *sfunc = m_doc->function(sequence->boundSceneID());
×
897

898
        if (sfunc == NULL)
×
899
        {
900
            // The bound Scene no longer exists. Invalidate the Sequence
901
            sequence->setBoundSceneID(Function::invalidId());
×
902
        }
903
        else
904
        {
905
            m_editor = new ChaserEditor(m_hsplitter->widget(1), sequence, m_doc);
×
906
            connect(this, SIGNAL(functionManagerActive(bool)),
×
907
                    m_editor, SLOT(slotFunctionManagerActive(bool)));
×
908

909
            if (sfunc->type() == Function::SceneType)
×
910
            {
911
                m_scene_editor = new SceneEditor(m_vsplitter->widget(1), qobject_cast<Scene*> (sfunc), m_doc, false);
×
912
                connect(this, SIGNAL(functionManagerActive(bool)),
×
913
                        m_scene_editor, SLOT(slotFunctionManagerActive(bool)));
×
914
                /** Signal from chaser editor to scene editor. When a step is clicked apply values immediately */
915
                connect(m_editor, SIGNAL(applyValues(QList<SceneValue>&)),
×
916
                        m_scene_editor, SLOT(slotSetSceneValues(QList <SceneValue>&)));
×
917
                /** Signal from scene editor to chaser editor. When a fixture value is changed, update the selected chaser step */
918
                connect(m_scene_editor, SIGNAL(fixtureValueChanged(SceneValue, bool)),
×
919
                        m_editor, SLOT(slotUpdateCurrentStep(SceneValue, bool)));
×
920
            }
921
        }
922
    }
923
    else if (function->type() == Function::CollectionType)
×
924
    {
925
        m_editor = new CollectionEditor(m_hsplitter->widget(1), qobject_cast<Collection*> (function), m_doc);
×
926
    }
927
    else if (function->type() == Function::EFXType)
×
928
    {
929
        m_editor = new EFXEditor(m_hsplitter->widget(1), qobject_cast<EFX*> (function), m_doc);
×
930
        connect(this, SIGNAL(functionManagerActive(bool)),
×
931
                m_editor, SLOT(slotFunctionManagerActive(bool)));
×
932
    }
933
    else if (function->type() == Function::RGBMatrixType)
×
934
    {
935
        m_editor = new RGBMatrixEditor(m_hsplitter->widget(1), qobject_cast<RGBMatrix*> (function), m_doc);
×
936
        connect(this, SIGNAL(functionManagerActive(bool)),
×
937
                m_editor, SLOT(slotFunctionManagerActive(bool)));
×
938
    }
939
    else if (function->type() == Function::ScriptType)
×
940
    {
941
        m_editor = new ScriptEditor(m_hsplitter->widget(1), qobject_cast<Script*> (function), m_doc);
×
942
    }
943
    else if (function->type() == Function::ShowType)
×
944
    {
945
        m_editor = new ShowEditor(m_hsplitter->widget(1), qobject_cast<Show*> (function), m_doc);
×
946
    }
947
    else if (function->type() == Function::AudioType)
×
948
    {
949
        m_editor = new AudioEditor(m_hsplitter->widget(1), qobject_cast<Audio*> (function), m_doc);
×
950
    }
951
    else if (function->type() == Function::VideoType)
×
952
    {
953
        m_editor = new VideoEditor(m_hsplitter->widget(1), qobject_cast<Video*> (function), m_doc);
×
954
    }
955
    else
956
    {
957
        m_editor = NULL;
×
958
        m_scene_editor = NULL;
×
959
    }
960

961
    // Show the editor
962
    if (m_editor != NULL)
×
963
    {
964
        m_hsplitter->widget(1)->show();
×
965
        m_hsplitter->widget(1)->layout()->addWidget(m_editor);
×
966
        m_editor->show();
×
967
    }
968
    if (m_scene_editor != NULL)
×
969
    {
970
        m_vsplitter->widget(1)->show();
×
971
        m_vsplitter->widget(1)->layout()->addWidget(m_scene_editor);
×
972
        m_scene_editor->show();
×
973
    }
974
}
975

976
void FunctionManager::deleteCurrentEditor(bool async)
×
977
{
978
    if (async)
×
979
    {
980
        if (m_editor) m_editor->deleteLater();
×
981
        if (m_scene_editor) m_scene_editor->deleteLater();
×
982
    }
983
    else
984
    {
985
        delete m_editor;
×
986
        delete m_scene_editor;
×
987
    }
988

989
    m_editor = NULL;
×
990
    m_scene_editor = NULL;
×
991

992
    m_hsplitter->widget(1)->hide();
×
993
    m_vsplitter->widget(1)->hide();
×
994
}
×
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