Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
signalslotdialog.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5#include "ui_signalslotdialog.h"
8
10#include "iconloader_p.h"
11
12#include <QtDesigner/membersheet.h>
13#include <QtDesigner/qextensionmanager.h>
14#include <QtDesigner/abstractformeditor.h>
15#include <QtDesigner/abstractformwindow.h>
16#include <QtDesigner/abstractwidgetfactory.h>
17#include <abstractdialoggui_p.h>
18
19#include <QtGui/qstandarditemmodel.h>
20#include <QtGui/qvalidator.h>
21#include <QtWidgets/qitemdelegate.h>
22#include <QtWidgets/qlineedit.h>
23#include <QtWidgets/qapplication.h>
24#include <QtWidgets/qmessagebox.h>
25
26#include <QtCore/qregularexpression.h>
27#include <QtCore/qdebug.h>
28
30
31using namespace Qt::StringLiterals;
32
33// Regexp to match a function signature, arguments potentially
34// with namespace colons.
35static constexpr auto signatureRegExp = "^[\\w+_]+\\‍(([\\w+:]\\*?,?)*\\‍)$"_L1;
36static constexpr auto methodNameRegExp = "^[\\w+_]+$"_L1;
37
38static QStandardItem *createEditableItem(const QString &text)
39{
40 QStandardItem *rc = new QStandardItem(text);
41 rc->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable);
42 return rc;
43}
44
45static QStandardItem *createDisabledItem(const QString &text)
46{
47 QStandardItem *rc = new QStandardItem(text);
48 Qt::ItemFlags flags = rc->flags();
49 rc->setFlags(flags & ~(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable));
50 return rc;
51}
52
53namespace {
54 // Internal helper class: A Delegate that validates using RegExps and additionally checks
55 // on closing (adds missing parentheses).
56 class SignatureDelegate : public QItemDelegate {
57 public:
58 SignatureDelegate(QObject * parent = nullptr);
59 QWidget * createEditor (QWidget * parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const override;
60 void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override;
61
62 private:
63 const QRegularExpression m_signatureRegexp;
64 const QRegularExpression m_methodNameRegexp;
65 };
66
67 SignatureDelegate::SignatureDelegate(QObject * parent) :
68 QItemDelegate(parent),
69 m_signatureRegexp(signatureRegExp),
70 m_methodNameRegexp(methodNameRegExp)
71 {
72 Q_ASSERT(m_signatureRegexp.isValid());
73 Q_ASSERT(m_methodNameRegexp.isValid());
74 }
75
76 QWidget * SignatureDelegate::createEditor ( QWidget * parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
77 {
78 QWidget *rc = QItemDelegate::createEditor(parent, option, index);
79 QLineEdit *le = qobject_cast<QLineEdit *>(rc);
80 Q_ASSERT(le);
81 le->setValidator(new QRegularExpressionValidator(m_signatureRegexp, le));
82 return rc;
83 }
84
85 void SignatureDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
86 {
87 QLineEdit *le = qobject_cast<QLineEdit *>(editor);
88 Q_ASSERT(le);
89 // Did the user just type a name? .. Add parentheses
90 QString signature = le->text();
91 if (!m_signatureRegexp.match(signature).hasMatch()) {
92 if (m_methodNameRegexp.match(signature).hasMatch()) {
93 signature += "()"_L1;
94 le->setText(signature);
95 } else {
96 return;
97 }
98 }
99 QItemDelegate::setModelData(editor, model, index);
100 }
101
102 // ------ FakeMethodMetaDBCommand: Undo Command to change fake methods in the meta DB.
103 class FakeMethodMetaDBCommand : public qdesigner_internal::QDesignerFormWindowCommand {
104
105 public:
106 explicit FakeMethodMetaDBCommand(QDesignerFormWindowInterface *formWindow);
107
108 void init(QObject *o,
109 const QStringList &oldFakeSlots, const QStringList &oldFakeSignals,
110 const QStringList &newFakeSlots, const QStringList &newFakeSignals);
111
112 void undo() override
113 {
114 qdesigner_internal::SignalSlotDialog::fakeMethodsToMetaDataBase(core(), m_object,
115 m_oldFakeSlots, m_oldFakeSignals);
116 }
117 void redo() override
118 {
119 qdesigner_internal::SignalSlotDialog::fakeMethodsToMetaDataBase(core(), m_object,
120 m_newFakeSlots, m_newFakeSignals);
121 }
122
123 private:
124 QObject *m_object;
125 QStringList m_oldFakeSlots;
126 QStringList m_oldFakeSignals;
127 QStringList m_newFakeSlots;
128 QStringList m_newFakeSignals;
129 };
130
131 FakeMethodMetaDBCommand::FakeMethodMetaDBCommand(QDesignerFormWindowInterface *formWindow) :
132 qdesigner_internal::QDesignerFormWindowCommand(QApplication::translate("Command", "Change signals/slots"), formWindow),
133 m_object(nullptr)
134 {
135 }
136
137 void FakeMethodMetaDBCommand::init(QObject *o,
138 const QStringList &oldFakeSlots, const QStringList &oldFakeSignals,
139 const QStringList &newFakeSlots, const QStringList &newFakeSignals)
140 {
141 m_object = o;
142 m_oldFakeSlots = oldFakeSlots;
143 m_oldFakeSignals = oldFakeSignals;
144 m_newFakeSlots = newFakeSlots;
145 m_newFakeSignals = newFakeSignals;
146 }
147}
148
149namespace qdesigner_internal {
150
151// ------ SignalSlotDialogData
153{
154 m_existingMethods.clear();
155 m_fakeMethods.clear();
156}
157
158// ------ SignatureModel
159SignatureModel::SignatureModel(QObject *parent) :
160 QStandardItemModel(parent)
161{
162}
163
164bool SignatureModel::setData(const QModelIndex &index, const QVariant &value, int role)
165{
166 if (role != Qt::EditRole)
167 return QStandardItemModel::setData(index, value, role);
168 // check via signal (unless it is the same), in which case we can't be bothered.
169 const QStandardItem *item = itemFromIndex(index);
170 Q_ASSERT(item);
171 const QString signature = value.toString();
172 if (item->text() == signature)
173 return true;
174
175 bool ok = true;
176 emit checkSignature(signature, &ok);
177 if (!ok)
178 return false;
179
180 return QStandardItemModel::setData(index, value, role);
181}
182
183// ------ SignaturePanel
184SignaturePanel::SignaturePanel(QObject *parent, QListView *listView, QToolButton *addButton, QToolButton *removeButton, const QString &newPrefix) :
185 QObject(parent),
186 m_newPrefix(newPrefix),
187 m_model(new SignatureModel(this)),
188 m_listView(listView),
189 m_removeButton(removeButton)
190{
191 m_removeButton->setEnabled(false);
192
193 connect(addButton, &QAbstractButton::clicked, this, &SignaturePanel::slotAdd);
194 connect(m_removeButton, &QAbstractButton::clicked, this, &SignaturePanel::slotRemove);
195
196 m_listView->setModel(m_model);
197 SignatureDelegate *delegate = new SignatureDelegate(this);
198 m_listView->setItemDelegate(delegate);
199 connect(m_model, &SignatureModel::checkSignature,
200 this, &SignaturePanel::checkSignature);
201 connect(m_listView->selectionModel(), &QItemSelectionModel::selectionChanged,
202 this, &SignaturePanel::slotSelectionChanged);
203}
204
205void SignaturePanel::slotAdd()
206{
207 m_listView->selectionModel()->clearSelection();
208 // find unique name
209 for (int i = 1; ; i++) {
210 // Always add number, Avoid setting 'slot' for first entry
211 QString newSlot = m_newPrefix + QString::number(i) + u'(';
212 // check for function name independent of parameters
213 if (m_model->findItems(newSlot, Qt::MatchStartsWith, 0).isEmpty()) {
214 newSlot += u')';
215 QStandardItem * item = createEditableItem(newSlot);
216 m_model->appendRow(item);
217 const QModelIndex index = m_model->indexFromItem (item);
218 m_listView->setCurrentIndex (index);
219 m_listView->edit(index);
220 return;
221 }
222 }
223}
224
225int SignaturePanel::count(const QString &signature) const
226{
227 return m_model->findItems(signature).size();
228}
229
230void SignaturePanel::slotRemove()
231{
232 const QModelIndexList selectedIndexes = m_listView->selectionModel()->selectedIndexes ();
233 if (selectedIndexes.isEmpty())
234 return;
235
236 closeEditor();
237 // scroll to previous
238 if (const int row = selectedIndexes.constFirst().row())
239 m_listView->setCurrentIndex (selectedIndexes.constFirst().sibling(row - 1, 0));
240
241 for (auto i = selectedIndexes.size() - 1; i >= 0; --i)
242 qDeleteAll(m_model->takeRow(selectedIndexes.at(i).row()));
243}
244
245void SignaturePanel::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &)
246{
247 m_removeButton->setEnabled(!selected.indexes().isEmpty());
248}
249
251{
252 m_model->clear();
253
254 QStandardItem *lastExisting = nullptr;
255 for (const QString &s : d.m_existingMethods) {
256 lastExisting = createDisabledItem(s);
257 m_model->appendRow(lastExisting);
258 }
259 for (const QString &s : d.m_fakeMethods)
260 m_model->appendRow(createEditableItem(s));
261 if (lastExisting)
262 m_listView->scrollTo(m_model->indexFromItem(lastExisting));
263}
264
266{
267 QStringList rc;
268 if (const int rowCount = m_model->rowCount())
269 for (int i = 0; i < rowCount; i++) {
270 const QStandardItem *item = m_model->item(i);
271 if (item->flags() & Qt::ItemIsEditable)
272 rc += item->text();
273 }
274 return rc;
275}
276
277void SignaturePanel::closeEditor()
278{
279 const QModelIndex idx = m_listView->currentIndex();
280 if (idx.isValid())
281 m_listView->closePersistentEditor(idx);
282}
283
284// ------ SignalSlotDialog
285
291{
292 setModal(true);
293 m_ui->setupUi(this);
294
295 const QIcon plusIcon = qdesigner_internal::createIconSet("plus.png"_L1);
296 const QIcon minusIcon = qdesigner_internal::createIconSet("minus.png"_L1);
301
303 m_ui->removeSlotButton, u"slot"_s);
305 m_ui->removeSignalButton, u"signal"_s);
310
313
314 switch(m_focusMode) {
315 case FocusSlots:
317 break;
318 case FocusSignals:
320 break;
321 }
322}
323
325{
326 delete m_ui;
327}
328
330{
332 do {
334 errorMessage = tr("There is already a slot with the signature '%1'.").arg(signature);
335 *ok = false;
336 break;
337 }
339 errorMessage = tr("There is already a signal with the signature '%1'.").arg(signature);
340 *ok = false;
341 break;
342 }
343 } while (false);
344 if (!*ok)
346 QMessageBox::Warning, tr("%1 - Duplicate Signature").arg(windowTitle()), errorMessage, QMessageBox::Close);
347}
348
362
389
391{
393 if (index == -1)
394 return false;
395
398 return false;
399
401 if (!widget)
402 return false;
405 return rc;
406}
407
418
419
421{
423 if (!db)
424 return false;
425
427 if (index == -1)
428 return false;
429
431
434
438
441
443 dlg.setWindowTitle(tr("Signals/Slots of %1").arg(promotedClassName));
444
446 return false;
447
449 return false;
450
453
454 return true;
455}
456
469
481
501
502}
503
504QT_END_NAMESPACE
505
506#include "moc_signalslotdialog_p.cpp"
friend class QWidget
Definition qpainter.h:421
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
\reimp
void setData(const SignalSlotDialogData &d)
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
static QStandardItem * createDisabledItem(const QString &text)
static constexpr auto methodNameRegExp
static constexpr auto signatureRegExp
static QStandardItem * createEditableItem(const QString &text)