Commit 9b060071 authored by Lasse Holmstedt's avatar Lasse Holmstedt

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.
parent 0a643a19
......@@ -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());
}
......
......@@ -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;
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);
}
}
......
......@@ -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>");
}
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());
}
}
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment