10#include <iconloader_p.h>
11#include <spacer_widget_p.h>
12#include <qlayout_widget_p.h>
14#include <QtDesigner/abstractformwindow.h>
15#include <QtDesigner/abstractformeditor.h>
16#include <QtDesigner/abstractformwindowmanager.h>
17#include <QtDesigner/qextensionmanager.h>
18#include <QtDesigner/abstractintegration.h>
19#include <QtDesigner/container.h>
20#include <QtDesigner/abstractmetadatabase.h>
21#include <QtDesigner/abstractformwindowcursor.h>
22#include <abstractdialoggui_p.h>
24#include <QtWidgets/qbuttongroup.h>
25#include <QtWidgets/qmenu.h>
26#include <QtWidgets/qcombobox.h>
27#include <QtWidgets/qapplication.h>
28#include <QtWidgets/qstyleditemdelegate.h>
29#include <QtWidgets/qitemeditorfactory.h>
30#include <QtWidgets/qtreeview.h>
31#include <QtWidgets/qheaderview.h>
32#include <QtWidgets/qboxlayout.h>
33#include <QtWidgets/qtoolbutton.h>
34#include <QtWidgets/qbuttongroup.h>
35#include <QtWidgets/qtoolbar.h>
37#include <QtGui/qaction.h>
38#include <QtGui/qstandarditemmodel.h>
40#include <QtCore/qabstractitemmodel.h>
41#include <QtCore/qdebug.h>
42#include <QtCore/qsortfilterproxymodel.h>
46using namespace Qt::StringLiterals;
52 const QMetaObject *mo = w->metaObject();
53 if (mo != &QLayoutWidget::staticMetaObject && mo != &Spacer::staticMetaObject) {
54 const QString name = w->objectName().trimmed();
64 QWidget *mainContainer = form->mainContainer();
70 if (
const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension *>(form->core()->extensionManager(), mainContainer)) {
71 const int count = c->count();
72 for (
int i = 0 ; i < count; i++)
73 addWidgetToObjectList(c->widget(i), result);
76 const QDesignerFormWindowCursorInterface *cursor = form->cursor();
77 const int widgetCount = cursor->widgetCount();
78 for (
int i = 0; i < widgetCount; ++i)
79 addWidgetToObjectList(cursor->widget(i), result);
81 const QDesignerMetaDataBaseInterface *mdb = form->core()->metaDataBase();
84 const auto actions = mainContainer->findChildren<QAction*>();
85 for (QAction *a : actions) {
86 if (!a->isSeparator()) {
87 if (QMenu *menu = a->menu()) {
89 result.push_back(menu->objectName());
92 result.push_back(a->objectName());
98 const auto buttonGroups = mainContainer->findChildren<QButtonGroup *>();
99 for (QButtonGroup * b : buttonGroups) {
101 result.append(b->objectName());
113 QAbstractItemModel(parent)
119 if (m_editor == editor)
124 disconnect(m_editor.data(), &SignalSlotEditor::connectionAdded,
125 this, &ConnectionModel::connectionAdded);
126 disconnect(m_editor.data(), &SignalSlotEditor::connectionRemoved,
128 disconnect(m_editor.data(), &SignalSlotEditor::aboutToRemoveConnection,
130 disconnect(m_editor.data(), &SignalSlotEditor::aboutToAddConnection,
132 disconnect(m_editor.data(), &SignalSlotEditor::connectionChanged,
137 connect(m_editor.data(), &SignalSlotEditor::connectionAdded,
138 this, &ConnectionModel::connectionAdded);
139 connect(m_editor.data(), &SignalSlotEditor::connectionRemoved,
141 connect(m_editor.data(), &SignalSlotEditor::aboutToRemoveConnection,
143 connect(m_editor.data(), &SignalSlotEditor::aboutToAddConnection,
145 connect(m_editor.data(), &SignalSlotEditor::connectionChanged,
154 if (orientation == Qt::Vertical || role != Qt::DisplayRole)
157 static const QVariant senderTitle = tr(
"Sender");
158 static const QVariant signalTitle = tr(
"Signal");
159 static const QVariant receiverTitle = tr(
"Receiver");
160 static const QVariant slotTitle = tr(
"Slot");
168 return receiverTitle;
178 if (parent.isValid() || !m_editor)
179 return QModelIndex();
180 if (row < 0 || row >= m_editor->connectionCount())
181 return QModelIndex();
182 return createIndex(row, column);
187 if (!index.isValid() || !m_editor)
189 if (index.row() < 0 || index.row() >= m_editor->connectionCount())
191 return m_editor->connection(index.row());
197 return createIndex(m_editor->indexOfConnection(con), 0);
202 return QModelIndex();
207 if (parent.isValid() || !m_editor)
209 return m_editor->connectionCount();
214 if (parent.isValid())
221 const int row = index.row();
222 return m_editor !=
nullptr && row >= 0 && row < m_editor->connectionCount()
223 ?
static_cast<
const SignalSlotConnection*>(m_editor->connection(row))
229 enum { deprecatedMember = 0 };
238 case Qt::ForegroundRole:
239 return deprecatedMember ? QColor(Qt::red) : QVariant();
241 if (deprecatedMember) {
242 QFont font = QApplication::font();
243 font.setItalic(
true);
247 case Qt::DisplayRole:
249 return ConnectionModel::columnText(con, index.column());
259 static const QString senderDefault = tr(
"<sender>");
260 static const QString signalDefault = tr(
"<signal>");
261 static const QString receiverDefault = tr(
"<receiver>");
262 static const QString slotDefault = tr(
"<slot>");
266 const QString sender = con->sender();
267 return sender.isEmpty() ? senderDefault : sender;
270 const QString signalName = con->signal();
271 return signalName.isEmpty() ? signalDefault : signalName;
274 const QString receiver = con->receiver();
275 return receiver.isEmpty() ? receiverDefault : receiver;
278 const QString slotName = con->slot();
279 return slotName.isEmpty() ? slotDefault : slotName;
287 if (!index.isValid() || !m_editor)
289 if (data.metaType().id() != QMetaType::QString)
292 SignalSlotConnection *con =
static_cast<SignalSlotConnection*>(m_editor->connection(index.row()));
293 QDesignerFormWindowInterface *form = m_editor->formWindow();
295 QString s = data.toString();
296 switch (index.column()) {
298 if (!s.isEmpty() && !objectNameList(form).contains(s))
300 m_editor->setSource(con, s);
303 if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Source), SignalMember, s))
305 m_editor->setSignal(con, s);
308 if (!s.isEmpty() && !objectNameList(form).contains(s))
310 m_editor->setTarget(con, s);
313 if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Target), SlotMember, s))
315 m_editor->setSlot(con, s);
335 int idx = m_editor->indexOfConnection(con);
336 beginRemoveRows(QModelIndex(), idx, idx);
342 beginInsertRows(QModelIndex(), idx, idx);
347 return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
353 const int idx = m_editor->indexOfConnection(con);
354 SignalSlotConnection *changedCon =
static_cast<SignalSlotConnection*>(m_editor->connection(idx));
356 for (
int i=0; i<m_editor->connectionCount(); ++i) {
359 c =
static_cast<SignalSlotConnection*>(m_editor->connection(i));
360 if (c->sender() == changedCon->sender() && c->signal() == changedCon->signal()
361 && c->receiver() == changedCon->receiver() && c->slot() == changedCon->slot()) {
362 const QString message = tr(
"The connection already exists!<br>%1").arg(changedCon->toString());
363 m_editor->formWindow()->core()->dialogGui()->message(m_editor->parentWidget(), QDesignerDialogGuiInterface::SignalSlotEditorMessage,
364 QMessageBox::Warning, tr(
"Signal and Slot Editor"), message, QMessageBox::Ok);
368 emit dataChanged(createIndex(idx, 0), createIndex(idx, 3));
373 emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
380class InlineEditorModel :
public QStandardItemModel
384 enum { TitleItem = 1 };
386 InlineEditorModel(
int rows,
int cols, QObject *parent =
nullptr);
388 void addTitle(
const QString &title);
389 void addTextList(
const QMap<QString,
bool> &text_list);
390 void addText(
const QString &text);
391 bool isTitle(
int idx)
const;
393 int findText(
const QString &text)
const;
395 Qt::ItemFlags flags(
const QModelIndex &index)
const override;
398InlineEditorModel::InlineEditorModel(
int rows,
int cols, QObject *parent)
399 : QStandardItemModel(rows, cols, parent)
403void InlineEditorModel::addTitle(
const QString &title)
405 const int cnt = rowCount();
408 setData(cat_idx, QString(title + u':'), Qt::DisplayRole);
409 setData(cat_idx, TitleItem, Qt::UserRole);
410 QFont font = QApplication::font();
412 setData(cat_idx, font, Qt::FontRole);
415bool InlineEditorModel::isTitle(
int idx)
const
420 return data(index(idx, 0), Qt::UserRole).toInt() == TitleItem;
423void InlineEditorModel::addText(
const QString &text)
425 const int cnt = rowCount();
427 setData(index(cnt, 0), text, Qt::DisplayRole);
430void InlineEditorModel::addTextList(
const QMap<QString,
bool> &text_list)
432 int cnt = rowCount();
433 insertRows(cnt, text_list.size());
434 QFont font = QApplication::font();
435 font.setItalic(
true);
436 QVariant fontVariant = QVariant::fromValue(font);
437 for (
auto it = text_list.cbegin(), itEnd = text_list.cend(); it != itEnd; ++it) {
439 setData(text_idx, it.key(), Qt::DisplayRole);
441 setData(text_idx, fontVariant, Qt::FontRole);
442 setData(text_idx, QColor(Qt::red), Qt::ForegroundRole);
447Qt::ItemFlags InlineEditorModel::flags(
const QModelIndex &index)
const
449 return isTitle(index.row())
450 ? Qt::ItemFlags(Qt::ItemIsEnabled)
451 : Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
454int InlineEditorModel::findText(
const QString &text)
const
456 const int cnt = rowCount();
457 for (
int i = 0; i < cnt; ++i) {
459 if (data(idx, Qt::UserRole).toInt() == TitleItem)
461 if (data(idx, Qt::DisplayRole).toString() == text)
468class InlineEditor :
public QComboBox
471 Q_PROPERTY(QString text READ text WRITE setText USER
true)
473 InlineEditor(QWidget *parent =
nullptr);
475 QString text()
const;
476 void setText(
const QString &text);
478 void addTitle(
const QString &title);
479 void addText(
const QString &text);
480 void addTextList(
const QMap<QString,
bool> &text_list);
483 void checkSelection(
int idx);
486 InlineEditorModel *m_model;
490InlineEditor::InlineEditor(
QWidget *parent) :
493 setModel(m_model =
new InlineEditorModel(0, 4,
this));
496 connect(
this, &QComboBox::activated,
497 this, &InlineEditor::checkSelection);
500void InlineEditor::checkSelection(
int idx)
505 if (m_model->isTitle(idx))
506 setCurrentIndex(m_idx);
511void InlineEditor::addTitle(
const QString &title)
513 m_model->addTitle(title);
516void InlineEditor::addTextList(
const QMap<QString,
bool> &text_list)
518 m_model->addTextList(text_list);
521void InlineEditor::addText(
const QString &text)
523 m_model->addText(text);
526QString InlineEditor::text()
const
528 return currentText();
531void InlineEditor::setText(
const QString &text)
533 m_idx = m_model->findText(text);
536 setCurrentIndex(m_idx);
541class ConnectionDelegate :
public QStyledItemDelegate
545 ConnectionDelegate(QWidget *parent =
nullptr);
547 void setForm(QDesignerFormWindowInterface *form);
550 const QStyleOptionViewItem &option,
554 void emitCommitData();
557 QDesignerFormWindowInterface *m_form;
560ConnectionDelegate::ConnectionDelegate(
QWidget *parent)
561 : QStyledItemDelegate(parent)
565 static QItemEditorFactory *factory =
nullptr;
566 if (factory ==
nullptr) {
567 factory =
new QItemEditorFactory;
568 QItemEditorCreatorBase *creator
569 =
new QItemEditorCreator<InlineEditor>(
"text");
570 factory->registerEditor(QMetaType::QString, creator);
573 setItemEditorFactory(factory);
576void ConnectionDelegate::setForm(QDesignerFormWindowInterface *form)
582 const QStyleOptionViewItem &option,
585 if (m_form ==
nullptr)
588 QWidget *w = QStyledItemDelegate::createEditor(parent, option, index);
589 InlineEditor *inline_editor = qobject_cast<InlineEditor*>(w);
590 Q_ASSERT(inline_editor !=
nullptr);
591 const QAbstractItemModel *model = index.model();
593 const QModelIndex obj_name_idx = model->index(index.row(), index.column() <= 1 ? 0 : 2);
594 const QString obj_name = model->data(obj_name_idx, Qt::DisplayRole).toString();
596 switch (index.column()) {
599 const QStringList &obj_name_list = objectNameList(m_form);
600 QMap<QString,
bool> markedNameList;
601 markedNameList.insert(tr(
"<object>"),
false);
602 inline_editor->addTextList(markedNameList);
603 markedNameList.clear();
604 for (
const QString &name : obj_name_list)
605 markedNameList.insert(name,
false);
606 inline_editor->addTextList(markedNameList);
612 const QModelIndex peer_index = model->index(index.row(), type == qdesigner_internal::SignalMember ? 3 : 1);
613 const QString peer = model->data(peer_index, Qt::DisplayRole).toString();
615 const qdesigner_internal::ClassesMemberFunctions class_list = qdesigner_internal::reverseClassesMemberFunctions(obj_name, type, peer, m_form);
618 for (
const qdesigner_internal::ClassMemberFunctions &classInfo : class_list) {
619 if (classInfo.m_className.isEmpty() || classInfo.m_memberList.isEmpty())
622 QMap<QString,
bool> markedMemberList;
623 for (
const QString &member : std::as_const(classInfo.m_memberList))
624 markedMemberList.insert(member,
false);
625 inline_editor->addTitle(classInfo.m_className);
626 inline_editor->addTextList(markedMemberList);
634 connect(inline_editor, &QComboBox::activated,
635 this, &ConnectionDelegate::emitCommitData);
637 return inline_editor;
640void ConnectionDelegate::emitCommitData()
642 InlineEditor *editor = qobject_cast<InlineEditor*>(sender());
643 emit commitData(editor);
651
652
657 m_view(
new QTreeView),
659 m_add_button(
new QToolButton),
660 m_remove_button(
new QToolButton),
662 m_model(
new ConnectionModel(
this)),
663 m_proxy_model(
new QSortFilterProxyModel(
this)),
664 m_handling_selection_change(
false)
666 m_proxy_model->setSourceModel(m_model);
667 m_view->setModel(m_proxy_model);
668 m_view->setSortingEnabled(
true);
669 m_view->setItemDelegate(
new ConnectionDelegate(
this));
670 m_view->setEditTriggers(QAbstractItemView::DoubleClicked
671 | QAbstractItemView::EditKeyPressed);
672 m_view->setRootIsDecorated(
false);
673 m_view->setTextElideMode (Qt::ElideMiddle);
674 connect(m_view->selectionModel(), &QItemSelectionModel::currentChanged,
676 connect(m_view->header(), &QHeaderView::sectionDoubleClicked,
677 m_view, &QTreeView::resizeColumnToContents);
679 QVBoxLayout *layout =
new QVBoxLayout(
this);
680 layout->setContentsMargins(QMargins());
681 layout->setSpacing(0);
683 QToolBar *toolBar =
new QToolBar;
684 toolBar->setIconSize(QSize(22, 22));
685 m_add_button->setIcon(createIconSet(
"plus.png"_L1));
687 toolBar->addWidget(m_add_button);
689 m_remove_button->setIcon(createIconSet(
"minus.png"_L1));
691 toolBar->addWidget(m_remove_button);
693 layout->addWidget(toolBar);
694 layout->addWidget(m_view);
696 connect(core->formWindowManager(),
697 &QDesignerFormWindowManagerInterface::activeFormWindowChanged,
698 this, &SignalSlotEditorWindow::setActiveFormWindow);
705 QDesignerIntegrationInterface *integration = m_core->integration();
707 if (!m_editor.isNull()) {
708 disconnect(m_view->selectionModel(),
709 &QItemSelectionModel::currentChanged,
711 disconnect(m_editor.data(), &SignalSlotEditor::connectionSelected,
712 this, &SignalSlotEditorWindow::updateDialogSelection);
713 disconnect(m_editor.data(), &SignalSlotEditor::connectionAdded,
716 disconnect(integration, &QDesignerIntegrationInterface::objectNameChanged,
717 this, &SignalSlotEditorWindow::objectNameChanged);
721 m_editor = form ? form->findChild<SignalSlotEditor*>() :
nullptr;
723 if (!m_editor.isNull()) {
724 ConnectionDelegate *delegate
725 = qobject_cast<ConnectionDelegate*>(m_view->itemDelegate());
726 if (delegate !=
nullptr)
727 delegate->setForm(form);
729 connect(m_view->selectionModel(),
730 &QItemSelectionModel::currentChanged,
732 connect(m_editor.data(), &SignalSlotEditor::connectionSelected,
733 this, &SignalSlotEditorWindow::updateDialogSelection);
734 connect(m_editor.data(), &SignalSlotEditor::connectionAdded,
737 connect(integration, &QDesignerIntegrationInterface::objectNameChanged,
738 this, &SignalSlotEditorWindow::objectNameChanged);
748 if (m_handling_selection_change || m_editor ==
nullptr)
751 QModelIndex index = m_proxy_model->mapFromSource(m_model->connectionToIndex(con));
752 if (!index.isValid() || index == m_view->currentIndex())
754 m_handling_selection_change =
true;
755 m_view->scrollTo(index, QTreeView::EnsureVisible);
756 m_view->setCurrentIndex(index);
757 m_handling_selection_change =
false;
764 if (m_handling_selection_change || m_editor ==
nullptr)
767 if (m_editor ==
nullptr)
770 Connection *con = m_model->indexToConnection(m_proxy_model->mapToSource(index));
771 if (m_editor->selected(con))
773 m_handling_selection_change =
true;
774 m_editor->selectNone();
775 m_editor->setSelected(con,
true);
776 m_handling_selection_change =
false;
781void SignalSlotEditorWindow::objectNameChanged(QDesignerFormWindowInterface *, QObject *,
const QString &,
const QString &)
789 if (m_editor.isNull())
792 m_editor->addEmptyConnection();
798 if (m_editor.isNull())
801 m_editor->deleteSelected();
807 m_add_button->setEnabled(!m_editor.isNull());
808 m_remove_button->setEnabled(!m_editor.isNull() && m_view->currentIndex().isValid());
813 for (
int c = 0, count = m_model->columnCount(); c < count; ++c)
814 m_view->resizeColumnToContents(c);
821#include "signalsloteditorwindow.moc"
QModelIndex connectionToIndex(Connection *con) const
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Returns the data for the given role and section in the header with the specified orientation.
void setEditor(SignalSlotEditor *editor=nullptr)
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
static void addWidgetToObjectList(const QWidget *w, QStringList &r)
static QStringList objectNameList(QDesignerFormWindowInterface *form)