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
selectsignaldialog.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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
7#include "ui_selectsignaldialog.h"
8
9#include <QtDesigner/abstractformeditor.h>
10#include <QtDesigner/abstractpromotioninterface.h>
11
13#include "metadatabase_p.h"
15
16#include <QtWidgets/qapplication.h>
17#include <QtWidgets/qpushbutton.h>
18
19#include <QtGui/qscreen.h>
20#include <QtGui/qstandarditemmodel.h>
21
22#include <QtCore/qitemselectionmodel.h>
23#include <QtCore/qlist.h>
24#include <QtCore/qvariant.h>
25
26#include <algorithm>
27
28QT_BEGIN_NAMESPACE
29
30namespace qdesigner_internal {
31
32enum { MethodRole = Qt::UserRole + 1 };
33
35
36SelectSignalDialog::SelectSignalDialog(QWidget *parent)
37 : QDialog(parent)
38 , m_ui(new QT_PREPEND_NAMESPACE(Ui)::SelectSignalDialog)
39 , m_model(new QStandardItemModel(0, 1, this))
40{
41 m_ui->setupUi(this);
42 m_okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok);
43
44 m_ui->signalList->setModel(m_model);
45 connect(m_ui->signalList->selectionModel(), &QItemSelectionModel::currentChanged,
46 this, &SelectSignalDialog::currentChanged);
47 connect(m_ui->signalList, &QTreeView::activated,
48 this, &SelectSignalDialog::activated);
49 const QRect availableGeometry = screen()->geometry();
50 resize(availableGeometry.width() / 5, availableGeometry.height() / 2);
51}
52
54{
55 delete m_ui;
56}
57
59{
60 return methodFromIndex(m_ui->signalList->currentIndex());
61}
62
63SelectSignalDialog::Method SelectSignalDialog::methodFromIndex(const QModelIndex &index) const
64{
65 if (index.isValid()) {
66 const QStandardItem *item = m_model->itemFromIndex(index);
67 const QVariant data = item->data(MethodRole);
68 if (data.canConvert<Method>())
69 return data.value<Method>();
70 }
71 return Method();
72}
73
74static QStandardItem *createTopLevelItem(const QString &text)
75{
76 QStandardItem *result = new QStandardItem(text);
77 result->setFlags(Qt::ItemIsEnabled);
78 return result;
79}
80
81static bool signatureLessThan(const SelectSignalDialog::Method &m1, const SelectSignalDialog::Method &m2)
82{
83 return m1.signature.compare(m2.signature) < 0;
84}
85
86// Append a class with alphabetically sorted methods to the model
87static void appendClass(const QString &className, Methods methods, QStandardItemModel *model)
88{
89 if (methods.isEmpty())
90 return;
91 std::sort(methods.begin(), methods.end(), signatureLessThan);
92 QStandardItem *topLevelItem = createTopLevelItem(className);
93 model->appendRow(topLevelItem);
94 for (const SelectSignalDialog::Method &m : std::as_const(methods)) {
95 QStandardItem *item = new QStandardItem(m.signature);
96 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
97 item->setData(QVariant::fromValue(m), MethodRole);
98 topLevelItem->appendRow(item);
99 }
100}
101
102static QString declaredInClass(const QDesignerMetaObjectInterface *metaObject, const QString &member)
103{
104 // Find class whose superclass does not contain the method.
105 const QDesignerMetaObjectInterface *meta = metaObject;
106
107 for (;;) {
108 const QDesignerMetaObjectInterface *tmpMeta = meta->superClass();
109 if (tmpMeta == nullptr)
110 break;
111 if (tmpMeta->indexOfMethod(member) == -1)
112 break;
113 meta = tmpMeta;
114 }
115 return meta->className();
116}
117
118static inline QString msgNoSignals()
119{
120 return QCoreApplication::translate("QDesignerTaskMenu", "no signals available");
121}
122
123void SelectSignalDialog::populate(QDesignerFormEditorInterface *core, QObject *object,
124 const QString &defaultSignal)
125{
126 m_okButton->setEnabled(false);
127
128 populateModel(core, object);
129
130 if (m_model->rowCount() == 0) {
131 m_model->appendRow(createTopLevelItem(msgNoSignals()));
132 return;
133 }
134
135 m_ui->signalList->expandAll();
136 m_ui->signalList->resizeColumnToContents(0);
137
138 QModelIndex selectedIndex;
139 if (defaultSignal.isEmpty()) {
140 selectedIndex = m_model->index(0, 0, m_model->index(0, 0, QModelIndex())); // first method
141 } else {
142 const auto items = m_model->findItems(defaultSignal, Qt::MatchExactly | Qt::MatchRecursive, 0);
143 if (!items.isEmpty())
144 selectedIndex = m_model->indexFromItem(items.constFirst());
145 }
146
147 if (selectedIndex.isValid())
148 m_ui->signalList->setCurrentIndex(selectedIndex);
149}
150
151void SelectSignalDialog::populateModel(QDesignerFormEditorInterface *core, QObject *object)
152{
153 m_model->removeRows(0, m_model->rowCount());
154
155 // Populate methods list in reverse order, starting from derived class.
156 if (object->isWidgetType() && qobject_cast<WidgetDataBase *>(core->widgetDataBase())) {
157 const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase();
158 const QString promotedClassName = promotedCustomClassName(core, static_cast<QWidget *>(object));
159 const int index = db->indexOfClassName(promotedClassName);
160 if (index >= 0) {
161 Methods methods;
162 WidgetDataBaseItem* item = static_cast<WidgetDataBaseItem*>(db->item(index));
163 const QStringList fakeSignals = item->fakeSignals();
164 for (const QString &fakeSignal : fakeSignals)
165 methods.append(SelectSignalDialog::Method(promotedClassName, fakeSignal));
166 appendClass(promotedClassName, methods, m_model);
167 }
168 }
169
170 // fake signals
171 if (qdesigner_internal::MetaDataBase *metaDataBase
172 = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase())) {
173 Methods methods;
174 qdesigner_internal::MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(object);
175 Q_ASSERT(item);
176 const QStringList fakeSignals = item->fakeSignals();
177 for (const QString &fakeSignal : fakeSignals)
178 methods.append(SelectSignalDialog::Method(item->customClassName(), fakeSignal));
179 appendClass(item->customClassName(), methods, m_model);
180 }
181
182 // "real" signals
183 if (const QDesignerMetaObjectInterface *metaObject = core->introspection()->metaObject(object)) {
184 QString lastClassName;
185 Methods methods;
186 for (int i = metaObject->methodCount() - 1; i >= 0; --i) {
187 const QDesignerMetaMethodInterface *metaMethod = metaObject->method(i);
188 if (metaMethod->methodType() == QDesignerMetaMethodInterface::Signal) {
189 const QString signature = metaMethod->signature();
190 const QString className = declaredInClass(metaObject, signature);
191 if (lastClassName.isEmpty()) {
192 lastClassName = className;
193 } else if (className != lastClassName) {
194 appendClass(lastClassName, methods, m_model);
195 lastClassName = className;
196 methods.clear();
197 }
198 methods.append(SelectSignalDialog::Method(className, signature,
199 metaMethod->parameterNames()));
200 }
201 }
202 appendClass(lastClassName, methods, m_model);
203 }
204}
205
206void SelectSignalDialog::activated(const QModelIndex &index)
207{
208 if (methodFromIndex(index).isValid())
209 m_okButton->animateClick();
210}
211
212void SelectSignalDialog::currentChanged(const QModelIndex &current, const QModelIndex &)
213{
214 m_okButton->setEnabled(methodFromIndex(current).isValid());
215}
216
217} // namespace qdesigner_internal
218
219QT_END_NAMESPACE
220
221#include "moc_selectsignaldialog_p.cpp"
Auxiliary methods to store/retrieve settings.
static QString msgNoSignals()
static void appendClass(const QString &className, Methods methods, QStandardItemModel *model)
static QStandardItem * createTopLevelItem(const QString &text)
static bool signatureLessThan(const SelectSignalDialog::Method &m1, const SelectSignalDialog::Method &m2)
static QString declaredInClass(const QDesignerMetaObjectInterface *metaObject, const QString &member)