diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /tools/designer/src/components/signalsloteditor | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'tools/designer/src/components/signalsloteditor')
17 files changed, 3322 insertions, 0 deletions
diff --git a/tools/designer/src/components/signalsloteditor/connectdialog.cpp b/tools/designer/src/components/signalsloteditor/connectdialog.cpp new file mode 100644 index 0000000..d9b8ed5 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include <signalslotdialog_p.h> +#include <metadatabase_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerWidgetDataBaseInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerLanguageExtension> + +#include <QtGui/QPushButton> + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList<QListWidgetItem*> ListWidgetItems; +} + +static QString realClassName(QDesignerFormEditorInterface *core, QWidget *widget) +{ + QString class_name = QLatin1String(widget->metaObject()->className()); + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int idx = wdb->indexOfObject(widget); + if (idx != -1) + class_name = wdb->item(idx)->name(); + return class_name; +} + +static QString widgetLabel(QDesignerFormEditorInterface *core, QWidget *widget) +{ + return QString::fromUtf8("%1 (%2)") + .arg(qdesigner_internal::realObjectName(core, widget)) + .arg(realClassName(core, widget)); +} + +namespace qdesigner_internal { + +ConnectDialog::ConnectDialog(QDesignerFormWindowInterface *formWindow, + QWidget *source, QWidget *destination, + QWidget *parent) : + QDialog(parent), + m_source(source), + m_destination(destination), + m_sourceMode(widgetMode(m_source, formWindow)), + m_destinationMode(widgetMode(m_destination, formWindow)), + m_formWindow(formWindow) +{ + m_ui.setupUi(this); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(m_ui.signalList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSignal(QListWidgetItem*))); + connect(m_ui.slotList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSlot(QListWidgetItem*))); + m_ui.slotList->setEnabled(false); + + QPushButton *ok_button = okButton(); + ok_button->setDefault(true); + ok_button->setEnabled(false); + + connect(m_ui.showAllCheckBox, SIGNAL(toggled(bool)), this, SLOT(populateLists())); + + QDesignerFormEditorInterface *core = m_formWindow->core(); + m_ui.signalGroupBox->setTitle(widgetLabel(core, source)); + m_ui.slotGroupBox->setTitle(widgetLabel(core, destination)); + + m_ui.editSignalsButton->setEnabled(m_sourceMode != NormalWidget); + connect(m_ui.editSignalsButton, SIGNAL(clicked()), this, SLOT(editSignals())); + + m_ui.editSlotsButton->setEnabled(m_destinationMode != NormalWidget); + connect(m_ui.editSlotsButton, SIGNAL(clicked()), this, SLOT(editSlots())); + + populateLists(); +} + +ConnectDialog::WidgetMode ConnectDialog::widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow) +{ + QDesignerFormEditorInterface *core = formWindow->core(); + if (qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) + return NormalWidget; + + if (w == formWindow || formWindow->mainContainer() == w) + return MainContainer; + + if (isPromoted(formWindow->core(), w)) + return PromotedWidget; + + return NormalWidget; +} + +QPushButton *ConnectDialog::okButton() +{ + return m_ui.buttonBox->button(QDialogButtonBox::Ok); +} + +void ConnectDialog::setOkButtonEnabled(bool e) +{ + okButton()->setEnabled(e); +} + +void ConnectDialog::populateLists() +{ + populateSignalList(); +} + +void ConnectDialog::setSignalSlot(const QString &signal, const QString &slot) +{ + ListWidgetItems sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + + if (sigItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + } + + if (!sigItems.empty()) { + selectSignal(sigItems.front()); + ListWidgetItems slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + if (slotItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + } + if (!slotItems.empty()) + selectSlot(slotItems.front()); + } +} + +bool ConnectDialog::showAllSignalsSlots() const +{ + return m_ui.showAllCheckBox->isChecked(); +} + +void ConnectDialog::setShowAllSignalsSlots(bool showIt) +{ + m_ui.showAllCheckBox->setChecked(showIt); +} + +void ConnectDialog::selectSignal(QListWidgetItem *item) +{ + if (item) { + m_ui.signalList->setCurrentItem(item); + populateSlotList(item->text()); + m_ui.slotList->setEnabled(true); + setOkButtonEnabled(!m_ui.slotList->selectedItems().isEmpty()); + } else { + m_ui.signalList->clearSelection(); + populateSlotList(); + m_ui.slotList->setEnabled(false); + setOkButtonEnabled(false); + } +} + +void ConnectDialog::selectSlot(QListWidgetItem *item) +{ + if (item) { + m_ui.slotList->setCurrentItem(item); + } else { + m_ui.slotList->clearSelection(); + } + setOkButtonEnabled(true); +} + +QString ConnectDialog::signal() const +{ + const ListWidgetItems item_list = m_ui.signalList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +QString ConnectDialog::slot() const +{ + const ListWidgetItems item_list = m_ui.slotList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +void ConnectDialog::populateSlotList(const QString &signal) +{ + QString selectedName; + if (const QListWidgetItem * item = m_ui.slotList->currentItem()) + selectedName = item->text(); + + m_ui.slotList->clear(); + + QMap<QString, QString> memberToClassName = getMatchingSlots(m_formWindow->core(), m_destination, signal, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = qVariantFromValue(font); + + QListWidgetItem *curr = 0; + QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin(); + const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Slot = isQt3Slot(m_formWindow->core(), m_destination, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.slotList); + item->setText(member); + if (member == selectedName) + curr = item; + + if (qt3Slot) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) + m_ui.slotList->setCurrentItem(curr); + + if (m_ui.slotList->selectedItems().isEmpty()) + setOkButtonEnabled(false); +} + +void ConnectDialog::populateSignalList() +{ + QString selectedName; + if (const QListWidgetItem *item = m_ui.signalList->currentItem()) + selectedName = item->text(); + + m_ui.signalList->clear(); + + QMap<QString, QString> memberToClassName = getSignals(m_formWindow->core(), m_source, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = qVariantFromValue(font); + + QListWidgetItem *curr = 0; + QMap<QString, QString>::ConstIterator itMember = memberToClassName.constBegin(); + const QMap<QString, QString>::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Signal = isQt3Signal(m_formWindow->core(), m_source, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.signalList); + item->setText(member); + if (!selectedName.isEmpty() && member == selectedName) + curr = item; + + if (qt3Signal) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) { + m_ui.signalList->setCurrentItem(curr); + } else { + selectedName.clear(); + } + + populateSlotList(selectedName); + if (!curr) + m_ui.slotList->setEnabled(false); +} + +void ConnectDialog::editSignals() +{ + editSignalsSlots(m_source, m_sourceMode, SignalSlotDialog::FocusSignals); +} + +void ConnectDialog::editSlots() +{ + editSignalsSlots(m_destination, m_destinationMode, SignalSlotDialog::FocusSlots); +} + +void ConnectDialog::editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogModeInt) +{ + const SignalSlotDialog::FocusMode signalSlotDialogMode = static_cast<SignalSlotDialog::FocusMode>(signalSlotDialogModeInt); + switch (mode) { + case NormalWidget: + break; + case MainContainer: + if (SignalSlotDialog::editMetaDataBase(m_formWindow, w, this, signalSlotDialogMode)) + populateLists(); + break; + case PromotedWidget: + if (SignalSlotDialog::editPromotedClass(m_formWindow->core(), w, this, signalSlotDialogMode)) + populateLists(); + break; + } +} + +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/connectdialog.ui b/tools/designer/src/components/signalsloteditor/connectdialog.ui new file mode 100644 index 0000000..bd062eb --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog.ui @@ -0,0 +1,150 @@ +<ui version="4.0" > + <class>ConnectDialog</class> + <widget class="QDialog" name="ConnectDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>585</width> + <height>361</height> + </rect> + </property> + <property name="windowTitle" > + <string>Configure Connection</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" colspan="2" > + <widget class="QGroupBox" name="signalGroupBox" > + <property name="title" > + <string>GroupBox</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QListWidget" name="signalList" > + <property name="textElideMode" > + <enum>Qt::ElideMiddle</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QToolButton" name="editSignalsButton" > + <property name="text" > + <string>Edit...</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="0" column="2" > + <widget class="QGroupBox" name="slotGroupBox" > + <property name="title" > + <string>GroupBox</string> + </property> + <layout class="QVBoxLayout" > + <item> + <widget class="QListWidget" name="slotList" > + <property name="textElideMode" > + <enum>Qt::ElideMiddle</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" > + <item> + <widget class="QToolButton" name="editSlotsButton" > + <property name="text" > + <string>Edit...</string> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item row="1" column="0" > + <widget class="QCheckBox" name="showAllCheckBox" > + <property name="text" > + <string>Show signals and slots inherited from QWidget</string> + </property> + </widget> + </item> + <item row="2" column="1" colspan="2" > + <widget class="QDialogButtonBox" name="buttonBox" > + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons" > + <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ConnectDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel" > + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel" > + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ConnectDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel" > + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/tools/designer/src/components/signalsloteditor/connectdialog_p.h b/tools/designer/src/components/signalsloteditor/connectdialog_p.h new file mode 100644 index 0000000..8fdc019 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/connectdialog_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONNECTDIALOG_H +#define CONNECTDIALOG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "ui_connectdialog.h" +#include <QtGui/QDialog> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QPushButton; + +namespace qdesigner_internal { + +class ConnectDialog : public QDialog +{ + Q_OBJECT +public: + ConnectDialog(QDesignerFormWindowInterface *formWindow, QWidget *sender, QWidget *receiver, QWidget *parent = 0); + + QString signal() const; + QString slot() const; + + void setSignalSlot(const QString &signal, const QString &slot); + + bool showAllSignalsSlots() const; + void setShowAllSignalsSlots(bool showIt); + +private slots: + void populateLists(); + void selectSignal(QListWidgetItem *item); + void selectSlot(QListWidgetItem *item); + void populateSignalList(); + void populateSlotList(const QString &signal = QString()); + void editSignals(); + void editSlots(); + +private: + enum WidgetMode { NormalWidget, MainContainer, PromotedWidget }; + + static WidgetMode widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow); + QPushButton *okButton(); + void setOkButtonEnabled(bool); + void editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogMode); + + QWidget *m_source; + QWidget *m_destination; + const WidgetMode m_sourceMode; + const WidgetMode m_destinationMode; + QDesignerFormWindowInterface *m_formWindow; + Ui::ConnectDialog m_ui; +}; + +} + +QT_END_NAMESPACE + +#endif // CONNECTDIALOG_H diff --git a/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp b/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp new file mode 100644 index 0000000..f4c7693 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalslot_utils.cpp @@ -0,0 +1,331 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalslot_utils_p.h" + +#include <qdesigner_membersheet_p.h> +#include <widgetdatabase_p.h> +#include <metadatabase_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerLanguageExtension> + +#include <QtCore/QPair> + +QT_BEGIN_NAMESPACE + +typedef QPair<QString, QString> ClassNameSignaturePair; + +// Find all member functions that match a predicate on the signature string +// using the member sheet and the fake methods stored in the widget +// database and the meta data base. +// Assign a pair of <classname, signature> to OutputIterator. + +template <class SignaturePredicate, class OutputIterator> +static void memberList(QDesignerFormEditorInterface *core, + QObject *object, + qdesigner_internal::MemberType member_type, + bool showAll, + SignaturePredicate predicate, + OutputIterator it) +{ + if (!object) + return; + + // 1) member sheet + const QDesignerMemberSheetExtension *members = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object); + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) { + if (!members->isVisible(i)) + continue; + + if (member_type == qdesigner_internal::SignalMember && !members->isSignal(i)) + continue; + + if (member_type == qdesigner_internal::SlotMember && !members->isSlot(i)) + continue; + + if (!showAll && members->inheritedFromWidget(i)) + continue; + + const QString signature = members->signature(i); + if (predicate(signature)) { + *it = ClassNameSignaturePair(members->declaredInClass(i), signature); + ++it; + } + } + // 2) fake slots from widget DB + const qdesigner_internal::WidgetDataBase *wdb = qobject_cast<qdesigner_internal::WidgetDataBase *>(core->widgetDataBase()); + if (!wdb) + return; + const int idx = wdb->indexOfObject(object); + Q_ASSERT(idx != -1); + // get the promoted class name + const qdesigner_internal::WidgetDataBaseItem *wdbItem = static_cast<qdesigner_internal::WidgetDataBaseItem *>(wdb->item(idx)); + const QString className = wdbItem->name(); + + const QStringList wdbFakeMethods = member_type == qdesigner_internal::SlotMember ? wdbItem->fakeSlots() : wdbItem->fakeSignals(); + if (!wdbFakeMethods.empty()) + foreach (const QString &fakeMethod, wdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } + // 3) fake slots from meta DB + qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast<qdesigner_internal::MetaDataBase *>(core->metaDataBase()); + if (!metaDataBase) + return; + + const qdesigner_internal::MetaDataBaseItem *mdbItem = metaDataBase->metaDataBaseItem(object); + Q_ASSERT(mdbItem); + const QStringList mdbFakeMethods = member_type == qdesigner_internal::SlotMember ? mdbItem->fakeSlots() : mdbItem->fakeSignals(); + if (!mdbFakeMethods.empty()) + foreach (const QString &fakeMethod, mdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } +} + +namespace { + // Predicate that matches the exact signature string + class EqualsPredicate { + public: + EqualsPredicate(const QString &pattern) : m_pattern(pattern) {} + bool operator()(const QString &s) const { return s == m_pattern; } + private: + const QString m_pattern; + }; + // Predicate for a QString member signature that matches signals up with slots and vice versa + class SignalMatchesSlotPredicate { + public: + SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType); + bool operator()(const QString &s) const; + + private: + bool signalMatchesSlot(const QString &signal, const QString &slot) const; + + const QString m_peer; + qdesigner_internal::MemberType m_memberType; + const QDesignerLanguageExtension *m_lang; + }; + + SignalMatchesSlotPredicate::SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType) : + m_peer(peer), + m_memberType(memberType), + m_lang(qt_extension<QDesignerLanguageExtension*>(core->extensionManager(), core)) + { + } + + bool SignalMatchesSlotPredicate::operator()(const QString &s) const + { + return m_memberType == qdesigner_internal::SlotMember ? signalMatchesSlot(m_peer, s) : signalMatchesSlot(s, m_peer); + } + + bool SignalMatchesSlotPredicate::signalMatchesSlot(const QString &signal, const QString &slot) const + { + if (m_lang) + return m_lang->signalMatchesSlot(signal, slot); + + return QDesignerMemberSheet::signalMatchesSlot(signal, slot); + } + + // Output iterator for a pair of pair of <classname, signature> + // that builds the reverse class list for reverseClassesMemberFunctions() + // (for the combos of the ToolWindow) + class ReverseClassesMemberIterator { + public: + ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result); + + ReverseClassesMemberIterator &operator*() { return *this; } + ReverseClassesMemberIterator &operator++(int) { return *this; } + ReverseClassesMemberIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature); + + private: + qdesigner_internal::ClassesMemberFunctions *m_result; + QString m_lastClassName; + QStringList *m_memberList; + }; + + ReverseClassesMemberIterator::ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result) : + m_result(result), + m_memberList(0) + { + } + + void ReverseClassesMemberIterator::operator=(const ClassNameSignaturePair &classNameSignature) + { + // prepend a new entry if class changes + if (!m_memberList || classNameSignature.first != m_lastClassName) { + m_lastClassName = classNameSignature.first; + m_result->push_front(qdesigner_internal::ClassMemberFunctions(m_lastClassName)); + m_memberList = &(m_result->front().m_memberList); + } + m_memberList->push_back(classNameSignature.second); + } + + // Output iterator for a pair of pair of <classname, signature> + // that adds the signatures to a string list + class SignatureIterator { + public: + SignatureIterator(QMap<QString, QString> *result) : m_result(result) {} + + SignatureIterator &operator*() { return *this; } + SignatureIterator &operator++(int) { return *this; } + SignatureIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature) { + m_result->insert(classNameSignature.second, classNameSignature.first); + } + + private: + QMap<QString, QString> *m_result; + }; +} + +static inline bool truePredicate(const QString &) { return true; } + +namespace qdesigner_internal { + + ClassMemberFunctions::ClassMemberFunctions(const QString &class_name) : + m_className(class_name) + { + } + + bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot) + { + const SignalMatchesSlotPredicate predicate(core, signal, qdesigner_internal::SlotMember); + return predicate(slot); + } + + // return classes and members in reverse class order to + // populate of the combo of the ToolWindow + ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form) + { + QObject *object = qFindChild<QObject*>(form, obj_name); + if (!object) + return ClassesMemberFunctions(); + + QDesignerFormEditorInterface *core = form->core(); + + ClassesMemberFunctions rc; + memberList(form->core(), object, member_type, true, SignalMatchesSlotPredicate(core, peer, member_type), + ReverseClassesMemberIterator(&rc)); + return rc; + } + + QMap<QString, QString> getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll) + { + QMap<QString, QString> rc; + memberList(core, object, SignalMember, showAll, truePredicate, SignatureIterator(&rc)); + return rc; + } + + bool isQt3Signal(QDesignerFormEditorInterface *core, + QObject *object, const QString &signalSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object)) { + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSignal(i) && members->signature(i) == signalSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast<QDesignerMemberSheet*>(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return memberSheet->isQt3Signal(i); + } + } + + return false; + } + + bool isQt3Slot(QDesignerFormEditorInterface *core, + QObject *object, const QString &slotSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension<QDesignerMemberSheetExtension*>(core->extensionManager(), object)) { + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSlot(i) && members->signature(i) == slotSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast<QDesignerMemberSheet*>(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return memberSheet->isQt3Slot(i); + } + } + return false; + } + + QMap<QString, QString> getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature, bool showAll) + { + QMap<QString, QString> rc; + memberList(core, object, SlotMember, showAll, SignalMatchesSlotPredicate(core, signalSignature, qdesigner_internal::SlotMember), SignatureIterator(&rc)); + return rc; + } + + bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature) + { + QMap<QString, QString> rc; + memberList(core, object, type, true, EqualsPredicate(signature), SignatureIterator(&rc)); + return !rc.empty(); + } + + // ### deprecated + QString realObjectName(QDesignerFormEditorInterface *core, QObject *object) + { + if (!object) + return QString(); + + const QDesignerMetaDataBaseInterface *mdb = core->metaDataBase(); + if (const QDesignerMetaDataBaseItemInterface *item = mdb->item(object)) + return item->name(); + + return object->objectName(); + } +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h b/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h new file mode 100644 index 0000000..9b051e4 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalslot_utils_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTUTILS_P_H +#define SIGNALSLOTUTILS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QStringList> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +enum MemberType { SignalMember, SlotMember }; + +// member to class name +QMap<QString, QString> getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll); +QMap<QString, QString> getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, + const QString &signalSignature, bool showAll); + +bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature); + +// Members functions listed by class they were inherited from +struct ClassMemberFunctions +{ + ClassMemberFunctions() {} + ClassMemberFunctions(const QString &_class_name); + + QString m_className; + QStringList m_memberList; +}; + +typedef QList<ClassMemberFunctions> ClassesMemberFunctions; + +// Return classes and members in reverse class order to +// populate of the combo of the ToolWindow. + +ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form); + +bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot); + +QString realObjectName(QDesignerFormEditorInterface *core, QObject *object); + +bool isQt3Signal(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); +bool isQt3Slot(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTUTILS_P_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp new file mode 100644 index 0000000..511b91f --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.cpp @@ -0,0 +1,528 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditor.h" +#include "signalsloteditor_p.h" +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include <metadatabase_p.h> +#include <ui4_p.h> +#include <qdesigner_formwindowcommand_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerMetaDataBaseInterface> + +#include <QtGui/QApplication> +#include <QtGui/QUndoCommand> +#include <QtGui/QMenu> + +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotConnection +*/ + +SignalSlotConnection::SignalSlotConnection(ConnectionEdit *edit, QWidget *source, QWidget *target) + : Connection(edit, source, target) +{ +} + +DomConnection *SignalSlotConnection::toUi() const +{ + DomConnection *result = new DomConnection; + + result->setElementSender(sender()); + result->setElementSignal(signal()); + result->setElementReceiver(receiver()); + result->setElementSlot(slot()); + + DomConnectionHints *hints = new DomConnectionHints; + QList<DomConnectionHint*> list; + + QPoint sp = endPointPos(EndPoint::Source); + QPoint tp = endPointPos(EndPoint::Target); + + DomConnectionHint *hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("sourcelabel")); + hint->setElementX(sp.x()); + hint->setElementY(sp.y()); + list.append(hint); + + hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("destinationlabel")); + hint->setElementX(tp.x()); + hint->setElementY(tp.y()); + list.append(hint); + + hints->setElementHint(list); + result->setElementHints(hints); + + return result; +} + +void SignalSlotConnection::setSignal(const QString &signal) +{ + m_signal = signal; + setLabel(EndPoint::Source, m_signal); +} + +void SignalSlotConnection::setSlot(const QString &slot) +{ + m_slot = slot; + setLabel(EndPoint::Target, m_slot); +} + +QString SignalSlotConnection::sender() const +{ + QObject *source = object(EndPoint::Source); + if (!source) + return QString(); + + SignalSlotEditor *edit = qobject_cast<SignalSlotEditor*>(this->edit()); + Q_ASSERT(edit != 0); + + return realObjectName(edit->formWindow()->core(), source); +} + +QString SignalSlotConnection::receiver() const +{ + QObject *sink = object(EndPoint::Target); + if (!sink) + return QString(); + + SignalSlotEditor *edit = qobject_cast<SignalSlotEditor*>(this->edit()); + Q_ASSERT(edit != 0); + return realObjectName(edit->formWindow()->core(), sink); +} + +void SignalSlotConnection::updateVisibility() +{ + Connection::updateVisibility(); + if (isVisible() && (signal().isEmpty() || slot().isEmpty())) + setVisible(false); +} + +QString SignalSlotConnection::toString() const +{ + return QCoreApplication::translate("SignalSlotConnection", "SENDER(%1), SIGNAL(%2), RECEIVER(%3), SLOT(%4)") + .arg(sender()).arg(signal()).arg(receiver()).arg(slot()); +} + +SignalSlotConnection::State SignalSlotConnection::isValid(const QWidget *background) const +{ + const QObject *source = object(EndPoint::Source); + if (!source) + return ObjectDeleted; + + const QObject *target = object(EndPoint::Target); + if (!target) + return ObjectDeleted; + + if (m_slot.isEmpty() || m_signal.isEmpty()) + return InvalidMethod; + + if (const QWidget *sourceWidget = qobject_cast<const QWidget*>(source)) + if (!background->isAncestorOf(sourceWidget)) + return NotAncestor; + + if (const QWidget *targetWidget = qobject_cast<const QWidget*>(target)) + if (!background->isAncestorOf(targetWidget)) + return NotAncestor; + + return Valid; +} + +/******************************************************************************* +** Commands +*/ + +class SetMemberCommand : public QUndoCommand, public CETypes +{ +public: + SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor); + virtual void redo(); + virtual void undo(); +private: + const QString m_old_member; + const QString m_new_member; + const EndPoint::Type m_type; + SignalSlotConnection *m_con; + SignalSlotEditor *m_editor; +}; + +SetMemberCommand::SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor) : + m_old_member(type == EndPoint::Source ? con->signal() : con->slot()), + m_new_member(member), + m_type(type), + m_con(con), + m_editor(editor) +{ + if (type == EndPoint::Source) + setText(QApplication::translate("Command", "Change signal")); + else + setText(QApplication::translate("Command", "Change slot")); +} + +void SetMemberCommand::redo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_new_member); + else + m_con->setSlot(m_new_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +void SetMemberCommand::undo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_old_member); + else + m_con->setSlot(m_old_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +// Command to modify a connection +class ModifyConnectionCommand : public QDesignerFormWindowCommand +{ +public: + explicit ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot); + virtual void redo(); + virtual void undo(); + +private: + SignalSlotConnection *m_conn; + const QString m_oldSignal; + const QString m_oldSlot; + const QString m_newSignal; + const QString m_newSlot; +}; + +ModifyConnectionCommand::ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot) : + QDesignerFormWindowCommand(QCoreApplication::translate("Command", "Change signal-slot connection"), form), + m_conn(conn), + m_oldSignal(conn->signal()), + m_oldSlot(conn->slot()), + m_newSignal(newSignal), + m_newSlot(newSlot) +{ +} + +void ModifyConnectionCommand::redo() +{ + m_conn->setSignal(m_newSignal); + m_conn->setSlot(m_newSlot); +} + +void ModifyConnectionCommand::undo() +{ + m_conn->setSignal(m_oldSignal); + m_conn->setSlot(m_oldSlot); +} + +/******************************************************************************* +** SignalSlotEditor +*/ + +SignalSlotEditor::SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent) : + ConnectionEdit(parent, form_window), + m_form_window(form_window), + m_showAllSignalsSlots(false) +{ +} + +void SignalSlotEditor::modifyConnection(Connection *con) +{ + SignalSlotConnection *sigslot_con = static_cast<SignalSlotConnection*>(con); + ConnectDialog dialog(m_form_window, + sigslot_con->widget(EndPoint::Source), + sigslot_con->widget(EndPoint::Target), + m_form_window->core()->topLevel()); + + dialog.setSignalSlot(sigslot_con->signal(), sigslot_con->slot()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + const QString newSignal = dialog.signal(); + const QString newSlot = dialog.slot(); + if (sigslot_con->signal() != newSignal || sigslot_con->slot() != newSlot) { + ModifyConnectionCommand *cmd = new ModifyConnectionCommand(m_form_window, sigslot_con, newSignal, newSlot); + m_form_window->commandHistory()->push(cmd); + } + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); +} + +Connection *SignalSlotEditor::createConnection(QWidget *source, QWidget *destination) +{ + SignalSlotConnection *con = 0; + + Q_ASSERT(source != 0); + Q_ASSERT(destination != 0); + + ConnectDialog dialog(m_form_window, source, destination, m_form_window->core()->topLevel()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + con = new SignalSlotConnection(this, source, destination); + con->setSignal(dialog.signal()); + con->setSlot(dialog.slot()); + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); + + return con; +} + +DomConnections *SignalSlotEditor::toUi() const +{ + DomConnections *result = new DomConnections; + QList<DomConnection*> list; + + const int count = connectionCount(); + for (int i = 0; i < count; ++i) { + const SignalSlotConnection *con = static_cast<const SignalSlotConnection*>(connection(i)); + Q_ASSERT(con != 0); + + // If a widget's parent has been removed or moved to a different form, + // and the parent was not a managed widget + // (a page in a tab widget), we never get a widgetRemoved(). So we filter out + // these child widgets here (check QPointer and verify ancestor). + // Also, the user might demote a promoted widget or remove a fake + // slot in the editor, which causes the connection to become invalid + // once he doubleclicks on the method combo. + switch (con->isValid(background())) { + case SignalSlotConnection::Valid: + list.append(con->toUi()); + break; + case SignalSlotConnection::ObjectDeleted: + case SignalSlotConnection::InvalidMethod: + case SignalSlotConnection::NotAncestor: + break; + } + } + result->setElementConnection(list); + return result; +} + +QObject *SignalSlotEditor::objectByName(QWidget *topLevel, const QString &name) const +{ + if (name.isEmpty()) + return 0; + + Q_ASSERT(topLevel); + QObject *object = 0; + if (topLevel->objectName() == name) + object = topLevel; + else + object = qFindChild<QObject*>(topLevel, name); + const QDesignerMetaDataBaseInterface *mdb = formWindow()->core()->metaDataBase(); + if (mdb->item(object)) + return object; + return 0; +} + +void SignalSlotEditor::fromUi(const DomConnections *connections, QWidget *parent) +{ + if (connections == 0) + return; + + setBackground(parent); + clear(); + const QList<DomConnection*> list = connections->elementConnection(); + foreach (const DomConnection *dom_con, list) { + QObject *source = objectByName(parent, dom_con->elementSender()); + if (source == 0) { + qDebug("SignalSlotEditor::fromUi(): no source widget called \"%s\"", + dom_con->elementSender().toUtf8().constData()); + continue; + } + QObject *destination = objectByName(parent, dom_con->elementReceiver()); + if (destination == 0) { + qDebug("SignalSlotEditor::fromUi(): no destination widget called \"%s\"", + dom_con->elementReceiver().toUtf8().constData()); + continue; + } + + QPoint sp = QPoint(20, 20), tp = QPoint(20, 20); + const DomConnectionHints *dom_hints = dom_con->elementHints(); + if (dom_hints != 0) { + QList<DomConnectionHint*> list = dom_hints->elementHint(); + foreach (DomConnectionHint *hint, list) { + QString attr_type = hint->attributeType(); + QPoint p = QPoint(hint->elementX(), hint->elementY()); + if (attr_type == QLatin1String("sourcelabel")) + sp = p; + else if (attr_type == QLatin1String("destinationlabel")) + tp = p; + } + } + + SignalSlotConnection *con = new SignalSlotConnection(this); + + con->setEndPoint(EndPoint::Source, source, sp); + con->setEndPoint(EndPoint::Target, destination, tp); + con->setSignal(dom_con->elementSignal()); + con->setSlot(dom_con->elementSlot()); + addConnection(con); + } +} + +static bool skipWidget(const QWidget *w) +{ + const QString name = QLatin1String(w->metaObject()->className()); + if (name == QLatin1String("QDesignerWidget")) + return true; + if (name == QLatin1String("QLayoutWidget")) + return true; + if (name == QLatin1String("qdesigner_internal::FormWindow")) + return true; + if (name == QLatin1String("Spacer")) + return true; + return false; +} + +QWidget *SignalSlotEditor::widgetAt(const QPoint &pos) const +{ + QWidget *widget = ConnectionEdit::widgetAt(pos); + + if (widget == m_form_window->mainContainer()) + return widget; + + for (; widget != 0; widget = widget->parentWidget()) { + QDesignerMetaDataBaseItemInterface *item = m_form_window->core()->metaDataBase()->item(widget); + if (item == 0) + continue; + if (skipWidget(widget)) + continue; + break; + } + + return widget; +} + +void SignalSlotEditor::setSignal(SignalSlotConnection *con, const QString &member) +{ + if (member == con->signal()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change signal")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, member, this)); + if (!signalMatchesSlot(m_form_window->core(), member, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSlot(SignalSlotConnection *con, const QString &member) +{ + if (member == con->slot()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change slot")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, member, this)); + if (!signalMatchesSlot(m_form_window->core(), con->signal(), member)) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSource(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(_con); + + if (con->sender() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change sender")); + ConnectionEdit::setSource(con, obj_name); + + QObject *sourceObject = con->object(EndPoint::Source); + + if (!memberFunctionListContains(m_form_window->core(), sourceObject, SignalMember, con->signal())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::setTarget(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(_con); + + if (con->receiver() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change receiver")); + ConnectionEdit::setTarget(con, obj_name); + + QObject *targetObject = con->object(EndPoint::Target); + if (!memberFunctionListContains(m_form_window->core(), targetObject, SlotMember, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::addEmptyConnection() +{ + SignalSlotConnection *con = new SignalSlotConnection(this); + undoStack()->push(new AddConnectionCommand(this, con)); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.h b/tools/designer/src/components/signalsloteditor/signalsloteditor.h new file mode 100644 index 0000000..f330ca0 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_H +#define SIGNALSLOTEDITOR_H + +#include "signalsloteditor_global.h" + +#include <QtDesigner/private/connectionedit_p.h> + +#include <QtXml/QDomDocument> +#include <QtXml/QDomElement> + +QT_BEGIN_NAMESPACE + +class DomConnections; + +namespace qdesigner_internal { + +class SignalSlotConnection; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditor : public ConnectionEdit +{ + Q_OBJECT + +public: + SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent); + + virtual void setSignal(SignalSlotConnection *con, const QString &member); + virtual void setSlot(SignalSlotConnection *con, const QString &member); + virtual void setSource(Connection *con, const QString &obj_name); + virtual void setTarget(Connection *con, const QString &obj_name); + + DomConnections *toUi() const; + void fromUi(const DomConnections *connections, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const { return m_form_window; } + + QObject *objectByName(QWidget *topLevel, const QString &name) const; + + void addEmptyConnection(); + +protected: + virtual QWidget *widgetAt(const QPoint &pos) const; + +private: + virtual Connection *createConnection(QWidget *source, QWidget *destination); + virtual void modifyConnection(Connection *con); + + QDesignerFormWindowInterface *m_form_window; + bool m_showAllSignalsSlots; + + friend class SetMemberCommand; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor.pri b/tools/designer/src/components/signalsloteditor/signalsloteditor.pri new file mode 100644 index 0000000..e903ce1 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor.pri @@ -0,0 +1,21 @@ + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/signalslot_utils_p.h \ + $$PWD/connectdialog_p.h \ + $$PWD/signalsloteditor.h \ + $$PWD/signalsloteditor_tool.h \ + $$PWD/signalsloteditor_plugin.h \ + $$PWD/signalsloteditor_global.h \ + $$PWD/signalsloteditor_p.h \ + $$PWD/signalsloteditorwindow.h + +SOURCES += $$PWD/signalslot_utils.cpp \ + $$PWD/connectdialog.cpp \ + $$PWD/signalsloteditor.cpp \ + $$PWD/signalsloteditor_tool.cpp \ + $$PWD/signalsloteditor_plugin.cpp \ + $$PWD/signalsloteditor_instance.cpp \ + $$PWD/signalsloteditorwindow.cpp + +FORMS += $$PWD/connectdialog.ui diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h new file mode 100644 index 0000000..399778a --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_GLOBAL_H +#define SIGNALSLOTEDITOR_GLOBAL_H + +#include <QtCore/qglobal.h> + +#ifdef Q_OS_WIN +#ifdef QT_SIGNALSLOTEDITOR_LIBRARY +# define QT_SIGNALSLOTEDITOR_EXPORT +#else +# define QT_SIGNALSLOTEDITOR_EXPORT +#endif +#else +#define QT_SIGNALSLOTEDITOR_EXPORT +#endif + +#endif // SIGNALSLOTEDITOR_GLOBAL_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp new file mode 100644 index 0000000..c7a799a --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qplugin.h> + +#include "signalsloteditor_plugin.h" + +QT_USE_NAMESPACE + +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(SignalSlotEditorPlugin) diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h new file mode 100644 index 0000000..8cec010 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_P_H +#define SIGNALSLOTEDITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> +#include <QtCore/QPointer> +#include <QtCore/QAbstractItemModel> + +#include <connectionedit_p.h> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class DomConnection; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class SignalSlotConnection : public Connection +{ +public: + explicit SignalSlotConnection(ConnectionEdit *edit, QWidget *source = 0, QWidget *target = 0); + + void setSignal(const QString &signal); + void setSlot(const QString &slot); + + QString sender() const; + QString receiver() const; + inline QString signal() const { return m_signal; } + inline QString slot() const { return m_slot; } + + DomConnection *toUi() const; + + virtual void updateVisibility(); + + enum State { Valid, ObjectDeleted, InvalidMethod, NotAncestor }; + State isValid(const QWidget *background) const; + + // format for messages, etc. + QString toString() const; + +private: + QString m_signal, m_slot; +}; + +class ConnectionModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit ConnectionModel(QObject *parent = 0); + void setEditor(SignalSlotEditor *editor = 0); + + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &child) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::DisplayRole); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QModelIndex connectionToIndex(Connection *con) const; + Connection *indexToConnection(const QModelIndex &index) const; + void updateAll(); + +private slots: + void connectionAdded(Connection *con); + void connectionRemoved(int idx); + void aboutToRemoveConnection(Connection *con); + void aboutToAddConnection(int idx); + void connectionChanged(Connection *con); + +private: + QPointer<SignalSlotEditor> m_editor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_P_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp new file mode 100644 index 0000000..311c843 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::SignalSlotEditorPlugin +*/ + +#include "signalsloteditor_plugin.h" +#include "signalsloteditor_tool.h" + +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> + +#include <QtGui/QAction> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorPlugin::SignalSlotEditorPlugin() + : m_initialized(false), m_action(0) +{ +} + +SignalSlotEditorPlugin::~SignalSlotEditorPlugin() +{ +} + +bool SignalSlotEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void SignalSlotEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Signals/Slots"), this); + m_action->setObjectName(QLatin1String("__qt_edit_signals_slots_action")); + m_action->setShortcut(tr("F4")); + QIcon icon(QIcon(core->resourceLocation() + QLatin1String("/signalslottool.png"))); + m_action->setIcon(icon); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +QDesignerFormEditorInterface *SignalSlotEditorPlugin::core() const +{ + return m_core; +} + +void SignalSlotEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + SignalSlotEditorTool *tool = new SignalSlotEditorTool(formWindow, this); + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + m_tools[formWindow] = tool; + formWindow->registerTool(tool); +} + +void SignalSlotEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + SignalSlotEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *SignalSlotEditorPlugin::action() const +{ + return m_action; +} + +void SignalSlotEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h new file mode 100644 index 0000000..546110d --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_plugin.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_PLUGIN_H +#define SIGNALSLOTEDITOR_PLUGIN_H + +#include "signalsloteditor_global.h" + +#include <QtDesigner/QDesignerFormEditorPluginInterface> + +#include <QtCore/QPointer> +#include <QtCore/QHash> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class SignalSlotEditorTool; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + SignalSlotEditorPlugin(); + virtual ~SignalSlotEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + virtual QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer<QDesignerFormEditorInterface> m_core; + QHash<QDesignerFormWindowInterface*, SignalSlotEditorTool*> m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_PLUGIN_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp new file mode 100644 index 0000000..973105c --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::SignalSlotEditorTool +*/ + +#include "signalsloteditor_tool.h" +#include "signalsloteditor.h" +#include "ui4_p.h" + +#include <QtDesigner/QDesignerFormWindowInterface> + +#include <QtGui/QAction> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorTool::SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Signals/Slots"), this)) +{ +} + +SignalSlotEditorTool::~SignalSlotEditorTool() +{ +} + +QDesignerFormEditorInterface *SignalSlotEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *SignalSlotEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool SignalSlotEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(event); + + return false; +} + +QWidget *SignalSlotEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new qdesigner_internal::SignalSlotEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); + } + + return m_editor; +} + +QAction *SignalSlotEditorTool::action() const +{ + return m_action; +} + +void SignalSlotEditorTool::activated() +{ + m_editor->enableUpdateBackground(true); +} + +void SignalSlotEditorTool::deactivated() +{ + m_editor->enableUpdateBackground(false); +} + +void SignalSlotEditorTool::saveToDom(DomUI *ui, QWidget*) +{ + ui->setElementConnections(m_editor->toUi()); +} + +void SignalSlotEditorTool::loadFromDom(DomUI *ui, QWidget *mainContainer) +{ + m_editor->fromUi(ui->elementConnections(), mainContainer); +} + +QT_END_NAMESPACE diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h new file mode 100644 index 0000000..97ea831 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditor_tool.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_TOOL_H +#define SIGNALSLOTEDITOR_TOOL_H + +#include "signalsloteditor_global.h" +#include "signalsloteditor.h" + +#include <QtCore/QPointer> +#include <QtDesigner/QDesignerFormWindowToolInterface> + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~SignalSlotEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + + QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + virtual void saveToDom(DomUI *ui, QWidget *mainContainer); + virtual void loadFromDom(DomUI *ui, QWidget *mainContainer); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer<qdesigner_internal::SignalSlotEditor> m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_TOOL_H diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp new file mode 100644 index 0000000..dc6b3c3 --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp @@ -0,0 +1,859 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* +TRANSLATOR qdesigner_internal::ConnectionModel +*/ + +#include "signalsloteditorwindow.h" +#include "signalsloteditor_p.h" +#include "signalsloteditor.h" +#include "qdesigner_integration_p.h" +#include "signalslot_utils_p.h" + +#include <iconloader_p.h> +#include <spacer_widget_p.h> +#include <qlayout_widget_p.h> + +#include <QtDesigner/QDesignerFormWindowInterface> +#include <QtDesigner/QDesignerFormEditorInterface> +#include <QtDesigner/QDesignerFormWindowManagerInterface> +#include <QtDesigner/QExtensionManager> +#include <QtDesigner/QDesignerContainerExtension> +#include <QtDesigner/QDesignerMetaDataBaseInterface> +#include <QtDesigner/QDesignerFormWindowCursorInterface> +#include <abstractdialoggui_p.h> + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QDebug> +#include <QtGui/QAction> +#include <QtGui/QButtonGroup> +#include <QtGui/QMenu> +#include <QtGui/QStandardItemModel> +#include <QtGui/QComboBox> +#include <QtGui/QApplication> +#include <QtGui/QItemDelegate> +#include <QtGui/QItemEditorFactory> +#include <QtGui/QTreeView> +#include <QtGui/QHeaderView> +#include <QtGui/QVBoxLayout> +#include <QtGui/QToolButton> +#include <QtGui/QButtonGroup> + +QT_BEGIN_NAMESPACE + +// Add suitable form widgets to a list of objects for the signal slot +// editor. Prevent special widgets from showing up there. +static void addWidgetToObjectList(const QWidget *w, QStringList &r) +{ + const QMetaObject *mo = w->metaObject(); + if (mo != &QLayoutWidget::staticMetaObject && mo != &Spacer::staticMetaObject) { + const QString name = w->objectName().trimmed(); + if (!name.isEmpty()) + r.push_back(name); + } +} + +static QStringList objectNameList(QDesignerFormWindowInterface *form) +{ + typedef QList<QAction*> ActionList; + typedef QList<QButtonGroup *> ButtonGroupList; + + QStringList result; + + QWidget *mainContainer = form->mainContainer(); + if (!mainContainer) + return result; + + // Add main container container pages (QStatusBar, QWizardPages) etc. + // to the list. Pages of containers on the form are not added, however. + if (const QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension *>(form->core()->extensionManager(), mainContainer)) { + const int count = c->count(); + for (int i = 0 ; i < count; i++) + addWidgetToObjectList(c->widget(i), result); + } + + const QDesignerFormWindowCursorInterface *cursor = form->cursor(); + const int widgetCount = cursor->widgetCount(); + for (int i = 0; i < widgetCount; ++i) + addWidgetToObjectList(cursor->widget(i), result); + + const QDesignerMetaDataBaseInterface *mdb = form->core()->metaDataBase(); + + // Add managed actions and actions with managed menus + const ActionList actions = qFindChildren<QAction*>(mainContainer); + if (!actions.empty()) { + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { + QAction *a = *it; + if (!a->isSeparator()) { + if (QMenu *menu = a->menu()) { + if (mdb->item(menu)) + result.push_back(menu->objectName()); + } else { + if (mdb->item(a)) + result.push_back(a->objectName()); + } + } + } + } + + // Add managed buttons groups + const ButtonGroupList buttonGroups = qFindChildren<QButtonGroup *>(mainContainer); + if (!buttonGroups.empty()) { + const ButtonGroupList::const_iterator cend = buttonGroups.constEnd(); + for (ButtonGroupList::const_iterator it = buttonGroups.constBegin(); it != cend; ++it) + if (mdb->item(*it)) + result.append((*it)->objectName()); + } + + result.sort(); + return result; +} + +namespace qdesigner_internal { + +// ------------ ConnectionModel + +ConnectionModel::ConnectionModel(QObject *parent) : + QAbstractItemModel(parent) +{ +} + +void ConnectionModel::setEditor(SignalSlotEditor *editor) +{ + if (m_editor == editor) + return; + + if (m_editor) { + disconnect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + disconnect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + disconnect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + disconnect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + disconnect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + m_editor = editor; + if (m_editor) { + connect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + connect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + connect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + connect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + connect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + reset(); +} + +QVariant ConnectionModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + + static const QVariant senderTitle = tr("Sender"); + static const QVariant signalTitle = tr("Signal"); + static const QVariant receiverTitle = tr("Receiver"); + static const QVariant slotTitle = tr("Slot"); + + switch (section) { + case 0: + return senderTitle; + case 1: + return signalTitle; + case 2: + return receiverTitle; + case 3: + return slotTitle; + } + return QVariant(); +} + +QModelIndex ConnectionModel::index(int row, int column, + const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return QModelIndex(); + if (row < 0 || row >= m_editor->connectionCount()) + return QModelIndex(); + return createIndex(row, column); +} + +Connection *ConnectionModel::indexToConnection(const QModelIndex &index) const +{ + if (!index.isValid() || !m_editor) + return 0; + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) + return 0; + return m_editor->connection(index.row()); +} + +QModelIndex ConnectionModel::connectionToIndex(Connection *con) const +{ + Q_ASSERT(m_editor); + return createIndex(m_editor->indexOfConnection(con), 0); +} + +QModelIndex ConnectionModel::parent(const QModelIndex&) const +{ + return QModelIndex(); +} + +int ConnectionModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return 0; + return m_editor->connectionCount(); +} + +int ConnectionModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return 4; +} + +QVariant ConnectionModel::data(const QModelIndex &index, int role) const +{ + if ((role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole && role != Qt::ForegroundRole) || !m_editor) + return QVariant(); + + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) { + return QVariant(); + } + + const SignalSlotConnection *con = static_cast<SignalSlotConnection*>(m_editor->connection(index.row())); + Q_ASSERT(con != 0); + + if (role == Qt::FontRole || role == Qt::ForegroundRole) { + bool isQt3Member = false; + if (index.column() == 1) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Source), con->signal()); + } else if (index.column() == 3) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Target), con->slot()); + } + if (isQt3Member) { + if (role == Qt::ForegroundRole) + return Qt::red; + QFont font = QApplication::font(); + font.setItalic(true); + return font; + } + return QVariant(); + } + + static const QVariant senderDefault = tr("<sender>"); + static const QVariant signalDefault = tr("<signal>"); + static const QVariant receiverDefault = tr("<receiver>"); + static const QVariant slotDefault = tr("<slot>"); + + switch (index.column()) { + case 0: { + const QString sender = con->sender(); + if (sender.isEmpty()) + return senderDefault; + return sender; + } + case 1: { + const QString signal = con->signal(); + if (signal.isEmpty()) + return signalDefault; + return signal; + } + case 2: { + const QString receiver = con->receiver(); + if (receiver.isEmpty()) + return receiverDefault; + return receiver; + } + case 3: { + const QString slot = con->slot(); + if (slot.isEmpty()) + return slotDefault; + return slot; + } + } + return QVariant(); +} + +bool ConnectionModel::setData(const QModelIndex &index, const QVariant &data, int) +{ + if (!index.isValid() || !m_editor) + return false; + if (data.type() != QVariant::String) + return false; + + SignalSlotConnection *con = static_cast<SignalSlotConnection*>(m_editor->connection(index.row())); + QDesignerFormWindowInterface *form = m_editor->formWindow(); + + QString s = data.toString(); + switch (index.column()) { + case 0: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setSource(con, s); + break; + case 1: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Source), SignalMember, s)) + s.clear(); + m_editor->setSignal(con, s); + break; + case 2: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setTarget(con, s); + break; + case 3: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Target), SlotMember, s)) + s.clear(); + m_editor->setSlot(con, s); + break; + } + + return true; +} + +void ConnectionModel::connectionAdded(Connection*) +{ + endInsertRows(); +} + +void ConnectionModel::connectionRemoved(int) +{ + endRemoveRows(); +} + +void ConnectionModel::aboutToRemoveConnection(Connection *con) +{ + Q_ASSERT(m_editor); + int idx = m_editor->indexOfConnection(con); + beginRemoveRows(QModelIndex(), idx, idx); +} + +void ConnectionModel::aboutToAddConnection(int idx) +{ + Q_ASSERT(m_editor); + beginInsertRows(QModelIndex(), idx, idx); +} + +Qt::ItemFlags ConnectionModel::flags(const QModelIndex&) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; +} + +void ConnectionModel::connectionChanged(Connection *con) +{ + Q_ASSERT(m_editor); + const int idx = m_editor->indexOfConnection(con); + SignalSlotConnection *changedCon = static_cast<SignalSlotConnection*>(m_editor->connection(idx)); + SignalSlotConnection *c = 0; + for (int i=0; i<m_editor->connectionCount(); ++i) { + if (i == idx) + continue; + c = static_cast<SignalSlotConnection*>(m_editor->connection(i)); + if (c->sender() == changedCon->sender() && c->signal() == changedCon->signal() + && c->receiver() == changedCon->receiver() && c->slot() == changedCon->slot()) { + const QString message = tr("The connection already exists!<br>%1").arg(changedCon->toString()); + m_editor->formWindow()->core()->dialogGui()->message(m_editor->parentWidget(), QDesignerDialogGuiInterface::SignalSlotEditorMessage, + QMessageBox::Warning, tr("Signal and Slot Editor"), message, QMessageBox::Ok); + break; + } + } + emit dataChanged(createIndex(idx, 0), createIndex(idx, 3)); +} + +void ConnectionModel::updateAll() +{ + emit dataChanged(index(0, 0), index(rowCount(), columnCount())); +} +} + +namespace { +// ---------------------- InlineEditorModel + +class InlineEditorModel : public QStandardItemModel +{ + Q_OBJECT +public: + enum { TitleItem = 1 }; + + InlineEditorModel(int rows, int cols, QObject *parent = 0); + + void addTitle(const QString &title); + void addTextList(const QMap<QString, bool> &text_list); + void addText(const QString &text); + bool isTitle(int idx) const; + + int findText(const QString &text) const; + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; +}; + +InlineEditorModel::InlineEditorModel(int rows, int cols, QObject *parent) + : QStandardItemModel(rows, cols, parent) +{ +} + +void InlineEditorModel::addTitle(const QString &title) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + QModelIndex cat_idx = index(cnt, 0); + setData(cat_idx, title + QLatin1Char(':'), Qt::DisplayRole); + setData(cat_idx, TitleItem, Qt::UserRole); + QFont font = QApplication::font(); + font.setBold(true); + setData(cat_idx, font, Qt::FontRole); +} + +bool InlineEditorModel::isTitle(int idx) const +{ + if (idx == -1) + return false; + + return data(index(idx, 0), Qt::UserRole).toInt() == TitleItem; +} + +void InlineEditorModel::addText(const QString &text) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + setData(index(cnt, 0), text, Qt::DisplayRole); +} + +void InlineEditorModel::addTextList(const QMap<QString, bool> &text_list) +{ + int cnt = rowCount(); + insertRows(cnt, text_list.size()); + QFont font = QApplication::font(); + font.setItalic(true); + QVariant fontVariant = qVariantFromValue(font); + QMap<QString, bool>::ConstIterator it = text_list.constBegin(); + const QMap<QString, bool>::ConstIterator itEnd = text_list.constEnd(); + while (it != itEnd) { + const QModelIndex text_idx = index(cnt++, 0); + setData(text_idx, it.key(), Qt::DisplayRole); + if (it.value()) { + setData(text_idx, fontVariant, Qt::FontRole); + setData(text_idx, Qt::red, Qt::ForegroundRole); + } + ++it; + } +} + +Qt::ItemFlags InlineEditorModel::flags(const QModelIndex &index) const +{ + if (isTitle(index.row())) + return Qt::ItemIsEnabled; + else + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +int InlineEditorModel::findText(const QString &text) const +{ + const int cnt = rowCount(); + for (int i = 0; i < cnt; ++i) { + const QModelIndex idx = index(i, 0); + if (data(idx, Qt::UserRole).toInt() == TitleItem) + continue; + if (data(idx, Qt::DisplayRole).toString() == text) + return i; + } + return -1; +} + +// ------------ InlineEditor +class InlineEditor : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText USER true) +public: + InlineEditor(QWidget *parent = 0); + + QString text() const; + void setText(const QString &text); + + void addTitle(const QString &title); + void addText(const QString &text); + void addTextList(const QMap<QString, bool> &text_list); + +private slots: + void checkSelection(int idx); + +private: + InlineEditorModel *m_model; + int m_idx; +}; + +InlineEditor::InlineEditor(QWidget *parent) : + QComboBox(parent), + m_idx(-1) +{ + setModel(m_model = new InlineEditorModel(0, 4, this)); + setFrame(false); + m_idx = -1; + connect(this, SIGNAL(activated(int)), this, SLOT(checkSelection(int))); +} + +void InlineEditor::checkSelection(int idx) +{ + if (idx == m_idx) + return; + + if (m_model->isTitle(idx)) + setCurrentIndex(m_idx); + else + m_idx = idx; +} + +void InlineEditor::addTitle(const QString &title) +{ + m_model->addTitle(title); +} + +void InlineEditor::addTextList(const QMap<QString, bool> &text_list) +{ + m_model->addTextList(text_list); +} + +void InlineEditor::addText(const QString &text) +{ + m_model->addText(text); +} + +QString InlineEditor::text() const +{ + return currentText(); +} + +void InlineEditor::setText(const QString &text) +{ + m_idx = m_model->findText(text); + if (m_idx == -1) + m_idx = 0; + setCurrentIndex(m_idx); +} + +// ------------------ ConnectionDelegate + +class ConnectionDelegate : public QItemDelegate +{ + Q_OBJECT +public: + ConnectionDelegate(QWidget *parent = 0); + + void setForm(QDesignerFormWindowInterface *form); + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + +private slots: + void emitCommitData(); + +private: + QDesignerFormWindowInterface *m_form; +}; + +ConnectionDelegate::ConnectionDelegate(QWidget *parent) + : QItemDelegate(parent) +{ + m_form = 0; + + static QItemEditorFactory *factory = 0; + if (factory == 0) { + factory = new QItemEditorFactory; + QItemEditorCreatorBase *creator + = new QItemEditorCreator<InlineEditor>("text"); + factory->registerEditor(QVariant::String, creator); + } + + setItemEditorFactory(factory); +} + +void ConnectionDelegate::setForm(QDesignerFormWindowInterface *form) +{ + m_form = form; +} + +QWidget *ConnectionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (m_form == 0) + return 0; + + QWidget *w = QItemDelegate::createEditor(parent, option, index); + InlineEditor *inline_editor = qobject_cast<InlineEditor*>(w); + Q_ASSERT(inline_editor != 0); + const QAbstractItemModel *model = index.model(); + + const QModelIndex obj_name_idx = model->index(index.row(), index.column() <= 1 ? 0 : 2); + const QString obj_name = model->data(obj_name_idx, Qt::DisplayRole).toString(); + + switch (index.column()) { + case 0: + case 2: { // object names + QStringList obj_name_list = objectNameList(m_form); + QMap<QString, bool> markedNameList; + markedNameList.insert(tr("<object>"), false); + inline_editor->addTextList(markedNameList); + markedNameList.clear(); + foreach (const QString &name, obj_name_list) + markedNameList.insert(name, false); + inline_editor->addTextList(markedNameList); + } + break; + case 1: + case 3: { // signals, slots + const qdesigner_internal::MemberType type = index.column() == 1 ? qdesigner_internal::SignalMember : qdesigner_internal::SlotMember; + const QModelIndex peer_index = model->index(index.row(), type == qdesigner_internal::SignalMember ? 3 : 1); + const QString peer = model->data(peer_index, Qt::DisplayRole).toString(); + + const qdesigner_internal::ClassesMemberFunctions class_list = qdesigner_internal::reverseClassesMemberFunctions(obj_name, type, peer, m_form); + + QObject *object = qFindChild<QObject*>(m_form, obj_name); + + inline_editor->addText(type == qdesigner_internal::SignalMember ? tr("<signal>") : tr("<slot>")); + foreach (const qdesigner_internal::ClassMemberFunctions &class_info, class_list) { + if (class_info.m_className.isEmpty() || class_info.m_memberList.isEmpty()) + continue; + QStringList memberList = class_info.m_memberList; + QMap<QString, bool> markedMemberList; + foreach (const QString &member, memberList) { + bool mark = false; + if (type == qdesigner_internal::SignalMember) + mark = qdesigner_internal::isQt3Signal(m_form->core(), object, member); + else + mark = qdesigner_internal::isQt3Slot(m_form->core(), object, member); + + if (!mark) + markedMemberList.insert(member, mark); + } + inline_editor->addTitle(class_info.m_className); + inline_editor->addTextList(markedMemberList); + } + } + break; + default: + break; + } + + connect(inline_editor, SIGNAL(activated(int)), this, SLOT(emitCommitData())); + + return inline_editor; +} + +void ConnectionDelegate::emitCommitData() +{ + InlineEditor *editor = qobject_cast<InlineEditor*>(sender()); + emit commitData(editor); +} + +} + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotEditorWindow +*/ + +SignalSlotEditorWindow::SignalSlotEditorWindow(QDesignerFormEditorInterface *core, + QWidget *parent) : + QWidget(parent), + m_view(new QTreeView), + m_editor(0), + m_add_button(new QToolButton), + m_remove_button(new QToolButton), + m_core(core), + m_model(new ConnectionModel(this)), + m_handling_selection_change(false) +{ + m_view->setModel(m_model); + m_view->setItemDelegate(new ConnectionDelegate(this)); + m_view->setEditTriggers(QAbstractItemView::DoubleClicked + | QAbstractItemView::EditKeyPressed); + m_view->setRootIsDecorated(false); + m_view->setTextElideMode (Qt::ElideMiddle); + connect(m_view, SIGNAL(activated(QModelIndex)), this, SLOT(updateUi())); + connect(m_view->header(), SIGNAL(sectionDoubleClicked(int)), m_view, SLOT(resizeColumnToContents(int))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_view); + + QHBoxLayout *layout2 = new QHBoxLayout; + layout2->setMargin(3); + layout->addLayout(layout2); + layout2->addStretch(); + + m_remove_button->setIcon(createIconSet(QLatin1String("minus.png"))); + connect(m_remove_button, SIGNAL(clicked()), this, SLOT(removeConnection())); + layout2->addWidget(m_remove_button); + + m_add_button->setIcon(createIconSet(QLatin1String("plus.png"))); + connect(m_add_button, SIGNAL(clicked()), this, SLOT(addConnection())); + layout2->addWidget(m_add_button); + + connect(core->formWindowManager(), + SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(setActiveFormWindow(QDesignerFormWindowInterface*))); + + updateUi(); +} + +void SignalSlotEditorWindow::setActiveFormWindow(QDesignerFormWindowInterface *form) +{ + QDesignerIntegration *integration = qobject_cast<QDesignerIntegration *>(m_core->integration()); + + if (!m_editor.isNull()) { + disconnect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + disconnect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + disconnect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString))); + } + } + + m_editor = qFindChild<SignalSlotEditor*>(form); + m_model->setEditor(m_editor); + if (!m_editor.isNull()) { + ConnectionDelegate *delegate + = qobject_cast<ConnectionDelegate*>(m_view->itemDelegate()); + if (delegate != 0) + delegate->setForm(form); + + connect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + connect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + connect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface *, QObject *, QString, QString))); + } + } + + updateUi(); +} + +void SignalSlotEditorWindow::updateDialogSelection(Connection *con) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + QModelIndex index = m_model->connectionToIndex(con); + if (index == m_view->currentIndex()) + return; + m_handling_selection_change = true; + m_view->setCurrentIndex(index); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::updateEditorSelection(const QModelIndex &index) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + if (m_editor == 0) + return; + + Connection *con = m_model->indexToConnection(index); + if (m_editor->selected(con)) + return; + m_handling_selection_change = true; + m_editor->selectNone(); + m_editor->setSelected(con, true); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::objectNameChanged(QDesignerFormWindowInterface *, QObject *, const QString &, const QString &) +{ + if (m_editor) + m_model->updateAll(); +} + +void SignalSlotEditorWindow::addConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->addEmptyConnection(); + updateUi(); +} + +void SignalSlotEditorWindow::removeConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->deleteSelected(); + updateUi(); +} + +void SignalSlotEditorWindow::updateUi() +{ + m_add_button->setEnabled(!m_editor.isNull()); + m_remove_button->setEnabled(!m_editor.isNull() && m_view->currentIndex().isValid()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#include "signalsloteditorwindow.moc" diff --git a/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h new file mode 100644 index 0000000..417e44b --- /dev/null +++ b/tools/designer/src/components/signalsloteditor/signalsloteditorwindow.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITORWINDOW_H +#define SIGNALSLOTEDITORWINDOW_H + +#include <QtCore/QPointer> +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QModelIndex; +class QTreeView; +class QToolButton; + +namespace qdesigner_internal { + +class SignalSlotEditor; +class ConnectionModel; +class Connection; + +class SignalSlotEditorWindow : public QWidget +{ + Q_OBJECT +public: + explicit SignalSlotEditorWindow(QDesignerFormEditorInterface *core, QWidget *parent = 0); + +public slots: + void setActiveFormWindow(QDesignerFormWindowInterface *form); + +private slots: + void updateDialogSelection(Connection *con); + void updateEditorSelection(const QModelIndex &index); + + void objectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName); + + void addConnection(); + void removeConnection(); + void updateUi(); + +private: + QTreeView *m_view; + QPointer<SignalSlotEditor> m_editor; + QToolButton *m_add_button, *m_remove_button; + QDesignerFormEditorInterface *m_core; + ConnectionModel *m_model; + bool m_handling_selection_change; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITORWINDOW_H |