1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #define RG_MODULE_STRING "[NameSetEditor]"
19 
20 #include "NameSetEditor.h"
21 
22 #include "BankEditorDialog.h"
23 #include "misc/Debug.h"
24 #include "gui/widgets/LineEdit.h"
25 
26 #include <QFrame>
27 #include <QGroupBox>
28 #include <QLabel>
29 #include <QPushButton>
30 #include <QString>
31 #include <QTabWidget>
32 #include <QWidget>
33 #include <QCompleter>
34 #include <QVBoxLayout>
35 #include <QHBoxLayout>
36 #include <QToolButton>
37 #include <QScrollArea>
38 
39 namespace Rosegarden
40 {
41 
42 
43 NameSetEditor::NameSetEditor(BankEditorDialog *bankEditor,
44                              QString title,
45                              QWidget *parent,
46                              bool showKeyMapButtons) :
47     QGroupBox(title, parent),
48     m_bankEditor(bankEditor),
49     m_topFrame(new QFrame(this)),
50     m_topLayout(new QGridLayout(m_topFrame)),
51     m_librarian(nullptr),
52     m_librarianEmail(nullptr),
53     m_names(),
54     m_completions(),
55     m_numberingBaseButton(nullptr),
56     m_numberingBase(1),
57     m_labels(),
58     m_keyMapButtons()
59 {
60     QVBoxLayout *mainLayout = new QVBoxLayout;
61     mainLayout->setContentsMargins(6, 2, 6, 6);
62 
63     // Area above the tabbed widget.
64 
65     m_topFrame->setContentsMargins(0, 0, 0, 5);
66     m_topLayout->setSpacing(0);
67     m_topLayout->setContentsMargins(0, 0, 0, 0);
68     m_topFrame->setLayout(m_topLayout);
69     mainLayout->addWidget(m_topFrame);
70 
71     // "Provided by" groupbox
72 
73     QGroupBox *groupBox = new QGroupBox(tr("Provided by"), m_topFrame);
74     QGridLayout *groupBoxLayout = new QGridLayout;
75 
76     m_topLayout->addWidget(groupBox, 0, 3, 3, 3);
77 
78     // Librarian
79     // ??? Would be nice if we could edit this.
80     m_librarian = new QLabel(groupBox);
81     groupBoxLayout->addWidget(m_librarian, 0, 1);
82 
83     // Librarian email
84     // ??? Would be nice if we could edit this.
85     m_librarianEmail = new QLabel(groupBox);
86     groupBoxLayout->addWidget(m_librarianEmail, 1, 1);
87 
88     groupBox->setLayout(groupBoxLayout);
89 
90     // QScrollArea
91 
92     QScrollArea *scrollArea = new QScrollArea(this);
93     // Make sure widget is expanded to fill the scroll area.
94     scrollArea->setWidgetResizable(true);
95 
96     mainLayout->addWidget(scrollArea);
97 
98     setLayout(mainLayout);
99 
100     // Widget and layout to hold each of the rows.
101     QWidget *listWidget = new QWidget;
102     QVBoxLayout *listLayout = new QVBoxLayout;
103     listLayout->setSpacing(2);
104 
105     unsigned index = 0;
106 
107     // For each row
108     for (unsigned int row = 0; row < 128; ++row) {
109         // Widget and layout to hold the row.  A row consists of the
110         // number label, optional keymap button, and name line edit.
111         QWidget *rowWidget = new QWidget;
112         QHBoxLayout *rowLayout = new QHBoxLayout;
113         // take out the excess vertical space that was making this
114         // dialog two screens tall
115         rowLayout->setContentsMargins(0, 0, 0, 0);
116 
117         // If this is the very first number label, make it a button.
118         if (index == 0) {
119             m_numberingBaseButton = new QPushButton("", rowWidget);
120             m_numberingBaseButton->setFixedWidth(25);
121             connect(m_numberingBaseButton,
122                     &QAbstractButton::clicked,
123                     this, &NameSetEditor::slotToggleNumberingBase);
124 
125             rowLayout->addWidget(m_numberingBaseButton);
126 
127         } else {  // All other numbers are QLabels.
128             QLabel *label = new QLabel("", rowWidget);
129             label->setFixedWidth(30);
130             label->setAlignment(Qt::AlignCenter);
131             m_labels.push_back(label);
132 
133             rowLayout->addWidget(label);
134         }
135 
136         if (showKeyMapButtons) {
137             QToolButton *button = new QToolButton;
138             // Object name is required or else serious data loss occurs.
139             // ??? Actually, this seems to work fine without this.  Leaving
140             //     it here for safety.
141             button->setObjectName(QString("Key Map Button %1").arg(index));
142             button->setProperty("index", index);
143             connect(button, &QAbstractButton::clicked,
144                     this, &NameSetEditor::slotKeyMapButtonPressed);
145             m_keyMapButtons.push_back(button);
146 
147             rowLayout->addWidget(button);
148         }
149 
150         // Note: ThornStyle::sizeFromContents() reduces the size
151         //       of these so they will fit on smaller displays.
152         LineEdit *lineEdit = new LineEdit("", rowWidget);
153         // A unique object name is required for each widget or else serious
154         // data loss occurs when switching between nodes on the tree.  Not
155         // sure why.
156         lineEdit->setObjectName(QString("Line Edit %1").arg(index));
157         lineEdit->setProperty("index", index);
158         lineEdit->setCompleter(new QCompleter(m_completions));
159 
160         m_names.push_back(lineEdit);
161         connect(m_names[index],
162                 &QLineEdit::textChanged,
163                 this, &NameSetEditor::slotNameChanged);
164 
165         rowLayout->addWidget(lineEdit, 1);
166 
167         rowWidget->setLayout(rowLayout);
168 
169         listLayout->addWidget(rowWidget);
170 
171         ++index;
172     }
173 
174     listWidget->setLayout(listLayout);
175 
176     scrollArea->setWidget(listWidget);
177 
178     m_numberingBaseButton->setMaximumSize(m_labels.front()->size());
179 
180     updateLabels();
181 }
182 
183 void
184 NameSetEditor::slotToggleNumberingBase()
185 {
186     m_numberingBase ^= 1;
187     updateLabels();
188 }
189 
190 void
191 NameSetEditor::updateLabels()
192 {
193     unsigned index = m_numberingBase;
194 
195     m_numberingBaseButton->setText(QString("%1").arg(index++));
196 
197     // For each subsequent label.
198     for (size_t i = 0; i < m_labels.size(); ++i) {
199         m_labels[i]->setText(QString("%1").arg(index++));
200     }
201 }
202 
203 
204 }
205