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