forked from qt-creator/qt-creator
UI improvements and functionality fixes to qml inspector
now you can modify expression values after you set a watch on them. doesn't seem to work yet for all cases, but there must be some issues within the qml debug server holding things back.
This commit is contained in:
@@ -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,13 +218,21 @@ void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &obj
|
||||
for (int i=0; i<properties.count(); ++i) {
|
||||
const QDeclarativeDebugPropertyReference &p = properties[i];
|
||||
|
||||
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);
|
||||
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());
|
||||
|
||||
// binding is set after property value to ensure it is added to the end of the
|
||||
@@ -224,6 +242,8 @@ void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &obj
|
||||
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());
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
if (index.column() == C_VALUE && index.data(CanEditRole).toBool())
|
||||
{
|
||||
flags |= Qt::ItemIsEditable;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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>");
|
||||
}
|
||||
//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 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;
|
||||
}
|
||||
//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());
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user