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