1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "signalslot_utils_p.h"
30
31#include <qdesigner_membersheet_p.h>
32#include <widgetdatabase_p.h>
33#include <metadatabase_p.h>
34
35#include <QtDesigner/abstractformwindow.h>
36#include <QtDesigner/abstractformeditor.h>
37#include <QtDesigner/abstractmetadatabase.h>
38#include <QtDesigner/qextensionmanager.h>
39#include <QtDesigner/abstractlanguage.h>
40
41#include <QtCore/qpair.h>
42
43QT_BEGIN_NAMESPACE
44
45using ClassNameSignaturePair = QPair<QString, QString>;
46
47// Find all member functions that match a predicate on the signature string
48// using the member sheet and the fake methods stored in the widget
49// database and the meta data base.
50// Assign a pair of <classname, signature> to OutputIterator.
51
52template <class SignaturePredicate, class OutputIterator>
53static void memberList(QDesignerFormEditorInterface *core,
54 QObject *object,
55 qdesigner_internal::MemberType member_type,
56 bool showAll,
57 SignaturePredicate predicate,
58 OutputIterator it)
59{
60 if (!object)
61 return;
62 // 1) member sheet
63 const QDesignerMemberSheetExtension *members = qt_extension<QDesignerMemberSheetExtension*>(manager: core->extensionManager(), object);
64 Q_ASSERT(members != nullptr);
65 const int count = members->count();
66 for (int i = 0; i < count; ++i) {
67 if (!members->isVisible(index: i))
68 continue;
69
70 if (member_type == qdesigner_internal::SignalMember && !members->isSignal(index: i))
71 continue;
72
73 if (member_type == qdesigner_internal::SlotMember && !members->isSlot(index: i))
74 continue;
75
76 if (!showAll && members->inheritedFromWidget(index: i))
77 continue;
78
79 const QString signature = members->signature(index: i);
80 if (predicate(signature)) {
81 *it = ClassNameSignaturePair(members->declaredInClass(index: i), signature);
82 ++it;
83 }
84 }
85 // 2) fake slots from widget DB
86 const qdesigner_internal::WidgetDataBase *wdb = qobject_cast<qdesigner_internal::WidgetDataBase *>(object: core->widgetDataBase());
87 if (!wdb)
88 return;
89 const int idx = wdb->indexOfObject(o: object);
90 Q_ASSERT(idx != -1);
91 // get the promoted class name
92 const qdesigner_internal::WidgetDataBaseItem *wdbItem = static_cast<qdesigner_internal::WidgetDataBaseItem *>(wdb->item(index: idx));
93 const QString className = wdbItem->name();
94
95 const QStringList wdbFakeMethods = member_type == qdesigner_internal::SlotMember ? wdbItem->fakeSlots() : wdbItem->fakeSignals();
96 if (!wdbFakeMethods.isEmpty())
97 for (const QString &fakeMethod : wdbFakeMethods)
98 if (predicate(fakeMethod)) {
99 *it = ClassNameSignaturePair(className, fakeMethod);
100 ++it;
101 }
102 // 3) fake slots from meta DB
103 qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<qdesigner_internal::MetaDataBase *>(object: core->metaDataBase());
104 if (!metaDataBase)
105 return;
106
107 if (const qdesigner_internal::MetaDataBaseItem *mdbItem = metaDataBase->metaDataBaseItem(object)) {
108 const QStringList mdbFakeMethods = member_type == qdesigner_internal::SlotMember ? mdbItem->fakeSlots() : mdbItem->fakeSignals();
109 if (!mdbFakeMethods.isEmpty())
110 for (const QString &fakeMethod : mdbFakeMethods)
111 if (predicate(fakeMethod)) {
112 *it = ClassNameSignaturePair(className, fakeMethod);
113 ++it;
114 }
115 }
116}
117
118namespace {
119 // Predicate that matches the exact signature string
120 class EqualsPredicate {
121 public:
122 EqualsPredicate(const QString &pattern) : m_pattern(pattern) {}
123 bool operator()(const QString &s) const { return s == m_pattern; }
124 private:
125 const QString m_pattern;
126 };
127 // Predicate for a QString member signature that matches signals up with slots and vice versa
128 class SignalMatchesSlotPredicate {
129 public:
130 SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType);
131 bool operator()(const QString &s) const;
132
133 private:
134 bool signalMatchesSlot(const QString &signal, const QString &slot) const;
135
136 const QString m_peer;
137 qdesigner_internal::MemberType m_memberType;
138 const QDesignerLanguageExtension *m_lang;
139 };
140
141 SignalMatchesSlotPredicate::SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType) :
142 m_peer(peer),
143 m_memberType(memberType),
144 m_lang(qt_extension<QDesignerLanguageExtension*>(manager: core->extensionManager(), object: core))
145 {
146 }
147
148 bool SignalMatchesSlotPredicate::operator()(const QString &s) const
149 {
150 return m_memberType == qdesigner_internal::SlotMember ? signalMatchesSlot(signal: m_peer, slot: s) : signalMatchesSlot(signal: s, slot: m_peer);
151 }
152
153 bool SignalMatchesSlotPredicate::signalMatchesSlot(const QString &signal, const QString &slot) const
154 {
155 if (m_lang)
156 return m_lang->signalMatchesSlot(signal, slot);
157
158 return QDesignerMemberSheet::signalMatchesSlot(signal, slot);
159 }
160
161 // Output iterator for a pair of pair of <classname, signature>
162 // that builds the reverse class list for reverseClassesMemberFunctions()
163 // (for the combos of the ToolWindow)
164 class ReverseClassesMemberIterator {
165 public:
166 ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result);
167
168 ReverseClassesMemberIterator &operator*() { return *this; }
169 ReverseClassesMemberIterator &operator++() { return *this; }
170 ReverseClassesMemberIterator &operator=(const ClassNameSignaturePair &classNameSignature);
171
172 private:
173 qdesigner_internal::ClassesMemberFunctions *m_result;
174 QString m_lastClassName;
175 QStringList *m_memberList;
176 };
177
178 ReverseClassesMemberIterator::ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result) :
179 m_result(result),
180 m_memberList(nullptr)
181 {
182 }
183
184 ReverseClassesMemberIterator &ReverseClassesMemberIterator::operator=(const ClassNameSignaturePair &classNameSignature)
185 {
186 // prepend a new entry if class changes
187 if (!m_memberList || classNameSignature.first != m_lastClassName) {
188 m_lastClassName = classNameSignature.first;
189 m_result->push_front(t: qdesigner_internal::ClassMemberFunctions(m_lastClassName));
190 m_memberList = &(m_result->front().m_memberList);
191 }
192 m_memberList->push_back(t: classNameSignature.second);
193 return *this;
194 }
195
196 // Output iterator for a pair of pair of <classname, signature>
197 // that adds the signatures to a string list
198 class SignatureIterator {
199 public:
200 SignatureIterator(QMap<QString, QString> *result) : m_result(result) {}
201
202 SignatureIterator &operator*() { return *this; }
203 SignatureIterator &operator++() { return *this; }
204 SignatureIterator &operator=(const ClassNameSignaturePair &classNameSignature)
205 {
206 m_result->insert(akey: classNameSignature.second, avalue: classNameSignature.first);
207 return *this;
208 }
209
210 private:
211 QMap<QString, QString> *m_result;
212 };
213}
214
215static inline bool truePredicate(const QString &) { return true; }
216
217namespace qdesigner_internal {
218
219 ClassMemberFunctions::ClassMemberFunctions(const QString &class_name) :
220 m_className(class_name)
221 {
222 }
223
224 bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot)
225 {
226 const SignalMatchesSlotPredicate predicate(core, signal, qdesigner_internal::SlotMember);
227 return predicate(slot);
228 }
229
230 // return classes and members in reverse class order to
231 // populate of the combo of the ToolWindow
232 ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type,
233 const QString &peer, QDesignerFormWindowInterface *form)
234 {
235 QObject *object = nullptr;
236 if (obj_name == form->mainContainer()->objectName()) {
237 object = form->mainContainer();
238 } else {
239 object = form->mainContainer()->findChild<QObject*>(aName: obj_name);
240 }
241 if (!object)
242 return ClassesMemberFunctions();
243 QDesignerFormEditorInterface *core = form->core();
244
245 ClassesMemberFunctions rc;
246 memberList(core: form->core(), object, member_type, showAll: true, predicate: SignalMatchesSlotPredicate(core, peer, member_type),
247 it: ReverseClassesMemberIterator(&rc));
248 return rc;
249 }
250
251 QMap<QString, QString> getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll)
252 {
253 QMap<QString, QString> rc;
254 memberList(core, object, member_type: SignalMember, showAll, predicate: truePredicate, it: SignatureIterator(&rc));
255 return rc;
256 }
257
258 QMap<QString, QString> getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature, bool showAll)
259 {
260 QMap<QString, QString> rc;
261 memberList(core, object, member_type: SlotMember, showAll, predicate: SignalMatchesSlotPredicate(core, signalSignature, qdesigner_internal::SlotMember), it: SignatureIterator(&rc));
262 return rc;
263 }
264
265 bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature)
266 {
267 QMap<QString, QString> rc;
268 memberList(core, object, member_type: type, showAll: true, predicate: EqualsPredicate(signature), it: SignatureIterator(&rc));
269 return !rc.isEmpty();
270 }
271
272 // ### deprecated
273 QString realObjectName(QDesignerFormEditorInterface *core, QObject *object)
274 {
275 if (!object)
276 return QString();
277
278 const QDesignerMetaDataBaseInterface *mdb = core->metaDataBase();
279 if (const QDesignerMetaDataBaseItemInterface *item = mdb->item(object))
280 return item->name();
281
282 return object->objectName();
283 }
284} // namespace qdesigner_internal
285
286QT_END_NAMESPACE
287

source code of qttools/src/designer/src/components/signalsloteditor/signalslot_utils.cpp