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 "connectdialog_p.h"
30 #include "signalslot_utils_p.h"
31 
32 #include <signalslotdialog_p.h>
33 #include <metadatabase_p.h>
34 
35 #include <QtDesigner/abstractformwindow.h>
36 #include <QtDesigner/abstractformeditor.h>
37 #include <QtDesigner/abstractwidgetdatabase.h>
38 #include <QtDesigner/qextensionmanager.h>
39 #include <QtDesigner/abstractlanguage.h>
40 
41 #include <QtWidgets/qpushbutton.h>
42 
43 QT_BEGIN_NAMESPACE
44 
realClassName(QDesignerFormEditorInterface * core,QWidget * widget)45 static QString realClassName(QDesignerFormEditorInterface *core, QWidget *widget)
46 {
47     QString class_name = QLatin1String(widget->metaObject()->className());
48     const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase();
49     const int idx = wdb->indexOfObject(widget);
50     if (idx != -1)
51         class_name = wdb->item(idx)->name();
52     return class_name;
53 }
54 
widgetLabel(QDesignerFormEditorInterface * core,QWidget * widget)55 static QString widgetLabel(QDesignerFormEditorInterface *core, QWidget *widget)
56 {
57     return QString::fromUtf8("%1 (%2)")
58             .arg(qdesigner_internal::realObjectName(core, widget),
59                  realClassName(core, widget));
60 }
61 
62 namespace qdesigner_internal {
63 
ConnectDialog(QDesignerFormWindowInterface * formWindow,QWidget * source,QWidget * destination,QWidget * parent)64 ConnectDialog::ConnectDialog(QDesignerFormWindowInterface *formWindow,
65                              QWidget *source, QWidget *destination,
66                              QWidget *parent) :
67     QDialog(parent),
68     m_source(source),
69     m_destination(destination),
70     m_sourceMode(widgetMode(m_source, formWindow)),
71     m_destinationMode(widgetMode(m_destination, formWindow)),
72     m_formWindow(formWindow)
73 {
74     m_ui.setupUi(this);
75 
76     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
77 
78     connect(m_ui.signalList, &QListWidget::itemClicked,
79             this, &ConnectDialog::selectSignal);
80     connect(m_ui.slotList, &QListWidget::itemClicked,
81             this, &ConnectDialog::selectSlot);
82     m_ui.slotList->setEnabled(false);
83 
84     QPushButton *ok_button = okButton();
85     ok_button->setDefault(true);
86     ok_button->setEnabled(false);
87 
88     connect(m_ui.showAllCheckBox, &QCheckBox::toggled, this, &ConnectDialog::populateLists);
89 
90     QDesignerFormEditorInterface *core = m_formWindow->core();
91     m_ui.signalGroupBox->setTitle(widgetLabel(core, source));
92     m_ui.slotGroupBox->setTitle(widgetLabel(core, destination));
93 
94     m_ui.editSignalsButton->setEnabled(m_sourceMode != NormalWidget);
95     connect(m_ui.editSignalsButton, &QAbstractButton::clicked,
96             this, &ConnectDialog::editSignals);
97 
98     m_ui.editSlotsButton->setEnabled(m_destinationMode != NormalWidget);
99     connect(m_ui.editSlotsButton, &QAbstractButton::clicked,
100             this, &ConnectDialog::editSlots);
101 
102     populateLists();
103 }
104 
widgetMode(QWidget * w,QDesignerFormWindowInterface * formWindow)105 ConnectDialog::WidgetMode ConnectDialog::widgetMode(QWidget *w,  QDesignerFormWindowInterface *formWindow)
106 {
107     QDesignerFormEditorInterface *core = formWindow->core();
108     if (qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core))
109         return NormalWidget;
110 
111     if (w == formWindow || formWindow->mainContainer() == w)
112         return MainContainer;
113 
114     if (isPromoted(formWindow->core(), w))
115         return PromotedWidget;
116 
117     return NormalWidget;
118 }
119 
okButton()120 QPushButton *ConnectDialog::okButton()
121 {
122     return m_ui.buttonBox->button(QDialogButtonBox::Ok);
123 }
124 
setOkButtonEnabled(bool e)125 void ConnectDialog::setOkButtonEnabled(bool e)
126 {
127     okButton()->setEnabled(e);
128 }
129 
populateLists()130 void ConnectDialog::populateLists()
131 {
132     populateSignalList();
133 }
134 
setSignalSlot(const QString & signal,const QString & slot)135 void ConnectDialog::setSignalSlot(const QString &signal, const QString &slot)
136 {
137     auto sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly);
138 
139     if (sigItems.isEmpty()) {
140         m_ui.showAllCheckBox->setChecked(true);
141         sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly);
142     }
143 
144     if (!sigItems.isEmpty()) {
145         selectSignal(sigItems.constFirst());
146         auto slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly);
147         if (slotItems.isEmpty()) {
148             m_ui.showAllCheckBox->setChecked(true);
149             slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly);
150         }
151         if (!slotItems.isEmpty())
152             selectSlot(slotItems.constFirst());
153     }
154 }
155 
showAllSignalsSlots() const156 bool ConnectDialog::showAllSignalsSlots() const
157 {
158     return m_ui.showAllCheckBox->isChecked();
159 }
160 
setShowAllSignalsSlots(bool showIt)161 void ConnectDialog::setShowAllSignalsSlots(bool showIt)
162 {
163     m_ui.showAllCheckBox->setChecked(showIt);
164 }
165 
selectSignal(QListWidgetItem * item)166 void ConnectDialog::selectSignal(QListWidgetItem *item)
167 {
168     if (item) {
169         m_ui.signalList->setCurrentItem(item);
170         populateSlotList(item->text());
171         m_ui.slotList->setEnabled(true);
172         setOkButtonEnabled(!m_ui.slotList->selectedItems().isEmpty());
173     } else {
174         m_ui.signalList->clearSelection();
175         populateSlotList();
176         m_ui.slotList->setEnabled(false);
177         setOkButtonEnabled(false);
178     }
179 }
180 
selectSlot(QListWidgetItem * item)181 void ConnectDialog::selectSlot(QListWidgetItem *item)
182 {
183     if (item) {
184         m_ui.slotList->setCurrentItem(item);
185     } else {
186         m_ui.slotList->clearSelection();
187     }
188     setOkButtonEnabled(true);
189 }
190 
signal() const191 QString ConnectDialog::signal() const
192 {
193     const auto item_list = m_ui.signalList->selectedItems();
194     if (item_list.size() != 1)
195         return QString();
196     return item_list.at(0)->text();
197 }
198 
slot() const199 QString ConnectDialog::slot() const
200 {
201     const auto item_list = m_ui.slotList->selectedItems();
202     if (item_list.size() != 1)
203         return QString();
204     return item_list.at(0)->text();
205 }
206 
populateSlotList(const QString & signal)207 void ConnectDialog::populateSlotList(const QString &signal)
208 {
209     enum { deprecatedSlot = 0 };
210     QString selectedName;
211     if (const QListWidgetItem * item = m_ui.slotList->currentItem())
212         selectedName = item->text();
213 
214     m_ui.slotList->clear();
215 
216     QMap<QString, QString> memberToClassName = getMatchingSlots(m_formWindow->core(), m_destination, signal, showAllSignalsSlots());
217 
218     QFont font = QApplication::font();
219     font.setItalic(true);
220     QVariant variantFont = QVariant::fromValue(font);
221 
222     QListWidgetItem *curr = nullptr;
223     QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin();
224     const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd();
225     while (itMember != itMemberEnd) {
226         const QString member = itMember.key();
227         QListWidgetItem *item = new QListWidgetItem(m_ui.slotList);
228         item->setText(member);
229         if (member == selectedName)
230             curr = item;
231 
232         // Mark deprecated slots red. Not currently in use (historically for Qt 3 slots in Qt 4),
233         // but may be used again in the future.
234         if (deprecatedSlot) {
235             item->setData(Qt::FontRole, variantFont);
236             item->setData(Qt::ForegroundRole, QColor(Qt::red));
237         }
238         ++itMember;
239     }
240 
241     if (curr)
242         m_ui.slotList->setCurrentItem(curr);
243 
244     if (m_ui.slotList->selectedItems().isEmpty())
245         setOkButtonEnabled(false);
246 }
247 
populateSignalList()248 void ConnectDialog::populateSignalList()
249 {
250     enum { deprecatedSignal = 0 };
251 
252     QString selectedName;
253     if (const QListWidgetItem *item = m_ui.signalList->currentItem())
254         selectedName = item->text();
255 
256     m_ui.signalList->clear();
257 
258     QMap<QString, QString> memberToClassName = getSignals(m_formWindow->core(), m_source, showAllSignalsSlots());
259 
260     QFont font = QApplication::font();
261     font.setItalic(true);
262     QVariant variantFont = QVariant::fromValue(font);
263 
264     QListWidgetItem *curr = nullptr;
265     QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin();
266     const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd();
267     while (itMember != itMemberEnd) {
268         const QString member = itMember.key();
269 
270         QListWidgetItem *item = new QListWidgetItem(m_ui.signalList);
271         item->setText(member);
272         if (!selectedName.isEmpty() && member == selectedName)
273             curr = item;
274 
275         // Mark deprecated signals red. Not currently in use (historically for Qt 3 slots in Qt 4),
276         // but may be used again in the future.
277         if (deprecatedSignal) {
278             item->setData(Qt::FontRole, variantFont);
279             item->setData(Qt::ForegroundRole, QColor(Qt::red));
280         }
281         ++itMember;
282     }
283 
284     if (curr) {
285         m_ui.signalList->setCurrentItem(curr);
286     } else {
287         selectedName.clear();
288     }
289 
290     populateSlotList(selectedName);
291     if (!curr)
292         m_ui.slotList->setEnabled(false);
293 }
294 
editSignals()295 void ConnectDialog::editSignals()
296 {
297     editSignalsSlots(m_source, m_sourceMode, SignalSlotDialog::FocusSignals);
298 }
299 
editSlots()300 void ConnectDialog::editSlots()
301 {
302     editSignalsSlots(m_destination, m_destinationMode, SignalSlotDialog::FocusSlots);
303 }
304 
editSignalsSlots(QWidget * w,WidgetMode mode,int signalSlotDialogModeInt)305 void ConnectDialog::editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogModeInt)
306 {
307     const SignalSlotDialog::FocusMode signalSlotDialogMode = static_cast<SignalSlotDialog::FocusMode>(signalSlotDialogModeInt);
308     switch (mode) {
309     case  NormalWidget:
310         break;
311     case MainContainer:
312         if (SignalSlotDialog::editMetaDataBase(m_formWindow, w, this, signalSlotDialogMode))
313             populateLists();
314         break;
315     case PromotedWidget:
316         if (SignalSlotDialog::editPromotedClass(m_formWindow->core(), w, this, signalSlotDialogMode))
317             populateLists();
318         break;
319     }
320 }
321 
322 }
323 
324 QT_END_NAMESPACE
325