diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.cpp b/src/plugins/qmlinspector/components/objectpropertiesview.cpp index b6bb4f18a8c070e90375f765a9bff2379b9b5007..c3cc71124b89e99d69151ca6bcc2d6bfb2cc8fb9 100644 --- a/src/plugins/qmlinspector/components/objectpropertiesview.cpp +++ b/src/plugins/qmlinspector/components/objectpropertiesview.cpp @@ -28,6 +28,7 @@ **************************************************************************/ #include "objectpropertiesview.h" #include "inspectorcontext.h" +#include "watchtable.h" #include <QtCore/QDebug> @@ -67,11 +68,13 @@ PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type) { } -ObjectPropertiesView::ObjectPropertiesView(QDeclarativeEngineDebug *client, QWidget *parent) +ObjectPropertiesView::ObjectPropertiesView(WatchTableModel *watchTableModel, + QDeclarativeEngineDebug *client, QWidget *parent) : QWidget(parent), m_client(client), m_query(0), - m_watch(0), m_clickedItem(0) + m_watch(0), m_clickedItem(0), m_showUnwatchableProperties(false), + m_watchTableModel(watchTableModel) { QVBoxLayout *layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); @@ -92,15 +95,22 @@ ObjectPropertiesView::ObjectPropertiesView(QDeclarativeEngineDebug *client, QWid m_addWatchAction = new QAction(tr("Watch expression"), this); m_removeWatchAction = new QAction(tr("Remove watch"), this); + m_toggleUnwatchablePropertiesAction = new QAction(tr("Show unwatchable properties"), this); connect(m_addWatchAction, SIGNAL(triggered()), SLOT(addWatch())); connect(m_removeWatchAction, SIGNAL(triggered()), SLOT(removeWatch())); - + connect(m_toggleUnwatchablePropertiesAction, SIGNAL(triggered()), SLOT(toggleUnwatchableProperties())); m_tree->setColumnCount(3); m_tree->header()->setDefaultSectionSize(150); layout->addWidget(m_tree); } +void ObjectPropertiesView::toggleUnwatchableProperties() +{ + m_showUnwatchableProperties = !m_showUnwatchableProperties; + setObject(m_object); +} + void ObjectPropertiesView::changeItemSelection() { if (m_tree->selectedItems().isEmpty()) @@ -208,21 +218,31 @@ void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &obj for (int i=0; i<properties.count(); ++i) { const QDeclarativeDebugPropertyReference &p = properties[i]; - PropertiesViewItem *item = new PropertiesViewItem(m_tree); - item->property = p; + if (m_showUnwatchableProperties || p.hasNotifySignal()) { + + PropertiesViewItem *item = new PropertiesViewItem(m_tree); + item->property = p; - item->setText(0, p.name()); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + item->setText(0, p.name()); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + if (m_watchTableModel.data() && m_watchTableModel.data()->isWatchingProperty(p)) { + QFont font = m_tree->font(); + font.setBold(true); + item->setFont(0, font); + } - setPropertyValue(item, p.value(), !p.hasNotifySignal()); - item->setText(2, p.valueTypeName()); + setPropertyValue(item, p.value(), !p.hasNotifySignal()); + + item->setText(2, p.valueTypeName()); + + // binding is set after property value to ensure it is added to the end of the + // list, if the value is a list + if (!p.binding().isEmpty()) { + PropertiesViewItem *binding = new PropertiesViewItem(item, PropertiesViewItem::BindingType); + binding->setText(1, p.binding()); + binding->setForeground(1, Qt::darkGreen); + } - // binding is set after property value to ensure it is added to the end of the - // list, if the value is a list - if (!p.binding().isEmpty()) { - PropertiesViewItem *binding = new PropertiesViewItem(item, PropertiesViewItem::BindingType); - binding->setText(1, p.binding()); - binding->setForeground(1, Qt::darkGreen); } } } @@ -315,6 +335,14 @@ void ObjectPropertiesView::contextMenuEvent(QContextMenuEvent *event) } else { menu.addAction(m_removeWatchAction); } + menu.addSeparator(); + + if (m_showUnwatchableProperties) + m_toggleUnwatchablePropertiesAction->setText(tr("Hide unwatchable properties")); + else + m_toggleUnwatchablePropertiesAction->setText(tr("Show unwatchable properties")); + + menu.addAction(m_toggleUnwatchablePropertiesAction); menu.exec(event->globalPos()); } diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.h b/src/plugins/qmlinspector/components/objectpropertiesview.h index 68d9585116ce8ff73427c99601cb07fb6a0c2d74..9ae22188dd7bd9312c7b9f25eacc5c6906f33a1d 100644 --- a/src/plugins/qmlinspector/components/objectpropertiesview.h +++ b/src/plugins/qmlinspector/components/objectpropertiesview.h @@ -45,12 +45,13 @@ namespace Qml { namespace Internal { class PropertiesViewItem; +class WatchTableModel; class ObjectPropertiesView : public QWidget { Q_OBJECT public: - ObjectPropertiesView(QDeclarativeEngineDebug *client = 0, QWidget *parent = 0); + ObjectPropertiesView(WatchTableModel *watchTableModel, QDeclarativeEngineDebug *client = 0, QWidget *parent = 0); void setEngineDebug(QDeclarativeEngineDebug *client); void clear(); @@ -75,6 +76,8 @@ private slots: void addWatch(); void removeWatch(); + void filterView(const QString &filterText); + void toggleUnwatchableProperties(); private: void toggleWatch(QTreeWidgetItem *item); @@ -89,9 +92,13 @@ private: QAction *m_addWatchAction; QAction *m_removeWatchAction; + QAction *m_toggleUnwatchablePropertiesAction; QTreeWidgetItem *m_clickedItem; + bool m_showUnwatchableProperties; QTreeWidget *m_tree; + QWeakPointer<WatchTableModel> m_watchTableModel; + QDeclarativeDebugObjectReference m_object; }; diff --git a/src/plugins/qmlinspector/components/watchtable.cpp b/src/plugins/qmlinspector/components/watchtable.cpp index f64108c3c614823e082cba0e2f152c5cb2912e1a..8a49c5444f9d62955c7440a4f912669ce843a7b8 100644 --- a/src/plugins/qmlinspector/components/watchtable.cpp +++ b/src/plugins/qmlinspector/components/watchtable.cpp @@ -28,14 +28,18 @@ **************************************************************************/ #include "watchtable.h" -#include <QtCore/qdebug.h> -#include <QtGui/qevent.h> -#include <QtGui/qaction.h> -#include <QtGui/qmenu.h> +#include <QtCore/QEvent> +#include <QtGui/QAction> +#include <QtGui/QMenu> +#include <QMouseEvent> +#include <QApplication> +#include <QCoreApplication> #include <private/qdeclarativedebug_p.h> #include <private/qdeclarativemetatype_p.h> +#include <QtCore/QDebug> + namespace Qml { namespace Internal { @@ -47,7 +51,7 @@ WatchTableModel::WatchTableModel(QDeclarativeEngineDebug *client, QObject *paren : QAbstractTableModel(parent), m_client(client) { - + m_editablePropertyTypes << "qreal" << "bool" << "QString" << "int" << "QVariant" << "QUrl"; } WatchTableModel::~WatchTableModel() @@ -61,7 +65,8 @@ void WatchTableModel::setEngineDebug(QDeclarativeEngineDebug *client) m_client = client; } -void WatchTableModel::addWatch(QDeclarativeDebugWatch *watch, const QString &title) +void WatchTableModel::addWatch(const QDeclarativeDebugObjectReference &object, const QString &propertyType, + QDeclarativeDebugWatch *watch, const QString &title) { QString property; if (qobject_cast<QDeclarativeDebugPropertyWatch *>(watch)) @@ -79,6 +84,9 @@ void WatchTableModel::addWatch(QDeclarativeDebugWatch *watch, const QString &tit e.title = title; e.property = property; e.watch = watch; + e.objectId = object.idString(); + e.objectDebugId = object.debugId(); + e.objectPropertyType = propertyType; m_entities.append(e); @@ -157,31 +165,86 @@ QVariant WatchTableModel::data(const QModelIndex &idx, int role) const if (role == Qt::DisplayRole || role == Qt::EditRole) { return QVariant(m_entities.at(idx.row()).value); + } else if (role == CanEditRole || role == Qt::ForegroundRole) { + const WatchedEntity &entity = m_entities.at(idx.row()); + bool canEdit = entity.objectId.length() > 0 && canEditProperty(entity.objectPropertyType); - } else if(role == Qt::BackgroundRole) { - //return QColor(Qt::green); + if (role == Qt::ForegroundRole) + return canEdit ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground); + + return canEdit; } } return QVariant(); } +bool WatchTableModel::isWatchingProperty(const QDeclarativeDebugPropertyReference &prop) const +{ + foreach (const WatchedEntity &entity, m_entities) { + if (entity.objectDebugId == prop.objectDebugId() && entity.property == prop.name()) + return true; + } + return false; +} + bool WatchTableModel::setData ( const QModelIndex & index, const QVariant & value, int role) { Q_UNUSED(index); Q_UNUSED(value); if (role == Qt::EditRole) { + + if (index.row() >= 0 && index.row() < m_entities.length()) { + WatchedEntity &entity = m_entities[index.row()]; + + qDebug() << entity.property << entity.title << entity.objectId; + if (entity.objectId.length()) { + + QString quoteWrappedValue = value.toString(); + if (addQuotesForData(value)) + quoteWrappedValue = QString("'%1'").arg(quoteWrappedValue); + + QString constructedExpression = entity.objectId + "." + entity.property + "=" + quoteWrappedValue; + qDebug() << "EXPRESSION:" << constructedExpression; + m_client->queryExpressionResult(entity.objectDebugId, constructedExpression, this); + } + } + return true; } return true; } +bool WatchTableModel::canEditProperty(const QString &propertyType) const +{ + return m_editablePropertyTypes.contains(propertyType); +} + +bool WatchTableModel::addQuotesForData(const QVariant &value) const +{ + switch (value.type()) { + case QVariant::String: + case QVariant::Color: + case QVariant::Date: + return true; + default: + break; + } + + return false; +} + Qt::ItemFlags WatchTableModel::flags ( const QModelIndex & index ) const { - if (index.column() == C_VALUE) - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; // Qt::ItemIsEditable | <- disabled for now + Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (index.column() == C_VALUE && index.data(CanEditRole).toBool()) + { + flags |= Qt::ItemIsEditable; + } + - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; + return flags; } void WatchTableModel::watchStateChanged() @@ -220,10 +283,11 @@ void WatchTableModel::togglePropertyWatch(const QDeclarativeDebugObjectReference delete watch; watch = 0; } else { + QString desc = (object.idString().isEmpty() ? QLatin1String("<") + object.className() + QLatin1String(">") : object.idString()) + QLatin1String(".") + property.name(); - addWatch(watch, desc); + addWatch(object, property.valueTypeName(), watch, desc); emit watchCreated(watch); } } @@ -247,7 +311,7 @@ void WatchTableModel::expressionWatchRequested(const QDeclarativeDebugObjectRefe delete watch; watch = 0; } else { - addWatch(watch, expr); + addWatch(obj, "<expression>", watch, expr); emit watchCreated(watch); } } diff --git a/src/plugins/qmlinspector/components/watchtable.h b/src/plugins/qmlinspector/components/watchtable.h index 3ec7583e951608d53b7b554672bed0b45181ef9c..e5bc4be8651e511a8183f4f4278d36b1443ca8e7 100644 --- a/src/plugins/qmlinspector/components/watchtable.h +++ b/src/plugins/qmlinspector/components/watchtable.h @@ -72,6 +72,8 @@ public: QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); + bool isWatchingProperty(const QDeclarativeDebugPropertyReference &prop) const; + signals: void watchCreated(QDeclarativeDebugWatch *watch); void watchRemoved(); @@ -85,7 +87,11 @@ private slots: void watchedValueChanged(const QByteArray &propertyName, const QVariant &value); private: - void addWatch(QDeclarativeDebugWatch *watch, const QString &title); + bool canEditProperty(const QString &propertyType) const; + bool addQuotesForData(const QVariant &value) const; + void addWatch(const QDeclarativeDebugObjectReference &object, const QString &propertyType, + QDeclarativeDebugWatch *watch, const QString &title); + void removeWatch(QDeclarativeDebugWatch *watch); void updateWatch(QDeclarativeDebugWatch *watch, const QVariant &value); @@ -93,12 +99,21 @@ private: struct WatchedEntity { + int objectDebugId; + QString objectId; QString title; QString property; + QString objectPropertyType; QPointer<QDeclarativeDebugWatch> watch; QVariant value; }; + enum DataRoles { + CanEditRole = Qt::UserRole + 1 + + }; + + QStringList m_editablePropertyTypes; QDeclarativeEngineDebug *m_client; QList<WatchedEntity> m_entities; }; diff --git a/src/plugins/qmlinspector/qmlinspector.cpp b/src/plugins/qmlinspector/qmlinspector.cpp index be333299cdb2a4788d7b6e5e7ba013794516b90c..488f74fc22242014bd82d6b4da56d7c622e9e6f0 100644 --- a/src/plugins/qmlinspector/qmlinspector.cpp +++ b/src/plugins/qmlinspector/qmlinspector.cpp @@ -97,7 +97,7 @@ using namespace Qml; namespace Qml { namespace Internal { -class EngineSpinBox : public QSpinBox +class EngineComboBox : public QComboBox { Q_OBJECT public: @@ -107,28 +107,27 @@ public: int id; }; - EngineSpinBox(QWidget *parent = 0); + EngineComboBox(QWidget *parent = 0); void addEngine(int engine, const QString &name); void clearEngines(); protected: - virtual QString textFromValue(int value) const; - virtual int valueFromText(const QString &text) const; + //virtual QString textFromValue(int value) const; + //virtual int valueFromText(const QString &text) const; private: QList<EngineInfo> m_engines; }; -EngineSpinBox::EngineSpinBox(QWidget *parent) - : QSpinBox(parent) +EngineComboBox::EngineComboBox(QWidget *parent) + : QComboBox(parent) { setEnabled(false); - setReadOnly(true); - setRange(0, 0); + setEditable(false); } -void EngineSpinBox::addEngine(int engine, const QString &name) +void EngineComboBox::addEngine(int engine, const QString &name) { EngineInfo info; info.id = engine; @@ -138,31 +137,31 @@ void EngineSpinBox::addEngine(int engine, const QString &name) info.name = name; m_engines << info; - setRange(0, m_engines.count()-1); + addItem(info.name); } -void EngineSpinBox::clearEngines() +void EngineComboBox::clearEngines() { m_engines.clear(); } -QString EngineSpinBox::textFromValue(int value) const -{ - for (int i=0; i<m_engines.count(); ++i) { - if (m_engines[i].id == value) - return m_engines[i].name; - } - return QLatin1String("<None>"); -} - -int EngineSpinBox::valueFromText(const QString &text) const -{ - for (int i=0; i<m_engines.count(); ++i) { - if (m_engines[i].name == text) - return m_engines[i].id; - } - return -1; -} +//QString EngineComboBox::textFromValue(int value) const +//{ +// for (int i=0; i<m_engines.count(); ++i) { +// if (m_engines[i].id == value) +// return m_engines[i].name; +// } +// return QLatin1String("<None>"); +//} + +//int EngineComboBox::valueFromText(const QString &text) const +//{ +// for (int i=0; i<m_engines.count(); ++i) { +// if (m_engines[i].name == text) +// return m_engines[i].id; +// } +// return -1; +//} } // Internal @@ -183,7 +182,7 @@ QmlInspector::QmlInspector(QObject *parent) m_watchTableModel = new Internal::WatchTableModel(0, this); m_objectTreeWidget = new Internal::ObjectTree; - m_propertiesWidget = new Internal::ObjectPropertiesView; + m_propertiesWidget = new Internal::ObjectPropertiesView(m_watchTableModel); m_watchTableView = new Internal::WatchTableView(m_watchTableModel); m_expressionWidget = new Internal::ExpressionQueryWidget(Internal::ExpressionQueryWidget::SeparateEntryMode); // m_frameRateWidget = new Internal::CanvasFrameRate; @@ -346,9 +345,9 @@ void QmlInspector::connectionError() void QmlInspector::createDockWidgets() { - m_engineSpinBox = new Internal::EngineSpinBox; - m_engineSpinBox->setEnabled(false); - connect(m_engineSpinBox, SIGNAL(valueChanged(int)), + m_engineComboBox = new Internal::EngineComboBox; + m_engineComboBox->setEnabled(false); + connect(m_engineComboBox, SIGNAL(currentIndexChanged(int)), SLOT(queryEngineContext(int))); // FancyMainWindow uses widgets' window titles for tab labels @@ -359,7 +358,7 @@ void QmlInspector::createDockWidgets() treeOptionBarLayout->setContentsMargins(5, 0, 5, 0); treeOptionBarLayout->setSpacing(5); treeOptionBarLayout->addWidget(new QLabel(tr("QML engine:"))); - treeOptionBarLayout->addWidget(m_engineSpinBox); + treeOptionBarLayout->addWidget(m_engineComboBox); QWidget *treeWindow = new QWidget; treeWindow->setObjectName(QLatin1String("QmlDebugTree")); @@ -590,7 +589,7 @@ void QmlInspector::reloadEngines() return; } - m_engineSpinBox->setEnabled(false); + m_engineComboBox->setEnabled(false); m_engineQuery = m_client->queryAvailableEngines(this); if (!m_engineQuery->isWaiting()) @@ -602,7 +601,7 @@ void QmlInspector::reloadEngines() void QmlInspector::enginesChanged() { - m_engineSpinBox->clearEngines(); + m_engineComboBox->clearEngines(); QList<QDeclarativeDebugEngineReference> engines = m_engineQuery->engines(); delete m_engineQuery; m_engineQuery = 0; @@ -610,13 +609,13 @@ void QmlInspector::enginesChanged() if (engines.isEmpty()) qWarning("qmldebugger: no engines found!"); - m_engineSpinBox->setEnabled(true); + m_engineComboBox->setEnabled(true); for (int i=0; i<engines.count(); ++i) - m_engineSpinBox->addEngine(engines.at(i).debugId(), engines.at(i).name()); + m_engineComboBox->addEngine(engines.at(i).debugId(), engines.at(i).name()); if (engines.count() > 0) { - m_engineSpinBox->setValue(engines.at(0).debugId()); + m_engineComboBox->setCurrentIndex(engines.at(0).debugId()); queryEngineContext(engines.at(0).debugId()); } } diff --git a/src/plugins/qmlinspector/qmlinspector.h b/src/plugins/qmlinspector/qmlinspector.h index 13be41d8afa22ed60bb61c85cd62d18278fcab73..bab467d89f222f57209aa75328ef5826cac96c59 100644 --- a/src/plugins/qmlinspector/qmlinspector.h +++ b/src/plugins/qmlinspector/qmlinspector.h @@ -64,7 +64,7 @@ namespace Core { namespace Qml { namespace Internal { - class EngineSpinBox; + class EngineComboBox; class InspectorContext; class ObjectTree; class ObjectPropertiesView; @@ -72,7 +72,6 @@ namespace Qml { class WatchTableView; class CanvasFrameRate; class ExpressionQueryWidget; - class EngineSpinBox; } const int MaxConnectionAttempts = 50; @@ -132,7 +131,7 @@ private: Internal::CanvasFrameRate *m_frameRateWidget; Internal::ExpressionQueryWidget *m_expressionWidget; - Internal::EngineSpinBox *m_engineSpinBox; + Internal::EngineComboBox *m_engineComboBox; QDockWidget *m_objectTreeDock; QDockWidget *m_frameRateDock;