From f303d6e3a44de30b9b1dc869c9a54c60cb383f8a Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 14 Oct 2009 14:31:18 +1000 Subject: Split the various debugger widgets out into their own files. The debugger interface remains unchanged. --- tools/qmldebugger/engine.cpp | 401 +++-------------------------- tools/qmldebugger/engine.h | 43 +--- tools/qmldebugger/main.cpp | 175 ++----------- tools/qmldebugger/objectpropertiesview.cpp | 166 ++++++++++++ tools/qmldebugger/objectpropertiesview.h | 47 ++++ tools/qmldebugger/objecttree.cpp | 168 ++++++++++++ tools/qmldebugger/objecttree.h | 55 ++++ tools/qmldebugger/propertyview.cpp | 117 --------- tools/qmldebugger/propertyview.h | 40 --- tools/qmldebugger/qmldebugger.cpp | 125 +++++++++ tools/qmldebugger/qmldebugger.h | 47 ++++ tools/qmldebugger/qmldebugger.pri | 22 ++ tools/qmldebugger/qmldebugger.pro | 16 +- tools/qmldebugger/watchtable.cpp | 299 +++++++++++++++++++++ tools/qmldebugger/watchtable.h | 110 ++++++++ tools/qmldebugger/watchtablemodel.cpp | 186 ------------- tools/qmldebugger/watchtablemodel.h | 61 ----- 17 files changed, 1103 insertions(+), 975 deletions(-) create mode 100644 tools/qmldebugger/objectpropertiesview.cpp create mode 100644 tools/qmldebugger/objectpropertiesview.h create mode 100644 tools/qmldebugger/objecttree.cpp create mode 100644 tools/qmldebugger/objecttree.h delete mode 100644 tools/qmldebugger/propertyview.cpp delete mode 100644 tools/qmldebugger/propertyview.h create mode 100644 tools/qmldebugger/qmldebugger.cpp create mode 100644 tools/qmldebugger/qmldebugger.h create mode 100644 tools/qmldebugger/qmldebugger.pri create mode 100644 tools/qmldebugger/watchtable.cpp create mode 100644 tools/qmldebugger/watchtable.h delete mode 100644 tools/qmldebugger/watchtablemodel.cpp delete mode 100644 tools/qmldebugger/watchtablemodel.h diff --git a/tools/qmldebugger/engine.cpp b/tools/qmldebugger/engine.cpp index 321f5e0..fac10f3 100644 --- a/tools/qmldebugger/engine.cpp +++ b/tools/qmldebugger/engine.cpp @@ -1,144 +1,21 @@ -#include "engine.h" -#include "propertyview.h" -#include "watchtablemodel.h" -#include -#include #include #include -#include -#include -#include #include #include -#include -#include -#include -#include #include -#include -#include + #include +#include #include #include #include -QT_BEGIN_NAMESPACE - - -class QmlObjectTree : public QTreeWidget -{ - Q_OBJECT -public: - enum AdditionalRoles { - ContextIdRole = Qt::UserRole + 1 - }; - - QmlObjectTree(QWidget *parent = 0); - - QTreeWidgetItem *findItemByObjectId(int debugId) const; - -signals: - void addExpressionWatch(int debugId, const QString &); - -protected: - virtual void mousePressEvent(QMouseEvent *); - -private: - QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const; -}; - -QmlObjectTree::QmlObjectTree(QWidget *parent) -: QTreeWidget(parent) -{ -} - -QTreeWidgetItem *QmlObjectTree::findItemByObjectId(int debugId) const -{ - for (int i=0; idata(0, Qt::UserRole).toInt() == debugId) - return item; - - QTreeWidgetItem *child; - for (int i=0; ichildCount(); i++) { - child = findItem(item->child(i), debugId); - if (child) - return child; - } - - return 0; -} - -void QmlObjectTree::mousePressEvent(QMouseEvent *me) -{ - QTreeWidget::mousePressEvent(me); - if (!currentItem()) - return; - if(me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) { - QAction action(tr("Add watch..."), 0); - QList actions; - actions << &action; - int debugId = currentItem()->data(0, Qt::UserRole).toInt(); - if (debugId >= 0 && QMenu::exec(actions, me->globalPos())) { - bool ok = false; - QString watch = QInputDialog::getText(this, tr("Watch expression"), - tr("Expression:"), QLineEdit::Normal, QString(), &ok); - if (ok && !watch.isEmpty()) - emit addExpressionWatch(debugId, watch); - } - } -} - - -class WatchTableHeaderView : public QHeaderView -{ - Q_OBJECT -public: - WatchTableHeaderView(QTableView *parent); - -signals: - void stopWatching(int column); - -protected: - void mousePressEvent(QMouseEvent *me); - -private: - QTableView *m_table; -}; - -WatchTableHeaderView::WatchTableHeaderView(QTableView *parent) - : QHeaderView(Qt::Horizontal, parent), m_table(parent) -{ - QObject::connect(this, SIGNAL(sectionClicked(int)), - m_table, SLOT(selectColumn(int))); - setClickable(true); -} +#include "engine.h" +#include "objectpropertiesview.h" +#include "objecttree.h" +#include "watchtable.h" -void WatchTableHeaderView::mousePressEvent(QMouseEvent *me) -{ - QHeaderView::mousePressEvent(me); - - if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) { - int col = logicalIndexAt(me->pos()); - if (col >= 0) { - m_table->selectColumn(col); - QAction action(tr("Stop watching"), 0); - QList actions; - actions << &action; - if (QMenu::exec(actions, me->globalPos())) - emit stopWatching(col); - } - } -} +QT_BEGIN_NAMESPACE class DebuggerEngineItem : public QObject @@ -159,14 +36,12 @@ private: int m_engineId; }; -EnginePane::EnginePane(QmlDebugConnection *client, QWidget *parent) -: QWidget(parent), m_client(client), m_engines(0), m_context(0), m_object(0), m_watchedObject(0), m_watchTableModel(0) +EnginePane::EnginePane(QmlDebugConnection *conn, QWidget *parent) +: QWidget(parent), m_client(new QmlEngineDebug(conn, this)), m_engines(0), m_context(0), m_watchTableModel(0) { - QVBoxLayout *layout = new QVBoxLayout; + QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); - setLayout(layout); - QFile enginesFile(":/engines.qml"); enginesFile.open(QFile::ReadOnly); Q_ASSERT(enginesFile.isOpen()); @@ -187,30 +62,34 @@ EnginePane::EnginePane(QmlDebugConnection *client, QWidget *parent) QSplitter *splitter = new QSplitter; - m_objTree = new QmlObjectTree(this); - m_objTree->setHeaderHidden(true); - connect(m_objTree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *))); - connect(m_objTree, SIGNAL(addExpressionWatch(int,QString)), this, SLOT(addExpressionWatch(int,QString))); - splitter->addWidget(m_objTree); + m_objTree = new ObjectTree(m_client, this); + m_propertiesView = new ObjectPropertiesView(m_client); + m_watchTableModel = new WatchTableModel(m_client, this); + + m_watchTableView = new WatchTableView(m_watchTableModel); + m_watchTableView->setModel(m_watchTableModel); + WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTableModel); + m_watchTableView->setHorizontalHeader(header); + + connect(m_objTree, SIGNAL(objectSelected(QmlDebugObjectReference)), + m_propertiesView, SLOT(reload(QmlDebugObjectReference))); + connect(m_objTree, SIGNAL(expressionWatchRequested(QmlDebugObjectReference,QString)), + m_watchTableModel, SLOT(expressionWatchRequested(QmlDebugObjectReference,QString))); + + connect(m_propertiesView, SIGNAL(activated(QmlDebugObjectReference,QmlDebugPropertyReference)), + m_watchTableModel, SLOT(togglePropertyWatch(QmlDebugObjectReference,QmlDebugPropertyReference))); - m_propView = new PropertyView(this); - connect(m_propView, SIGNAL(propertyActivated(QmlDebugPropertyReference)), - this, SLOT(propertyActivated(QmlDebugPropertyReference))); + connect(m_watchTableModel, SIGNAL(watchCreated(QmlDebugWatch*)), + m_propertiesView, SLOT(watchCreated(QmlDebugWatch*))); - m_watchTableModel = new WatchTableModel(this); - m_watchTable = new QTableView(this); - m_watchTable->setModel(m_watchTableModel); - QObject::connect(m_watchTable, SIGNAL(activated(QModelIndex)), - this, SLOT(watchedItemActivated(QModelIndex))); - WatchTableHeaderView *header = new WatchTableHeaderView(m_watchTable); - m_watchTable->setHorizontalHeader(header); - QObject::connect(header, SIGNAL(stopWatching(int)), - this, SLOT(stopWatching(int))); + connect(m_watchTableView, SIGNAL(objectActivated(int)), + m_objTree, SLOT(selectObject(int))); m_tabs = new QTabWidget(this); - m_tabs->addTab(m_propView, tr("Properties")); - m_tabs->addTab(m_watchTable, tr("Watched")); + m_tabs->addTab(m_propertiesView, tr("Properties")); + m_tabs->addTab(m_watchTableView, tr("Watched")); + splitter->addWidget(m_objTree); splitter->addWidget(m_tabs); splitter->setStretchFactor(1, 2); layout->addWidget(splitter); @@ -222,128 +101,6 @@ void EnginePane::engineSelected(int id) queryContext(id); } -void EnginePane::itemClicked(QTreeWidgetItem *item) -{ - m_propView->clear(); - - if (m_object) { - delete m_object; - m_object = 0; - } - - m_object = m_client.queryObjectRecursive(QmlDebugObjectReference(item->data(0, Qt::UserRole).toInt()), this); - if (!m_object->isWaiting()) - showProperties(); - else - QObject::connect(m_object, SIGNAL(stateChanged(State)), - this, SLOT(showProperties())); -} - -void EnginePane::showProperties() -{ - QmlDebugObjectReference obj = m_object->object(); - m_propView->setObject(obj); - - if (m_watchedObject) { - m_client.removeWatch(m_watchedObject); - delete m_watchedObject; - m_watchedObject = 0; - } - - QmlDebugWatch *watch = m_client.addWatch(obj, this); - if (watch->state() != QmlDebugWatch::Dead) { - m_watchedObject = watch; - QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)), - this, SLOT(valueChanged(QByteArray,QVariant))); - } - - delete m_object; m_object = 0; -} - -void EnginePane::addExpressionWatch(int debugId, const QString &expr) -{ - QmlDebugWatch *watch = m_client.addWatch(QmlDebugObjectReference(debugId), expr, this); - - if (watch->state() != QmlDebugWatch::Dead) { - QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)), - this, SLOT(valueChanged(QByteArray,QVariant))); - m_watchTableModel->addWatch(watch, expr); - m_watchTable->resizeColumnsToContents(); - } -} - -void EnginePane::valueChanged(const QByteArray &propertyName, const QVariant &value) -{ - QmlDebugWatch *watch = qobject_cast(sender()); - - m_watchTableModel->updateWatch(watch, value); - - if (!propertyName.isEmpty()) { - if (watch->objectDebugId() == m_propView->object().debugId()) - m_propView->updateProperty(propertyName, value); - } -} - -void EnginePane::propertyActivated(const QmlDebugPropertyReference &property) -{ - PropertyView *view = qobject_cast(sender()); - if (!view) - return; - - QmlDebugObjectReference object = view->object(); - QmlDebugWatch *watch = m_watchTableModel->findWatch(object.debugId(), property.name()); - if (watch) { - m_client.removeWatch(watch); - delete watch; - watch = 0; - } else { - QmlDebugWatch *watch = m_client.addWatch(property, this); - if (watch->state() != QmlDebugWatch::Dead) { - QObject::connect(watch, SIGNAL(stateChanged(State)), - this, SLOT(propertyWatchStateChanged())); - QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)), - this, SLOT(valueChanged(QByteArray,QVariant))); - QString desc = property.name() - + QLatin1String(" on\n") - + object.className() - + QLatin1String(": ") - + (object.name().isEmpty() ? QLatin1String("") : object.name()); - m_watchTableModel->addWatch(watch, desc); - m_watchTable->resizeColumnsToContents(); - } - } -} - -void EnginePane::propertyWatchStateChanged() -{ - QmlDebugPropertyWatch *watch = qobject_cast(sender()); - if (watch && watch->objectDebugId() == m_propView->object().debugId()) - m_propView->setPropertyIsWatched(watch->name(), watch->state() == QmlDebugWatch::Active); -} - -void EnginePane::stopWatching(int column) -{ - QmlDebugWatch *watch = m_watchTableModel->findWatch(column); - if (watch) { - m_client.removeWatch(watch); - delete watch; - watch = 0; - } -} - -void EnginePane::watchedItemActivated(const QModelIndex &index) -{ - QmlDebugWatch *watch = m_watchTableModel->findWatch(index.column()); - if (!watch) - return; - QTreeWidgetItem *item = m_objTree->findItemByObjectId(watch->objectDebugId()); - if (item) { - m_objTree->setCurrentItem(item); - m_objTree->scrollToItem(item); - item->setExpanded(true); - } -} - void EnginePane::queryContext(int id) { if (m_context) { @@ -351,88 +108,30 @@ void EnginePane::queryContext(int id) m_context = 0; } - m_context = m_client.queryRootContexts(QmlDebugEngineReference(id), this); + m_context = m_client->queryRootContexts(QmlDebugEngineReference(id), this); if (!m_context->isWaiting()) contextChanged(); else - QObject::connect(m_context, SIGNAL(stateChanged(State)), + QObject::connect(m_context, SIGNAL(stateChanged(State)), this, SLOT(contextChanged())); } void EnginePane::contextChanged() { - dump(m_context->rootContext(), 0); + //dump(m_context->rootContext(), 0); + foreach (const QmlDebugObjectReference &object, m_context->rootContext().objects()) - fetchObject(object.debugId()); + m_objTree->reload(object.debugId()); delete m_context; m_context = 0; } -void EnginePane::dump(const QmlDebugContextReference &ctxt, int ind) -{ - QByteArray indent(ind * 4, ' '); - qWarning().nospace() << indent.constData() << ctxt.debugId() << " " - << qPrintable(ctxt.name()); - - for (int ii = 0; ii < ctxt.contexts().count(); ++ii) - dump(ctxt.contexts().at(ii), ind + 1); - - for (int ii = 0; ii < ctxt.objects().count(); ++ii) - dump(ctxt.objects().at(ii), ind); -} - -void EnginePane::dump(const QmlDebugObjectReference &obj, int ind) -{ - QByteArray indent(ind * 4, ' '); - qWarning().nospace() << indent.constData() << qPrintable(obj.className()) - << " " << qPrintable(obj.name()) << " " - << obj.debugId(); - - for (int ii = 0; ii < obj.children().count(); ++ii) - dump(obj.children().at(ii), ind + 1); -} - - -void EnginePane::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent) -{ - if (!parent) - m_objTree->clear(); - - QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(m_objTree); - item->setText(0, obj.className()); - item->setData(0, Qt::UserRole, obj.debugId()); - item->setData(0, QmlObjectTree::ContextIdRole, obj.contextDebugId()); - - if (parent && obj.contextDebugId() >= 0 - && obj.contextDebugId() != parent->data(0, QmlObjectTree::ContextIdRole).toInt()) { - QmlDebugFileReference source = obj.source(); - if (!source.url().isEmpty()) { - QString toolTipString = QLatin1String("URL: ") + source.url().toString(); - item->setToolTip(0, toolTipString); - } - item->setForeground(0, QColor("orange")); - } else { - item->setExpanded(true); - } - - if (obj.contextDebugId() < 0) - item->setForeground(0, Qt::lightGray); - - for (int ii = 0; ii < obj.children().count(); ++ii) - buildTree(obj.children().at(ii), item); -} - void EnginePane::refreshEngines() { if (m_engines) return; - QList watches = m_watchTableModel->watches(); - for (int i=0; iqueryAvailableEngines(this); if (!m_engines->isWaiting()) enginesChanged(); else @@ -462,28 +161,6 @@ void EnginePane::enginesChanged() engineSelected(qobject_cast(m_engineItems.at(0))->engineId()); } -void EnginePane::fetchObject(int id) -{ - if (m_object) { - delete m_object; - m_object = 0; - } - - m_object = m_client.queryObjectRecursive(QmlDebugObjectReference(id), this); - if (!m_object->isWaiting()) - objectFetched(); - else - QObject::connect(m_object, SIGNAL(stateChanged(State)), - this, SLOT(objectFetched())); -} - -void EnginePane::objectFetched() -{ - dump(m_object->object(), 0); - buildTree(m_object->object(), 0); - delete m_object; m_object = 0; -} - #include "engine.moc" diff --git a/tools/qmldebugger/engine.h b/tools/qmldebugger/engine.h index c7707ed..8e8c0f2 100644 --- a/tools/qmldebugger/engine.h +++ b/tools/qmldebugger/engine.h @@ -10,21 +10,15 @@ QT_BEGIN_NAMESPACE +class ObjectPropertiesView; class QmlDebugConnection; class QmlDebugPropertyReference; class QmlDebugWatch; -class QmlObjectTree; -class EngineClientPlugin; -class PropertyView; +class ObjectTree; class WatchTableModel; -class QLineEdit; -class QModelIndex; -class QTreeWidget; -class QTreeWidgetItem; +class WatchTableView; + class QTabWidget; -class QTableWidget; -class QTableView; -class QTableWidgetItem; class EnginePane : public QWidget { @@ -41,42 +35,23 @@ private slots: void queryContext(int); void contextChanged(); - void fetchObject(int); - void objectFetched(); - void engineSelected(int); - void itemClicked(QTreeWidgetItem *); - void showProperties(); - void addExpressionWatch(int debugId, const QString &expr); - - void valueChanged(const QByteArray &property, const QVariant &value); - - void propertyActivated(const QmlDebugPropertyReference &property); - void propertyWatchStateChanged(); - void watchedItemActivated(const QModelIndex &index); - void stopWatching(int column); - private: - void dump(const QmlDebugContextReference &, int); - void dump(const QmlDebugObjectReference &, int); - void buildTree(const QmlDebugObjectReference &, QTreeWidgetItem *parent); - - QmlEngineDebug m_client; + QmlEngineDebug *m_client; QmlDebugEnginesQuery *m_engines; QmlDebugRootContextQuery *m_context; - QmlDebugObjectQuery *m_object; - QmlObjectTree *m_objTree; + ObjectTree *m_objTree; QTabWidget *m_tabs; - PropertyView *m_propView; - QTableView *m_watchTable; + WatchTableView *m_watchTableView; QmlView *m_engineView; QList m_engineItems; - QmlDebugWatch *m_watchedObject; WatchTableModel *m_watchTableModel; + + ObjectPropertiesView *m_propertiesView; }; QT_END_NAMESPACE diff --git a/tools/qmldebugger/main.cpp b/tools/qmldebugger/main.cpp index ccd3761..c9983cd 100644 --- a/tools/qmldebugger/main.cpp +++ b/tools/qmldebugger/main.cpp @@ -1,154 +1,6 @@ -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include "canvasframerate.h" -#include "engine.h" -#include -#include -#include -#include -#include -#include -class Shell : public QWidget -{ -Q_OBJECT -public: - Shell(QWidget * = 0); - - void setHost(const QString &host); - void setPort(quint16 port); - void showEngineTab(); - -public slots: - void connectToHost(); - void disconnectFromHost(); - -private slots: - void connectionStateChanged(); - -private: - QmlDebugConnection client; - - QLabel *m_connectionState; - QLineEdit *m_host; - QSpinBox *m_port; - QPushButton *m_connectButton; - QPushButton *m_disconnectButton; - - EnginePane *m_enginePane; - QTabWidget *m_tabs; -}; - -Shell::Shell(QWidget *parent) -: QWidget(parent) -{ - QVBoxLayout *layout = new QVBoxLayout; - setLayout(layout); - - - QHBoxLayout *connectLayout = new QHBoxLayout; - layout->addLayout(connectLayout); - connectLayout->addStretch(2); - - m_connectionState = new QLabel(this); - connectLayout->addWidget(m_connectionState); - m_host = new QLineEdit(this); - m_host->setText("127.0.0.1"); - connectLayout->addWidget(m_host); - m_port = new QSpinBox(this); - m_port->setMinimum(1024); - m_port->setMaximum(20000); - m_port->setValue(3768); - connectLayout->addWidget(m_port); - m_connectButton = new QPushButton(tr("Connect"), this); - QObject::connect(m_connectButton, SIGNAL(clicked()), - this, SLOT(connectToHost())); - connectLayout->addWidget(m_connectButton); - m_disconnectButton = new QPushButton(tr("Disconnect"), this); - QObject::connect(m_disconnectButton, SIGNAL(clicked()), - this, SLOT(disconnectFromHost())); - m_disconnectButton->setEnabled(false); - connectLayout->addWidget(m_disconnectButton); - - m_tabs = new QTabWidget(this); - layout->addWidget(m_tabs); - - CanvasFrameRate *cfr = new CanvasFrameRate(&client, this); - m_tabs->addTab(cfr, tr("Frame Rate")); - - m_enginePane = new EnginePane(&client, this); - m_tabs->addTab(m_enginePane, tr("QML Engine")); - - QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(connectionStateChanged())); - connectionStateChanged(); -} - -void Shell::setHost(const QString &host) -{ - m_host->setText(host); -} - -void Shell::setPort(quint16 port) -{ - m_port->setValue(port); -} - -void Shell::showEngineTab() -{ - m_tabs->setCurrentWidget(m_enginePane); -} - -void Shell::connectionStateChanged() -{ - switch (client.state()) { - default: - case QAbstractSocket::UnconnectedState: - m_connectionState->setText(tr("Disconnected")); - m_connectButton->setEnabled(true); - m_disconnectButton->setEnabled(false); - break; - case QAbstractSocket::HostLookupState: - m_connectionState->setText(tr("Resolving")); - m_connectButton->setEnabled(false); - m_disconnectButton->setEnabled(true); - break; - case QAbstractSocket::ConnectingState: - m_connectionState->setText(tr("Connecting")); - m_connectButton->setEnabled(false); - m_disconnectButton->setEnabled(true); - break; - case QAbstractSocket::ConnectedState: - m_connectionState->setText(tr("Connected")); - m_connectButton->setEnabled(false); - m_disconnectButton->setEnabled(true); - - QTimer::singleShot(0, m_enginePane, SLOT(refreshEngines())); - break; - case QAbstractSocket::ClosingState: - m_connectionState->setText(tr("Closing")); - m_connectButton->setEnabled(false); - m_disconnectButton->setEnabled(false); - break; - } -} - -void Shell::connectToHost() -{ - client.connectToHost(m_host->text(), m_port->value()); -} - -void Shell::disconnectFromHost() -{ - client.disconnectFromHost(); -} +#include "qmldebugger.h" int main(int argc, char ** argv) { @@ -156,24 +8,27 @@ int main(int argc, char ** argv) QStringList args = app.arguments(); - Shell shell; + QmlDebugger win; if (args.contains("--engine")) - shell.showEngineTab(); + win.showEngineTab(); - if (args.count() > 1 && args.at(1).contains(':')) { - QStringList hostAndPort = args.at(1).split(':'); + for (int i=0; i +#include + +#include +#include +#include + +#include "objectpropertiesview.h" + +QT_BEGIN_NAMESPACE + +class PropertiesViewItem : public QObject, public QTreeWidgetItem +{ + Q_OBJECT +public: + PropertiesViewItem(QTreeWidget *widget); + PropertiesViewItem(QTreeWidgetItem *parent); + + QmlDebugPropertyReference property; +}; + +PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget) +: QTreeWidgetItem(widget) +{ +} + +PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent) +: QTreeWidgetItem(parent) +{ +} + +ObjectPropertiesView::ObjectPropertiesView(QmlEngineDebug *client, QWidget *parent) + : QWidget(parent), + m_client(client), + m_query(0), + m_watch(0) +{ + QVBoxLayout *layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + setLayout(layout); + + m_tree = new QTreeWidget(this); + m_tree->setExpandsOnDoubleClick(false); + m_tree->setHeaderLabels(QStringList() << tr("Property") << tr("Value")); + QObject::connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), + this, SLOT(itemActivated(QTreeWidgetItem *))); + + m_tree->setColumnCount(2); + + layout->addWidget(m_tree); +} + +void ObjectPropertiesView::reload(const QmlDebugObjectReference &obj) +{ + m_query = m_client->queryObjectRecursive(obj, this); + if (!m_query->isWaiting()) + queryFinished(); + else + QObject::connect(m_query, SIGNAL(stateChanged(State)), + this, SLOT(queryFinished())); +} + +void ObjectPropertiesView::queryFinished() +{ + if (m_watch) { + m_client->removeWatch(m_watch); + delete m_watch; + m_watch = 0; + } + + QmlDebugObjectReference obj = m_query->object(); + + QmlDebugWatch *watch = m_client->addWatch(obj, this); + if (watch->state() != QmlDebugWatch::Dead) { + m_watch = watch; + QObject::connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)), + this, SLOT(valueChanged(QByteArray,QVariant))); + } + + delete m_query; + m_query = 0; + + setObject(obj); +} + +void ObjectPropertiesView::setObject(const QmlDebugObjectReference &object) +{ + m_object = object; + m_tree->clear(); + + QList properties = object.properties(); + for (int i=0; iproperty = p; + + item->setText(0, p.name()); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + if (!p.hasNotifySignal()) + item->setForeground(0, Qt::lightGray); + + if (!p.binding().isEmpty()) { + PropertiesViewItem *binding = new PropertiesViewItem(item); + binding->setText(1, p.binding()); + binding->setForeground(1, Qt::darkGreen); + } + + item->setExpanded(true); + } + + m_tree->resizeColumnToContents(0); +} + +void ObjectPropertiesView::watchCreated(QmlDebugWatch *watch) +{ + if (watch->objectDebugId() == m_object.debugId() + && qobject_cast(watch)) { + connect(watch, SIGNAL(stateChanged(State)), SLOT(watchStateChanged())); + setWatched(qobject_cast(watch)->name(), true); + } +} + +void ObjectPropertiesView::watchStateChanged() +{ + QmlDebugWatch *watch = qobject_cast(sender()); + + if (watch->objectDebugId() == m_object.debugId() + && qobject_cast(watch) + && watch->state() == QmlDebugWatch::Inactive) { + setWatched(qobject_cast(watch)->name(), false); + } +} + +void ObjectPropertiesView::setWatched(const QString &property, bool watched) +{ + for (int i=0; itopLevelItemCount(); i++) { + PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); + if (item->property.name() == property && item->property.hasNotifySignal()) { + QFont font = m_tree->font(); + font.setBold(watched); + item->setFont(0, font); + } + } +} + +void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant &value) +{ + for (int i=0; itopLevelItemCount(); i++) { + PropertiesViewItem *item = static_cast(m_tree->topLevelItem(i)); + if (item->property.name() == name) + item->setText(1, value.toString()); + } +} + +void ObjectPropertiesView::itemActivated(QTreeWidgetItem *i) +{ + PropertiesViewItem *item = static_cast(i); + if (!item->property.name().isEmpty() && item->property.hasNotifySignal()) + emit activated(m_object, item->property); +} + +QT_END_NAMESPACE + +#include "objectpropertiesview.moc" diff --git a/tools/qmldebugger/objectpropertiesview.h b/tools/qmldebugger/objectpropertiesview.h new file mode 100644 index 0000000..0f72ff4 --- /dev/null +++ b/tools/qmldebugger/objectpropertiesview.h @@ -0,0 +1,47 @@ +#ifndef PROPERTIESTABLEMODEL_H +#define PROPERTIESTABLEMODEL_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QTreeWidget; +class QTreeWidgetItem; + +class ObjectPropertiesView : public QWidget +{ + Q_OBJECT +public: + ObjectPropertiesView(QmlEngineDebug *client, QWidget *parent = 0); + +signals: + void activated(const QmlDebugObjectReference &, const QmlDebugPropertyReference &); + +public slots: + void reload(const QmlDebugObjectReference &); + void watchCreated(QmlDebugWatch *); + +private slots: + void queryFinished(); + void watchStateChanged(); + void valueChanged(const QByteArray &name, const QVariant &value); + void itemActivated(QTreeWidgetItem *i); + +private: + void setObject(const QmlDebugObjectReference &object); + void setWatched(const QString &property, bool watched); + + QmlEngineDebug *m_client; + QmlDebugObjectQuery *m_query; + QmlDebugWatch *m_watch; + + QTreeWidget *m_tree; + QmlDebugObjectReference m_object; +}; + + +QT_END_NAMESPACE + +#endif diff --git a/tools/qmldebugger/objecttree.cpp b/tools/qmldebugger/objecttree.cpp new file mode 100644 index 0000000..f398987 --- /dev/null +++ b/tools/qmldebugger/objecttree.cpp @@ -0,0 +1,168 @@ +#include +#include +#include + +#include + +#include +#include +#include + +#include "objecttree.h" + +Q_DECLARE_METATYPE(QmlDebugObjectReference) + +ObjectTree::ObjectTree(QmlEngineDebug *client, QWidget *parent) + : QTreeWidget(parent), + m_client(client), + m_query(0) +{ + setHeaderHidden(true); + + connect(this, SIGNAL(itemClicked(QTreeWidgetItem *, int)), + this, SLOT(handleItemClicked(QTreeWidgetItem *))); +} + +void ObjectTree::reload(int objectDebugId) +{ + if (m_query) { + delete m_query; + m_query = 0; + } + + m_query = m_client->queryObjectRecursive(QmlDebugObjectReference(objectDebugId), this); + if (!m_query->isWaiting()) + objectFetched(); + else + QObject::connect(m_query, SIGNAL(stateChanged(State)), + this, SLOT(objectFetched())); +} + +void ObjectTree::selectObject(int debugId) +{ + QTreeWidgetItem *item = findItemByObjectId(debugId); + if (item) { + setCurrentItem(item); + scrollToItem(item); + item->setExpanded(true); + } +} + +void ObjectTree::objectFetched() +{ + dump(m_query->object(), 0); + buildTree(m_query->object(), 0); + + delete m_query; + m_query = 0; +} + +void ObjectTree::handleItemClicked(QTreeWidgetItem *item) +{ + QmlDebugObjectReference obj = item->data(0, Qt::UserRole).value(); + if (obj.debugId() < 0) { + qWarning("QML Object Tree: bad object id"); + return; + } + emit objectSelected(obj); +} + +void ObjectTree::buildTree(const QmlDebugObjectReference &obj, QTreeWidgetItem *parent) +{ + if (!parent) + clear(); + + QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this); + item->setText(0, obj.className()); + item->setData(0, Qt::UserRole, qVariantFromValue(obj)); + item->setData(0, ObjectTree::ContextIdRole, obj.contextDebugId()); + + if (parent && obj.contextDebugId() >= 0 + && obj.contextDebugId() != parent->data(0, ObjectTree::ContextIdRole).toInt()) { + QmlDebugFileReference source = obj.source(); + if (!source.url().isEmpty()) { + QString toolTipString = QLatin1String("URL: ") + source.url().toString(); + item->setToolTip(0, toolTipString); + } + item->setForeground(0, QColor("orange")); + } else { + item->setExpanded(true); + } + + if (obj.contextDebugId() < 0) + item->setForeground(0, Qt::lightGray); + + for (int ii = 0; ii < obj.children().count(); ++ii) + buildTree(obj.children().at(ii), item); +} + +void ObjectTree::dump(const QmlDebugContextReference &ctxt, int ind) +{ + QByteArray indent(ind * 4, ' '); + qWarning().nospace() << indent.constData() << ctxt.debugId() << " " + << qPrintable(ctxt.name()); + + for (int ii = 0; ii < ctxt.contexts().count(); ++ii) + dump(ctxt.contexts().at(ii), ind + 1); + + for (int ii = 0; ii < ctxt.objects().count(); ++ii) + dump(ctxt.objects().at(ii), ind); +} + +void ObjectTree::dump(const QmlDebugObjectReference &obj, int ind) +{ + QByteArray indent(ind * 4, ' '); + qWarning().nospace() << indent.constData() << qPrintable(obj.className()) + << " " << qPrintable(obj.name()) << " " + << obj.debugId(); + + for (int ii = 0; ii < obj.children().count(); ++ii) + dump(obj.children().at(ii), ind + 1); +} + +QTreeWidgetItem *ObjectTree::findItemByObjectId(int debugId) const +{ + for (int i=0; idata(0, Qt::UserRole).value().debugId() == debugId) + return item; + + QTreeWidgetItem *child; + for (int i=0; ichildCount(); i++) { + child = findItem(item->child(i), debugId); + if (child) + return child; + } + + return 0; +} + +void ObjectTree::mousePressEvent(QMouseEvent *me) +{ + QTreeWidget::mousePressEvent(me); + if (!currentItem()) + return; + if(me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) { + QAction action(tr("Add watch..."), 0); + QList actions; + actions << &action; + QmlDebugObjectReference obj = + currentItem()->data(0, Qt::UserRole).value(); + if (QMenu::exec(actions, me->globalPos())) { + bool ok = false; + QString watch = QInputDialog::getText(this, tr("Watch expression"), + tr("Expression:"), QLineEdit::Normal, QString(), &ok); + if (ok && !watch.isEmpty()) + emit expressionWatchRequested(obj, watch); + } + } +} diff --git a/tools/qmldebugger/objecttree.h b/tools/qmldebugger/objecttree.h new file mode 100644 index 0000000..a924ec5 --- /dev/null +++ b/tools/qmldebugger/objecttree.h @@ -0,0 +1,55 @@ +#ifndef OBJECTTREE_H +#define OBJECTTREE_H + +#include + +QT_BEGIN_NAMESPACE + +class QTreeWidgetItem; + +class QmlEngineDebug; +class QmlDebugObjectReference; +class QmlDebugObjectQuery; +class QmlDebugContextReference; + + +class ObjectTree : public QTreeWidget +{ + Q_OBJECT +public: + enum AdditionalRoles { + ContextIdRole = Qt::UserRole + 1 + }; + + ObjectTree(QmlEngineDebug *client, QWidget *parent = 0); + +signals: + void objectSelected(const QmlDebugObjectReference &); + void expressionWatchRequested(const QmlDebugObjectReference &, const QString &); + +public slots: + void reload(int objectDebugId); + void selectObject(int debugId); + +protected: + virtual void mousePressEvent(QMouseEvent *); + +private slots: + void objectFetched(); + void handleItemClicked(QTreeWidgetItem *); + +private: + QTreeWidgetItem *findItemByObjectId(int debugId) const; + QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const; + void dump(const QmlDebugContextReference &, int); + void dump(const QmlDebugObjectReference &, int); + void buildTree(const QmlDebugObjectReference &, QTreeWidgetItem *parent); + + QmlEngineDebug *m_client; + QmlDebugObjectQuery *m_query; +}; + +QT_END_NAMESPACE + + +#endif diff --git a/tools/qmldebugger/propertyview.cpp b/tools/qmldebugger/propertyview.cpp deleted file mode 100644 index 44e406b..0000000 --- a/tools/qmldebugger/propertyview.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "propertyview.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE - -PropertyView::PropertyView(QWidget *parent) -: QWidget(parent), m_tree(0) -{ - QVBoxLayout *layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(0); - setLayout(layout); - - m_tree = new QTreeWidget(this); - m_tree->setExpandsOnDoubleClick(false); - m_tree->setHeaderLabels(QStringList() << tr("Property") << tr("Value")); - QObject::connect(m_tree, SIGNAL(itemActivated(QTreeWidgetItem *, int)), - this, SLOT(itemActivated(QTreeWidgetItem *))); - - m_tree->setColumnCount(2); - - layout->addWidget(m_tree); -} - -class PropertyViewItem : public QObject, public QTreeWidgetItem -{ - Q_OBJECT -public: - PropertyViewItem(QTreeWidget *widget); - PropertyViewItem(QTreeWidgetItem *parent); - - QmlDebugPropertyReference property; -}; - -PropertyViewItem::PropertyViewItem(QTreeWidget *widget) -: QTreeWidgetItem(widget) -{ -} - -PropertyViewItem::PropertyViewItem(QTreeWidgetItem *parent) -: QTreeWidgetItem(parent) -{ -} - - -void PropertyView::setObject(const QmlDebugObjectReference &object) -{ - m_object = object; - m_tree->clear(); - - QList properties = object.properties(); - for (int i=0; iproperty = p; - - item->setText(0, p.name()); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - if (!p.hasNotifySignal()) - item->setForeground(0, Qt::lightGray); - - if (!p.binding().isEmpty()) { - PropertyViewItem *binding = new PropertyViewItem(item); - binding->setText(1, p.binding()); - binding->setForeground(1, Qt::darkGreen); - } - - item->setExpanded(true); - } - - m_tree->resizeColumnToContents(0); -} - -const QmlDebugObjectReference &PropertyView::object() const -{ - return m_object; -} - -void PropertyView::clear() -{ - setObject(QmlDebugObjectReference()); -} - -void PropertyView::updateProperty(const QString &name, const QVariant &value) -{ - for (int i=0; itopLevelItemCount(); i++) { - PropertyViewItem *item = static_cast(m_tree->topLevelItem(i)); - if (item->property.name() == name) - item->setText(1, value.toString()); - } -} - -void PropertyView::setPropertyIsWatched(const QString &name, bool watched) -{ - for (int i=0; itopLevelItemCount(); i++) { - PropertyViewItem *item = static_cast(m_tree->topLevelItem(i)); - if (item->property.name() == name && item->property.hasNotifySignal()) { - QFont font = m_tree->font(); - font.setBold(watched); - item->setFont(0, font); - } - } -} - -void PropertyView::itemActivated(QTreeWidgetItem *i) -{ - PropertyViewItem *item = static_cast(i); - if (!item->property.name().isEmpty() && item->property.hasNotifySignal()) - emit propertyActivated(item->property); -} - -QT_END_NAMESPACE - -#include "propertyview.moc" diff --git a/tools/qmldebugger/propertyview.h b/tools/qmldebugger/propertyview.h deleted file mode 100644 index 6b69bdf..0000000 --- a/tools/qmldebugger/propertyview.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef PROPERTYVIEW_H -#define PROPERTYVIEW_H - -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QTreeWidget; -class QTreeWidgetItem; - -class PropertyView : public QWidget -{ - Q_OBJECT -public: - PropertyView(QWidget *parent = 0); - - void setObject(const QmlDebugObjectReference &object); - const QmlDebugObjectReference &object() const; - - void updateProperty(const QString &name, const QVariant &value); - void setPropertyIsWatched(const QString &name, bool watched); - - void clear(); - -signals: - void propertyActivated(const QmlDebugPropertyReference &property); - -private slots: - void itemActivated(QTreeWidgetItem *); - -private: - QmlDebugObjectReference m_object; - QTreeWidget *m_tree; -}; - -QT_END_NAMESPACE - -#endif // PROPERTYVIEW_H diff --git a/tools/qmldebugger/qmldebugger.cpp b/tools/qmldebugger/qmldebugger.cpp new file mode 100644 index 0000000..0f0fc03 --- /dev/null +++ b/tools/qmldebugger/qmldebugger.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "canvasframerate.h" +#include "engine.h" +#include "qmldebugger.h" + +QmlDebugger::QmlDebugger(QWidget *parent) +: QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + + + QHBoxLayout *connectLayout = new QHBoxLayout; + layout->addLayout(connectLayout); + connectLayout->addStretch(2); + + m_connectionState = new QLabel(this); + connectLayout->addWidget(m_connectionState); + m_host = new QLineEdit(this); + m_host->setText("127.0.0.1"); + connectLayout->addWidget(m_host); + m_port = new QSpinBox(this); + m_port->setMinimum(1024); + m_port->setMaximum(20000); + m_port->setValue(3768); + connectLayout->addWidget(m_port); + m_connectButton = new QPushButton(tr("Connect"), this); + QObject::connect(m_connectButton, SIGNAL(clicked()), + this, SLOT(connectToHost())); + connectLayout->addWidget(m_connectButton); + m_disconnectButton = new QPushButton(tr("Disconnect"), this); + QObject::connect(m_disconnectButton, SIGNAL(clicked()), + this, SLOT(disconnectFromHost())); + m_disconnectButton->setEnabled(false); + connectLayout->addWidget(m_disconnectButton); + + m_tabs = new QTabWidget(this); + layout->addWidget(m_tabs); + + CanvasFrameRate *cfr = new CanvasFrameRate(&client, this); + m_tabs->addTab(cfr, tr("Frame Rate")); + + m_enginePane = new EnginePane(&client, this); + m_tabs->addTab(m_enginePane, tr("QML Engine")); + + QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + this, SLOT(connectionStateChanged())); + connectionStateChanged(); + + QObject::connect(&client, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(connectionError(QAbstractSocket::SocketError))); +} + +void QmlDebugger::setHost(const QString &host) +{ + m_host->setText(host); +} + +void QmlDebugger::setPort(quint16 port) +{ + m_port->setValue(port); +} + +void QmlDebugger::showEngineTab() +{ + m_tabs->setCurrentWidget(m_enginePane); +} + +void QmlDebugger::connectionStateChanged() +{ + switch (client.state()) { + default: + case QAbstractSocket::UnconnectedState: + m_connectionState->setText(tr("Disconnected")); + m_connectButton->setEnabled(true); + m_disconnectButton->setEnabled(false); + break; + case QAbstractSocket::HostLookupState: + m_connectionState->setText(tr("Resolving")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + break; + case QAbstractSocket::ConnectingState: + m_connectionState->setText(tr("Connecting")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + break; + case QAbstractSocket::ConnectedState: + m_connectionState->setText(tr("Connected")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(true); + + QTimer::singleShot(0, m_enginePane, SLOT(refreshEngines())); + break; + case QAbstractSocket::ClosingState: + m_connectionState->setText(tr("Closing")); + m_connectButton->setEnabled(false); + m_disconnectButton->setEnabled(false); + break; + } +} + +void QmlDebugger::connectionError(QAbstractSocket::SocketError socketError) +{ + qWarning() << "qmldebugger cannot connect:" << socketError + << client.errorString(); +} + +void QmlDebugger::connectToHost() +{ + client.connectToHost(m_host->text(), m_port->value()); +} + +void QmlDebugger::disconnectFromHost() +{ + client.disconnectFromHost(); +} diff --git a/tools/qmldebugger/qmldebugger.h b/tools/qmldebugger/qmldebugger.h new file mode 100644 index 0000000..9203e33 --- /dev/null +++ b/tools/qmldebugger/qmldebugger.h @@ -0,0 +1,47 @@ +#ifndef QMLDEBUGGER_H +#define QMLDEBUGGER_H + +#include +#include +#include + +class QLabel; +class QLineEdit; +class QSpinBox; +class QPushButton; +class QTabWidget; + +class EnginePane; + +class QmlDebugger : public QWidget +{ + Q_OBJECT +public: + QmlDebugger(QWidget * = 0); + + void setHost(const QString &host); + void setPort(quint16 port); + void showEngineTab(); + +public slots: + void connectToHost(); + void disconnectFromHost(); + +private slots: + void connectionStateChanged(); + void connectionError(QAbstractSocket::SocketError socketError); + +private: + QmlDebugConnection client; + + QLabel *m_connectionState; + QLineEdit *m_host; + QSpinBox *m_port; + QPushButton *m_connectButton; + QPushButton *m_disconnectButton; + + EnginePane *m_enginePane; + QTabWidget *m_tabs; +}; + +#endif diff --git a/tools/qmldebugger/qmldebugger.pri b/tools/qmldebugger/qmldebugger.pri new file mode 100644 index 0000000..ce36381 --- /dev/null +++ b/tools/qmldebugger/qmldebugger.pri @@ -0,0 +1,22 @@ +QT += network declarative +contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl + +# Input +HEADERS += $$PWD/qmldebugger.h \ + $$PWD/canvasframerate.h \ + $$PWD/watchtable.h \ + $$PWD/engine.h \ + $$PWD/objecttree.h \ + $$PWD/objectpropertiesview.h + +SOURCES += $$PWD/qmldebugger.cpp \ + $$PWD/main.cpp \ + $$PWD/canvasframerate.cpp \ + $$PWD/watchtable.cpp \ + $$PWD/engine.cpp \ + $$PWD/objecttree.cpp \ + $$PWD/objectpropertiesview.cpp + +RESOURCES += $$PWD/qmldebugger.qrc + +OTHER_FILES += $$PWD/engines.qml diff --git a/tools/qmldebugger/qmldebugger.pro b/tools/qmldebugger/qmldebugger.pro index b177875..4cdfd18 100644 --- a/tools/qmldebugger/qmldebugger.pro +++ b/tools/qmldebugger/qmldebugger.pro @@ -1,20 +1,6 @@ DESTDIR = ../../bin -QT += network declarative -contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, opengles1): QT += opengl -# Input -HEADERS += canvasframerate.h \ - watchtablemodel.h \ - propertyview.h \ - engine.h -SOURCES += main.cpp \ - canvasframerate.cpp \ - watchtablemodel.cpp \ - propertyview.cpp \ - engine.cpp -RESOURCES += qmldebugger.qrc - -OTHER_FILES += engines.qml +include(qmldebugger.pri) target.path=$$[QT_INSTALL_BINS] INSTALLS += target diff --git a/tools/qmldebugger/watchtable.cpp b/tools/qmldebugger/watchtable.cpp new file mode 100644 index 0000000..e4163dc --- /dev/null +++ b/tools/qmldebugger/watchtable.cpp @@ -0,0 +1,299 @@ +#include "watchtable.h" + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + + +WatchTableModel::WatchTableModel(QmlEngineDebug *client, QObject *parent) + : QAbstractTableModel(parent), + m_client(client) +{ +} + +WatchTableModel::~WatchTableModel() +{ + for (int i=0; i(watch)) + property = qobject_cast(watch)->name(); + + connect(watch, SIGNAL(valueChanged(QByteArray,QVariant)), + SLOT(watchedValueChanged(QByteArray,QVariant))); + + connect(watch, SIGNAL(stateChanged(State)), SLOT(watchStateChanged())); + + int col = columnCount(QModelIndex()); + beginInsertColumns(QModelIndex(), col, col); + + WatchedEntity e; + e.title = title; + e.hasFirstValue = false; + e.property = property; + e.watch = watch; + m_columns.append(e); + + endInsertColumns(); +} + +void WatchTableModel::removeWatch(QmlDebugWatch *watch) +{ + int column = columnForWatch(watch); + if (column == -1) + return; + + WatchedEntity entity = m_columns.takeAt(column); + + for (QList::Iterator iter = m_values.begin(); iter != m_values.end();) { + if (iter->column == column) { + iter = m_values.erase(iter); + } else { + if(iter->column > column) + --iter->column; + ++iter; + } + } + + reset(); +} + +void WatchTableModel::updateWatch(QmlDebugWatch *watch, const QVariant &value) +{ + int column = columnForWatch(watch); + if (column == -1) + return; + + addValue(column, value); + + if (!m_columns[column].hasFirstValue) { + m_columns[column].hasFirstValue = true; + m_values[m_values.count() - 1].first = true; + } +} + +QmlDebugWatch *WatchTableModel::findWatch(int column) const +{ + if (column < m_columns.count()) + return m_columns.at(column).watch; + return 0; +} + +QmlDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QString &property) const +{ + for (int i=0; iobjectDebugId() == objectDebugId + && m_columns[i].property == property) { + return m_columns[i].watch; + } + } + return 0; +} + +int WatchTableModel::rowCount(const QModelIndex &) const +{ + return m_values.count(); +} + +int WatchTableModel::columnCount(const QModelIndex &) const +{ + return m_columns.count(); +} + +QVariant WatchTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal) { + if (section < m_columns.count() && role == Qt::DisplayRole) + return m_columns.at(section).title; + } else { + if (role == Qt::DisplayRole) + return section + 1; + } + return QVariant(); +} + +QVariant WatchTableModel::data(const QModelIndex &idx, int role) const +{ + if (m_values.at(idx.row()).column == idx.column()) { + if (role == Qt::DisplayRole) { + const QVariant &value = m_values.at(idx.row()).variant; + QString str = value.toString(); + + if (str.isEmpty() && QmlMetaType::isObject(value.userType())) { + QObject *o = QmlMetaType::toQObject(value); + if(o) { + QString objectName = o->objectName(); + if(objectName.isEmpty()) + objectName = QLatin1String(""); + str = QLatin1String(o->metaObject()->className()) + + QLatin1String(": ") + objectName; + } + } + + if(str.isEmpty()) { + QDebug d(&str); + d << value; + } + return QVariant(str); + } else if(role == Qt::BackgroundRole) { + if(m_values.at(idx.row()).first) + return QColor(Qt::green); + else + return QVariant(); + } else { + return QVariant(); + } + } else { + return QVariant(); + } +} + +void WatchTableModel::watchStateChanged() +{ + QmlDebugWatch *watch = qobject_cast(sender()); + + if (watch && watch->state() == QmlDebugWatch::Inactive) { + removeWatch(watch); + watch->deleteLater(); + } +} + +int WatchTableModel::columnForWatch(QmlDebugWatch *watch) const +{ + for (int i=0; iremoveWatch(watch); + return; + } + + watch = m_client->addWatch(property, this); + if (watch->state() == QmlDebugWatch::Dead) { + delete watch; + watch = 0; + } else { + QString desc = property.name() + + QLatin1String(" on\n") + + object.className() + + QLatin1String(": ") + + (object.name().isEmpty() ? QLatin1String("") : object.name()); + addWatch(watch, desc); + emit watchCreated(watch); + } +} + +void WatchTableModel::watchedValueChanged(const QByteArray &propertyName, const QVariant &value) +{ + Q_UNUSED(propertyName); + QmlDebugWatch *watch = qobject_cast(sender()); + if (watch) + updateWatch(watch, value); +} + +void WatchTableModel::expressionWatchRequested(const QmlDebugObjectReference &obj, const QString &expr) +{ + QmlDebugWatch *watch = m_client->addWatch(obj, expr, this); + + if (watch->state() == QmlDebugWatch::Dead) { + delete watch; + watch = 0; + } else { + addWatch(watch, expr); + emit watchCreated(watch); + } +} + +void WatchTableModel::stopWatching(int column) +{ + QmlDebugWatch *watch = findWatch(column); + if (watch) { + m_client->removeWatch(watch); + delete watch; + watch = 0; + } +} + + +//---------------------------------------------- + +WatchTableHeaderView::WatchTableHeaderView(WatchTableModel *model, QWidget *parent) + : QHeaderView(Qt::Horizontal, parent), + m_model(model) +{ + setClickable(true); +} + +void WatchTableHeaderView::mousePressEvent(QMouseEvent *me) +{ + QHeaderView::mousePressEvent(me); + + if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) { + int col = logicalIndexAt(me->pos()); + if (col >= 0) { + QAction action(tr("Stop watching"), 0); + QList actions; + actions << &action; + if (QMenu::exec(actions, me->globalPos())) + m_model->stopWatching(col); + } + } +} + + +//---------------------------------------------- + +WatchTableView::WatchTableView(WatchTableModel *model, QWidget *parent) + : QTableView(parent), + m_model(model) +{ + connect(model, SIGNAL(watchCreated(QmlDebugWatch*)), SLOT(watchCreated(QmlDebugWatch*))); + connect(this, SIGNAL(activated(QModelIndex)), SLOT(indexActivated(QModelIndex))); +} + +void WatchTableView::indexActivated(const QModelIndex &index) +{ + QmlDebugWatch *watch = m_model->findWatch(index.column()); + if (watch) + emit objectActivated(watch->objectDebugId()); +} + +void WatchTableView::watchCreated(QmlDebugWatch *watch) +{ + int column = m_model->columnForWatch(watch); + resizeColumnToContents(column); +} + +QT_END_NAMESPACE diff --git a/tools/qmldebugger/watchtable.h b/tools/qmldebugger/watchtable.h new file mode 100644 index 0000000..abada2b --- /dev/null +++ b/tools/qmldebugger/watchtable.h @@ -0,0 +1,110 @@ +#ifndef WATCHTABLEMODEL_H +#define WATCHTABLEMODEL_H + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlDebugWatch; +class QmlEngineDebug; +class QmlDebugPropertyReference; +class QmlDebugObjectReference; + +class WatchTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + WatchTableModel(QmlEngineDebug *client, QObject *parent = 0); + ~WatchTableModel(); + + QmlDebugWatch *findWatch(int column) const; + int columnForWatch(QmlDebugWatch *watch) const; + + void stopWatching(int column); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + +signals: + void watchCreated(QmlDebugWatch *watch); + +public slots: + void togglePropertyWatch(const QmlDebugObjectReference &obj, const QmlDebugPropertyReference &prop); + void expressionWatchRequested(const QmlDebugObjectReference &, const QString &); + +private slots: + void watchStateChanged(); + void watchedValueChanged(const QByteArray &propertyName, const QVariant &value); + +private: + void addWatch(QmlDebugWatch *watch, const QString &title); + void removeWatch(QmlDebugWatch *watch); + void updateWatch(QmlDebugWatch *watch, const QVariant &value); + + QmlDebugWatch *findWatch(int objectDebugId, const QString &property) const; + + void addValue(int column, const QVariant &value); + + struct WatchedEntity + { + QString title; + bool hasFirstValue; + QString property; + QPointer watch; + }; + + struct Value { + int column; + QVariant variant; + bool first; + }; + + QmlEngineDebug *m_client; + QList m_columns; + QList m_values; +}; + + +class WatchTableHeaderView : public QHeaderView +{ + Q_OBJECT +public: + WatchTableHeaderView(WatchTableModel *model, QWidget *parent = 0); + +protected: + void mousePressEvent(QMouseEvent *me); + +private: + WatchTableModel *m_model; +}; + + +class WatchTableView : public QTableView +{ + Q_OBJECT +public: + WatchTableView(WatchTableModel *model, QWidget *parent = 0); + +signals: + void objectActivated(int objectDebugId); + +private slots: + void indexActivated(const QModelIndex &index); + void watchCreated(QmlDebugWatch *watch); + +private: + WatchTableModel *m_model; +}; + + +QT_END_NAMESPACE + +#endif // WATCHTABLEMODEL_H diff --git a/tools/qmldebugger/watchtablemodel.cpp b/tools/qmldebugger/watchtablemodel.cpp deleted file mode 100644 index 9d3ca1e..0000000 --- a/tools/qmldebugger/watchtablemodel.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include "watchtablemodel.h" - -#include -#include -#include - -QT_BEGIN_NAMESPACE - - -WatchTableModel::WatchTableModel(QObject *parent) - : QAbstractTableModel(parent) -{ -} - -void WatchTableModel::addWatch(QmlDebugWatch *watch, const QString &title) -{ - QString property; - if (qobject_cast(watch)) - property = qobject_cast(watch)->name(); - - // Watch will be automatically removed when its state is Inactive - QObject::connect(watch, SIGNAL(stateChanged(State)), SLOT(watchStateChanged())); - - int col = columnCount(QModelIndex()); - beginInsertColumns(QModelIndex(), col, col); - - WatchedEntity e; - e.title = title; - e.hasFirstValue = false; - e.property = property; - e.watch = watch; - m_columns.append(e); - - endInsertColumns(); -} - -void WatchTableModel::removeWatch(QmlDebugWatch *watch) -{ - int column = columnForWatch(watch); - if (column == -1) - return; - - WatchedEntity entity = m_columns.takeAt(column); - - for (QList::Iterator iter = m_values.begin(); iter != m_values.end();) { - if (iter->column == column) { - iter = m_values.erase(iter); - } else { - if(iter->column > column) - --iter->column; - ++iter; - } - } - - reset(); -} - -void WatchTableModel::updateWatch(QmlDebugWatch *watch, const QVariant &value) -{ - int column = columnForWatch(watch); - if (column == -1) - return; - - addValue(column, value); - - if (!m_columns[column].hasFirstValue) { - m_columns[column].hasFirstValue = true; - m_values[m_values.count() - 1].first = true; - } -} - -QmlDebugWatch *WatchTableModel::findWatch(int column) const -{ - if (column < m_columns.count()) - return m_columns.at(column).watch; - return 0; -} - -QmlDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QString &property) const -{ - for (int i=0; iobjectDebugId() == objectDebugId - && m_columns[i].property == property) { - return m_columns[i].watch; - } - } - return 0; -} - -QList WatchTableModel::watches() const -{ - QList watches; - for (int i=0; iobjectName(); - if(objectName.isEmpty()) - objectName = QLatin1String(""); - str = QLatin1String(o->metaObject()->className()) + - QLatin1String(": ") + objectName; - } - } - - if(str.isEmpty()) { - QDebug d(&str); - d << value; - } - return QVariant(str); - } else if(role == Qt::BackgroundRole) { - if(m_values.at(idx.row()).first) - return QColor(Qt::green); - else - return QVariant(); - } else { - return QVariant(); - } - } else { - return QVariant(); - } -} - -void WatchTableModel::watchStateChanged() -{ - QmlDebugWatch *watch = qobject_cast(sender()); - if (watch && watch->state() == QmlDebugWatch::Inactive) - removeWatch(watch); -} - -int WatchTableModel::columnForWatch(QmlDebugWatch *watch) const -{ - for (int i=0; i -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QmlDebugWatch; - -class WatchTableModel : public QAbstractTableModel -{ - Q_OBJECT -public: - WatchTableModel(QObject *parent = 0); - - void addWatch(QmlDebugWatch *watch, const QString &title); - void updateWatch(QmlDebugWatch *watch, const QVariant &value); - - QmlDebugWatch *findWatch(int column) const; - QmlDebugWatch *findWatch(int objectDebugId, const QString &property) const; - - QList watches() const; - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - -private slots: - void watchStateChanged(); - -private: - int columnForWatch(QmlDebugWatch *watch) const; - void addValue(int column, const QVariant &value); - void removeWatch(QmlDebugWatch *watch); - - struct WatchedEntity - { - QString title; - bool hasFirstValue; - QString property; - QPointer watch; - }; - - struct Value { - int column; - QVariant variant; - bool first; - }; - - QList m_columns; - QList m_values; -}; - - -QT_END_NAMESPACE - -#endif // WATCHTABLEMODEL_H -- cgit v0.12