From 473a8e5d2867d8eb2684baed705bd9000e3c6271 Mon Sep 17 00:00:00 2001 From: Lasse Holmstedt <lasse.holmstedt@nokia.com> Date: Tue, 20 Apr 2010 16:27:41 +0200 Subject: [PATCH] Categories and saving of settings in qml inspector --- .../qmlinspector/QmlInspector.pluginspec | 1 + .../components/canvasframerate.cpp | 4 +- .../components/inspectortreeitems.cpp | 85 ++++++ .../components/inspectortreeitems.h | 56 ++++ .../components/objectpropertiesview.cpp | 268 ++++++++++++------ .../components/objectpropertiesview.h | 17 +- .../qmlinspector/components/objecttree.cpp | 137 ++++++--- .../qmlinspector/components/objecttree.h | 20 +- .../components/propertytypefinder.cpp | 69 +++++ .../components/propertytypefinder.h | 45 +++ .../qmlinspector/components/qmldebugger.pri | 9 +- .../qmlinspector/inspectorsettings.cpp | 39 ++- src/plugins/qmlinspector/inspectorsettings.h | 10 + src/plugins/qmlinspector/qmlinspector.cpp | 105 +++++-- src/plugins/qmlinspector/qmlinspector.h | 7 +- .../qmlinspector/qmlinspectorconstants.h | 3 + .../qmlinspector/qmlinspectorplugin.cpp | 2 +- 17 files changed, 719 insertions(+), 158 deletions(-) create mode 100644 src/plugins/qmlinspector/components/inspectortreeitems.cpp create mode 100644 src/plugins/qmlinspector/components/inspectortreeitems.h create mode 100644 src/plugins/qmlinspector/components/propertytypefinder.cpp create mode 100644 src/plugins/qmlinspector/components/propertytypefinder.h diff --git a/src/plugins/qmlinspector/QmlInspector.pluginspec b/src/plugins/qmlinspector/QmlInspector.pluginspec index 1780f2cb6a0..ffe1ad22c68 100644 --- a/src/plugins/qmlinspector/QmlInspector.pluginspec +++ b/src/plugins/qmlinspector/QmlInspector.pluginspec @@ -25,5 +25,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license> <dependency name="CppTools" version="1.3.84"/> <dependency name="CppEditor" version="1.3.84"/> <dependency name="Debugger" version="1.3.84"/> + <dependency name="QmlJSEditor" version="1.3.84"/> </dependencyList> </plugin> diff --git a/src/plugins/qmlinspector/components/canvasframerate.cpp b/src/plugins/qmlinspector/components/canvasframerate.cpp index d3f6179d8f7..0575544b102 100644 --- a/src/plugins/qmlinspector/components/canvasframerate.cpp +++ b/src/plugins/qmlinspector/components/canvasframerate.cpp @@ -563,7 +563,7 @@ void CanvasFrameRate::enabledToggled(bool checked) static_cast<QDeclarativeDebugClient *>(m_plugin)->setEnabled(checked); } -} -} +} // Internal +} // Qml #include "canvasframerate.moc" diff --git a/src/plugins/qmlinspector/components/inspectortreeitems.cpp b/src/plugins/qmlinspector/components/inspectortreeitems.cpp new file mode 100644 index 00000000000..5527b0fc163 --- /dev/null +++ b/src/plugins/qmlinspector/components/inspectortreeitems.cpp @@ -0,0 +1,85 @@ +#include "inspectortreeitems.h" +#include "qmlinspector.h" + +#include <QtGui/QApplication> + +namespace Qml { +namespace Internal { + +// ************************************************************************* +// ObjectTreeItem +// ************************************************************************* + +ObjectTreeItem::ObjectTreeItem(QTreeWidget *widget, int type) : + QTreeWidgetItem(widget, type), m_hasValidDebugId(true) +{ + +} + +ObjectTreeItem::ObjectTreeItem(QTreeWidgetItem *parentItem, int type) : + QTreeWidgetItem(parentItem, type), m_hasValidDebugId(true) +{ + +} + +QVariant ObjectTreeItem::data (int column, int role) const +{ + if (role == Qt::ForegroundRole) + return m_hasValidDebugId ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground); + + return QTreeWidgetItem::data(column, role); +} + +void ObjectTreeItem::setData (int column, int role, const QVariant & value) +{ + QTreeWidgetItem::setData(column, role, value); +} + +void ObjectTreeItem::setHasValidDebugId(bool value) +{ + m_hasValidDebugId = value; +} + +// ************************************************************************* +// PropertiesViewItem +// ************************************************************************* +PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type) + : QTreeWidgetItem(widget), type(type) +{ +} + +PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type) + : QTreeWidgetItem(parent), type(type) +{ +} + +QVariant PropertiesViewItem::data (int column, int role) const +{ + if (column == 1) { + if (role == Qt::ForegroundRole) { + bool canEdit = data(0, CanEditRole).toBool(); + return canEdit ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground); + } + } + + return QTreeWidgetItem::data(column, role); +} + +void PropertiesViewItem::setData (int column, int role, const QVariant & value) +{ + if (role == Qt::EditRole) { + if (column == 1) + QmlInspector::instance()->executeExpression(property.objectDebugId(), objectIdString(), property.name(), value); + } + + QTreeWidgetItem::setData(column, role, value); +} + +QString PropertiesViewItem::objectIdString() const +{ + return data(0, ObjectIdStringRole).toString(); +} + + +} // Internal +} // Qml diff --git a/src/plugins/qmlinspector/components/inspectortreeitems.h b/src/plugins/qmlinspector/components/inspectortreeitems.h new file mode 100644 index 00000000000..b09ff80d772 --- /dev/null +++ b/src/plugins/qmlinspector/components/inspectortreeitems.h @@ -0,0 +1,56 @@ +#ifndef INSPECTORTREEITEMS_H +#define INSPECTORTREEITEMS_H + +#include <QTreeWidgetItem> +#include <QObject> +#include <private/qdeclarativedebug_p.h> + +namespace Qml { +namespace Internal { + + +class ObjectTreeItem : public QTreeWidgetItem +{ +public: + explicit ObjectTreeItem(QTreeWidget *widget, int type = 0); + ObjectTreeItem(QTreeWidgetItem *parentItem, int type = 0); + QVariant data (int column, int role) const; + void setData (int column, int role, const QVariant & value); + + void setHasValidDebugId(bool value); + + +private: + bool m_hasValidDebugId; +}; + +class PropertiesViewItem : public QTreeWidgetItem +{ +public: + enum Type { + BindingType, + OtherType, + ClassType, + }; + enum DataRoles { + CanEditRole = Qt::UserRole + 1, + ObjectIdStringRole = Qt::UserRole + 50, + ClassDepthRole = Qt::UserRole + 51 + }; + + PropertiesViewItem(QTreeWidget *widget, Type type = OtherType); + PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType); + QVariant data (int column, int role) const; + void setData (int column, int role, const QVariant & value); + + QDeclarativeDebugPropertyReference property; + Type type; +private: + QString objectIdString() const; + +}; + +} // Internal +} // Qml + +#endif // INSPECTORTREEITEMS_H diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.cpp b/src/plugins/qmlinspector/components/objectpropertiesview.cpp index c41eac4070e..1e380efbf5d 100644 --- a/src/plugins/qmlinspector/components/objectpropertiesview.cpp +++ b/src/plugins/qmlinspector/components/objectpropertiesview.cpp @@ -27,10 +27,15 @@ ** **************************************************************************/ #include "objectpropertiesview.h" +#include "inspectortreeitems.h" #include "inspectorcontext.h" #include "watchtable.h" #include "qmlinspector.h" +#include "propertytypefinder.h" +#include <extensionsystem/pluginmanager.h> +#include <qmljseditor/qmljsmodelmanagerinterface.h> +#include <qmljs/qmljsdocument.h> #include <QtGui/QApplication> #include <QtGui/QTreeWidget> @@ -39,79 +44,19 @@ #include <QtGui/QMenu> #include <QtGui/QContextMenuEvent> +#include <QtCore/QFile> #include <QtCore/QDebug> namespace Qml { namespace Internal { - -class PropertiesViewItem : public QObject, public QTreeWidgetItem -{ - Q_OBJECT -public: - enum Type { - BindingType, - OtherType - }; - - PropertiesViewItem(QTreeWidget *widget, Type type = OtherType); - PropertiesViewItem(QTreeWidgetItem *parent, Type type = OtherType); - QVariant data (int column, int role) const; - void setData (int column, int role, const QVariant & value); - - QDeclarativeDebugPropertyReference property; - Type type; -private: - QString objectIdString() const; - -}; - -PropertiesViewItem::PropertiesViewItem(QTreeWidget *widget, Type type) - : QTreeWidgetItem(widget), type(type) -{ -} - -PropertiesViewItem::PropertiesViewItem(QTreeWidgetItem *parent, Type type) - : QTreeWidgetItem(parent), type(type) -{ -} - -QVariant PropertiesViewItem::data (int column, int role) const -{ - if (column == 1) { - if (role == Qt::ForegroundRole) { - bool canEdit = data(0, ObjectPropertiesView::CanEditRole).toBool(); - return canEdit ? qApp->palette().color(QPalette::Foreground) : qApp->palette().color(QPalette::Disabled, QPalette::Foreground); - } - } - - return QTreeWidgetItem::data(column, role); -} - -void PropertiesViewItem::setData (int column, int role, const QVariant & value) -{ - if (role == Qt::EditRole) { - if (column == 1) { - qDebug() << "editing prop item w/role" << role << "and value" << value; - QmlInspector::instance()->executeExpression(property.objectDebugId(), objectIdString(), property.name(), value); - } - return; - } - - QTreeWidgetItem::setData(column, role, value); -} - -QString PropertiesViewItem::objectIdString() const -{ - return data(0, ObjectPropertiesView::ObjectIdStringRole).toString(); -} - ObjectPropertiesView::ObjectPropertiesView(WatchTableModel *watchTableModel, QDeclarativeEngineDebug *client, QWidget *parent) : QWidget(parent), m_client(client), m_query(0), - m_watch(0), m_clickedItem(0), m_showUnwatchableProperties(false), + m_watch(0), m_clickedItem(0), + m_groupByItemType(true), m_showUnwatchableProperties(false), m_watchTableModel(watchTableModel) { QVBoxLayout *layout = new QVBoxLayout; @@ -124,7 +69,7 @@ ObjectPropertiesView::ObjectPropertiesView(WatchTableModel *watchTableModel, m_tree->setFrameStyle(QFrame::NoFrame); m_tree->setAlternatingRowColors(true); m_tree->setExpandsOnDoubleClick(false); - m_tree->setRootIsDecorated(false); + m_tree->setRootIsDecorated(m_groupByItemType); m_tree->setEditTriggers(QAbstractItemView::NoEditTriggers); m_tree->setHeaderLabels(QStringList() @@ -133,24 +78,53 @@ ObjectPropertiesView::ObjectPropertiesView(WatchTableModel *watchTableModel, this, SLOT(itemDoubleClicked(QTreeWidgetItem *, int))); connect(m_tree, SIGNAL(itemSelectionChanged()), SLOT(changeItemSelection())); - 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); + 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); + + + m_toggleGroupByItemTypeAction = new QAction(tr("&Group by item type"), this); + m_toggleGroupByItemTypeAction->setCheckable(true); + m_toggleGroupByItemTypeAction->setChecked(m_groupByItemType); connect(m_addWatchAction, SIGNAL(triggered()), SLOT(addWatch())); connect(m_removeWatchAction, SIGNAL(triggered()), SLOT(removeWatch())); connect(m_toggleUnwatchablePropertiesAction, SIGNAL(triggered()), SLOT(toggleUnwatchableProperties())); + connect(m_toggleGroupByItemTypeAction, SIGNAL(triggered()), SLOT(toggleGroupingByItemType())); + m_tree->setColumnCount(3); m_tree->header()->setDefaultSectionSize(150); layout->addWidget(m_tree); } +void ObjectPropertiesView::readSettings(const InspectorSettings &settings) +{ + if (settings.showUnwatchableProperties() != m_showUnwatchableProperties) + toggleUnwatchableProperties(); + if (settings.groupPropertiesByItemType() != m_groupByItemType) + toggleGroupingByItemType(); +} + +void ObjectPropertiesView::saveSettings(InspectorSettings &settings) +{ + settings.setShowUnwatchableProperties(m_showUnwatchableProperties); + settings.setGroupPropertiesByItemType(m_groupByItemType); +} + void ObjectPropertiesView::toggleUnwatchableProperties() { m_showUnwatchableProperties = !m_showUnwatchableProperties; setObject(m_object); } +void ObjectPropertiesView::toggleGroupingByItemType() +{ + m_groupByItemType = !m_groupByItemType; + m_tree->setRootIsDecorated(m_groupByItemType); + m_toggleGroupByItemTypeAction->setChecked(m_groupByItemType); + setObject(m_object); +} + void ObjectPropertiesView::changeItemSelection() { if (m_tree->selectedItems().isEmpty()) @@ -249,25 +223,98 @@ void ObjectPropertiesView::setPropertyValue(PropertiesViewItem *item, const QVar } } +QString ObjectPropertiesView::propertyBaseClass(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property, int &depth) +{ + ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance(); + QmlJSEditor::ModelManagerInterface *modelManager = pluginManager->getObject<QmlJSEditor::ModelManagerInterface>(); + QmlJS::Snapshot snapshot = modelManager->snapshot(); + + //qDebug() << property.name() << object.source().url().path(); + + QmlJS::Document::Ptr document = snapshot.document(object.source().url().path()); + if (document.isNull()) { + + QFile inFile(object.source().url().path()); + QString contents; + if (inFile.open(QIODevice::ReadOnly)) { + QTextStream ins(&inFile); + contents = ins.readAll(); + inFile.close(); + } + //qDebug() << contents; + + document = QmlJS::Document::create(object.source().url().path()); + document->setSource(contents); + if (!document->parse()) + return QString(); + + snapshot.insert(document); + } + + PropertyTypeFinder find(document, snapshot, modelManager->importPaths()); + QString baseClassName = find(object.source().lineNumber(), object.source().columnNumber(), property.name()); + depth = find.depth(); + + return baseClassName; + +} + void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &object) { m_object = object; m_tree->clear(); + QHash<QString, PropertiesViewItem*> baseClassItems; + PropertiesViewItem* currentParentItem = 0; + + QList<QString> insertedPropertyNames; + QList<QDeclarativeDebugPropertyReference> properties = object.properties(); for (int i=0; i<properties.count(); ++i) { const QDeclarativeDebugPropertyReference &p = properties[i]; + // ignore overridden/redefined/shadowed properties; and do special ignore for QGraphicsObject* parent, + // which is useless while debugging. + if (insertedPropertyNames.contains(p.name()) + || (p.name() == "parent" && p.valueTypeName() == "QGraphicsObject*")) + { + continue; + } + insertedPropertyNames.append(p.name()); + if (m_showUnwatchableProperties || p.hasNotifySignal()) { - PropertiesViewItem *item = new PropertiesViewItem(m_tree); + PropertiesViewItem *item = 0; + + if (m_groupByItemType) { + int depth = 0; + QString baseClassName = propertyBaseClass(object, p, depth); + if (!baseClassItems.contains(baseClassName)) { + PropertiesViewItem *baseClassItem = new PropertiesViewItem(m_tree, PropertiesViewItem::ClassType); + baseClassItem->setData(0, PropertiesViewItem::CanEditRole, false); + baseClassItem->setData(0, PropertiesViewItem::ClassDepthRole, depth); + baseClassItem->setText(0, baseClassName); + + QFont font = m_tree->font(); + font.setBold(true); + baseClassItem->setFont(0, font); + + baseClassItems.insert(baseClassName, baseClassItem); + + qDebug() << "Baseclass" << baseClassName; + } + currentParentItem = baseClassItems.value(baseClassName); + item = new PropertiesViewItem(currentParentItem); + } else + item = new PropertiesViewItem(m_tree); + item->property = p; - item->setData(0, ObjectIdStringRole, object.idString()); + item->setData(0, PropertiesViewItem::ObjectIdStringRole, object.idString()); item->setText(0, p.name()); Qt::ItemFlags itemFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; bool canEdit = object.idString().length() && QmlInspector::instance()->canEditProperty(item->property.valueTypeName()); - item->setData(0, CanEditRole, canEdit); + item->setData(0, PropertiesViewItem::CanEditRole, canEdit); if (canEdit) itemFlags |= Qt::ItemIsEditable; @@ -293,10 +340,36 @@ void ObjectPropertiesView::setObject(const QDeclarativeDebugObjectReference &obj } } + if (m_groupByItemType) + sortBaseClassItems(); + m_tree->expandAll(); + +} + +static bool baseClassItemsDepthLessThan(const PropertiesViewItem *item1, const PropertiesViewItem *item2) +{ + int depth1 = item1->data(0, PropertiesViewItem::ClassDepthRole).toInt(); + int depth2 = item2->data(0, PropertiesViewItem::ClassDepthRole).toInt(); + + // reversed order + return !(depth1 < depth2); +} + +void ObjectPropertiesView::sortBaseClassItems() +{ + QList<PropertiesViewItem*> topLevelItems; + while(m_tree->topLevelItemCount()) + topLevelItems.append(static_cast<PropertiesViewItem*>(m_tree->takeTopLevelItem(0))); + + qSort(topLevelItems.begin(), topLevelItems.end(), baseClassItemsDepthLessThan); + foreach(PropertiesViewItem *item, topLevelItems) + m_tree->addTopLevelItem(item); + } void ObjectPropertiesView::watchCreated(QDeclarativeDebugWatch *watch) { + if (watch->objectDebugId() == m_object.debugId() && qobject_cast<QDeclarativeDebugPropertyWatch*>(watch)) { connect(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)), SLOT(watchStateChanged())); @@ -317,16 +390,32 @@ void ObjectPropertiesView::watchStateChanged() void ObjectPropertiesView::setWatched(const QString &property, bool watched) { - for (int i=0; i<m_tree->topLevelItemCount(); ++i) { - PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i)); - if (item->property.name() == property && item->property.hasNotifySignal()) { - QFont font = m_tree->font(); - font.setBold(watched); - item->setFont(0, font); + for (int i = 0; i < m_tree->topLevelItemCount(); ++i) { + PropertiesViewItem *topLevelItem = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i)); + if (m_groupByItemType) { + for(int j = 0; j < topLevelItem->childCount(); ++j) { + PropertiesViewItem *item = static_cast<PropertiesViewItem*>(topLevelItem->child(j)); + if (styleWatchedItem(item, property, watched)) + return; + } + } else { + if (styleWatchedItem(topLevelItem, property, watched)) + return; } } } +bool ObjectPropertiesView::styleWatchedItem(PropertiesViewItem *item, const QString &property, bool isWatched) const +{ + if (item->property.name() == property && item->property.hasNotifySignal()) { + QFont font = m_tree->font(); + font.setBold(isWatched); + item->setFont(0, font); + return true; + } + return false; +} + bool ObjectPropertiesView::isWatched(QTreeWidgetItem *item) { return item->font(0).bold(); @@ -335,16 +424,31 @@ bool ObjectPropertiesView::isWatched(QTreeWidgetItem *item) void ObjectPropertiesView::valueChanged(const QByteArray &name, const QVariant &value) { for (int i=0; i<m_tree->topLevelItemCount(); ++i) { - PropertiesViewItem *item = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i)); - if (item->property.name() == name) { - setPropertyValue(item, value, !item->property.hasNotifySignal()); - return; + PropertiesViewItem *topLevelItem = static_cast<PropertiesViewItem *>(m_tree->topLevelItem(i)); + + if (m_groupByItemType) { + for(int j = 0; j < topLevelItem->childCount(); ++j) { + PropertiesViewItem *item = static_cast<PropertiesViewItem*>(topLevelItem->child(j)); + if (item->property.name() == name) { + setPropertyValue(item, value, !item->property.hasNotifySignal()); + return; + } + } + } else { + if (topLevelItem->property.name() == name) { + setPropertyValue(topLevelItem, value, !topLevelItem->property.hasNotifySignal()); + return; + } } + } } void ObjectPropertiesView::itemDoubleClicked(QTreeWidgetItem *item, int column) { + if (item->type() == PropertiesViewItem::ClassType) + return; + if (column == 0) toggleWatch(item); else if (column == 1) @@ -355,6 +459,7 @@ void ObjectPropertiesView::addWatch() { toggleWatch(m_clickedItem); } + void ObjectPropertiesView::removeWatch() { toggleWatch(m_clickedItem); @@ -393,6 +498,7 @@ void ObjectPropertiesView::contextMenuEvent(QContextMenuEvent *event) else m_toggleUnwatchablePropertiesAction->setText(tr("Show unwatchable properties")); + menu.addAction(m_toggleGroupByItemTypeAction); menu.addAction(m_toggleUnwatchablePropertiesAction); menu.exec(event->globalPos()); @@ -400,5 +506,3 @@ void ObjectPropertiesView::contextMenuEvent(QContextMenuEvent *event) } // Internal } // Qml - -#include "objectpropertiesview.moc" diff --git a/src/plugins/qmlinspector/components/objectpropertiesview.h b/src/plugins/qmlinspector/components/objectpropertiesview.h index b2aa1cf3770..c4e7e2857c3 100644 --- a/src/plugins/qmlinspector/components/objectpropertiesview.h +++ b/src/plugins/qmlinspector/components/objectpropertiesview.h @@ -29,8 +29,9 @@ #ifndef PROPERTIESTABLEMODEL_H #define PROPERTIESTABLEMODEL_H -#include <private/qdeclarativedebug_p.h> +#include "inspectorsettings.h" +#include <private/qdeclarativedebug_p.h> #include <QtGui/qwidget.h> QT_BEGIN_NAMESPACE @@ -52,16 +53,12 @@ class ObjectPropertiesView : public QWidget Q_OBJECT public: ObjectPropertiesView(WatchTableModel *watchTableModel, QDeclarativeEngineDebug *client = 0, QWidget *parent = 0); + void readSettings(const InspectorSettings &settings); + void saveSettings(InspectorSettings &settings); void setEngineDebug(QDeclarativeEngineDebug *client); void clear(); - - enum DataRoles { - CanEditRole = Qt::UserRole + 1, - ObjectIdStringRole = Qt::UserRole + 50 - }; - signals: void watchToggleRequested(const QDeclarativeDebugObjectReference &, const QDeclarativeDebugPropertyReference &); void contextHelpIdChanged(const QString &contextHelpId); @@ -83,8 +80,12 @@ private slots: void addWatch(); void removeWatch(); void toggleUnwatchableProperties(); + void toggleGroupingByItemType(); private: + void sortBaseClassItems(); + bool styleWatchedItem(PropertiesViewItem *item, const QString &property, bool isWatched) const; + QString propertyBaseClass(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property, int &depth); void toggleWatch(QTreeWidgetItem *item); void setObject(const QDeclarativeDebugObjectReference &object); bool isWatched(QTreeWidgetItem *item); @@ -98,8 +99,10 @@ private: QAction *m_addWatchAction; QAction *m_removeWatchAction; QAction *m_toggleUnwatchablePropertiesAction; + QAction *m_toggleGroupByItemTypeAction; QTreeWidgetItem *m_clickedItem; + bool m_groupByItemType; bool m_showUnwatchableProperties; QTreeWidget *m_tree; QWeakPointer<WatchTableModel> m_watchTableModel; diff --git a/src/plugins/qmlinspector/components/objecttree.cpp b/src/plugins/qmlinspector/components/objecttree.cpp index 2723387ee6b..970113e79b5 100644 --- a/src/plugins/qmlinspector/components/objecttree.cpp +++ b/src/plugins/qmlinspector/components/objecttree.cpp @@ -37,6 +37,7 @@ #include <private/qdeclarativedebug_p.h> #include "objecttree.h" +#include "inspectortreeitems.h" #include "inspectorcontext.h" namespace Qml { @@ -45,14 +46,22 @@ namespace Internal { ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent) : QTreeWidget(parent), m_client(client), - m_query(0) + m_query(0), m_clickedItem(0), m_showUninspectableItems(false), + m_currentObjectDebugId(0), m_showUninspectableOnInitDone(false) { setAttribute(Qt::WA_MacShowFocusRect, false); setFrameStyle(QFrame::NoFrame); setHeaderHidden(true); - setMinimumWidth(250); setExpandsOnDoubleClick(false); + m_addWatchAction = new QAction(tr("Add watch expression..."), this); + m_toggleUninspectableItemsAction = new QAction(tr("Show uninspectable items"), this); + m_toggleUninspectableItemsAction->setCheckable(true); + m_goToFileAction = new QAction(tr("Go to file"), this); + connect(m_toggleUninspectableItemsAction, SIGNAL(triggered()), SLOT(toggleUninspectableItems())); + connect(m_addWatchAction, SIGNAL(triggered()), SLOT(addWatch())); + connect(m_goToFileAction, SIGNAL(triggered()), SLOT(goToFile())); + connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)), SLOT(currentItemChanged(QTreeWidgetItem *))); connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)), @@ -60,11 +69,28 @@ ObjectTree::ObjectTree(QDeclarativeEngineDebug *client, QWidget *parent) connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged())); } +void ObjectTree::readSettings(const InspectorSettings &settings) +{ + if (settings.showUninspectableItems() != m_showUninspectableItems) + toggleUninspectableItems(); +} +void ObjectTree::saveSettings(InspectorSettings &settings) +{ + settings.setShowUninspectableItems(m_showUninspectableItems); +} + void ObjectTree::setEngineDebug(QDeclarativeEngineDebug *client) { m_client = client; } +void ObjectTree::toggleUninspectableItems() +{ + m_showUninspectableItems = !m_showUninspectableItems; + m_toggleUninspectableItemsAction->setChecked(m_showUninspectableItems); + reload(m_currentObjectDebugId); +} + void ObjectTree::selectionChanged() { if (selectedItems().isEmpty()) @@ -84,13 +110,14 @@ void ObjectTree::reload(int objectDebugId) delete m_query; m_query = 0; } + m_currentObjectDebugId = objectDebugId; m_query = m_client->queryObjectRecursive(QDeclarativeDebugObjectReference(objectDebugId), this); if (!m_query->isWaiting()) objectFetched(); else QObject::connect(m_query, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)), - this, SLOT(objectFetched())); + this, SLOT(objectFetched(QDeclarativeDebugQuery::State))); } void ObjectTree::setCurrentObject(int debugId) @@ -105,14 +132,25 @@ void ObjectTree::setCurrentObject(int debugId) } -void ObjectTree::objectFetched() +void ObjectTree::objectFetched(QDeclarativeDebugQuery::State state) { - //dump(m_query->object(), 0); - buildTree(m_query->object(), 0); - setCurrentItem(topLevelItem(0)); + if (state == QDeclarativeDebugQuery::Completed) { + //dump(m_query->object(), 0); + buildTree(m_query->object(), 0); + setCurrentItem(topLevelItem(0)); - delete m_query; - m_query = 0; + delete m_query; + m_query = 0; + + // this ugly hack is needed if user wants to see internal structs + // on startup - debugger does not load them until towards the end, + // so essentially loading twice gives us the full list as everything + // is already loaded. + if (m_showUninspectableItems && !m_showUninspectableOnInitDone) { + m_showUninspectableOnInitDone = true; + reload(m_currentObjectDebugId); + } + } } void ObjectTree::currentItemChanged(QTreeWidgetItem *item) @@ -135,35 +173,46 @@ void ObjectTree::activated(QTreeWidgetItem *item) emit activated(obj); } +void ObjectTree::cleanup() +{ + m_showUninspectableOnInitDone = false; + clear(); +} + void ObjectTree::buildTree(const QDeclarativeDebugObjectReference &obj, QTreeWidgetItem *parent) { if (!parent) clear(); - QTreeWidgetItem *item = parent ? new QTreeWidgetItem(parent) : new QTreeWidgetItem(this); + qDebug() << obj.className(); + + if (obj.contextDebugId() < 0 && !m_showUninspectableItems) + return; + + ObjectTreeItem *item = parent ? new ObjectTreeItem(parent) : new ObjectTreeItem(this); if (obj.idString().isEmpty()) - item->setText(0, QLatin1String("<")+obj.className()+QLatin1String(">")); + item->setText(0, QString("<%1>").arg(obj.className())); else item->setText(0, obj.idString()); item->setData(0, Qt::UserRole, qVariantFromValue(obj)); if (parent && obj.contextDebugId() >= 0 && obj.contextDebugId() != parent->data(0, Qt::UserRole - ).value<QDeclarativeDebugObjectReference>().contextDebugId()) { + ).value<QDeclarativeDebugObjectReference>().contextDebugId()) + { + QDeclarativeDebugFileReference 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); - } + item->setHasValidDebugId(false); for (int ii = 0; ii < obj.children().count(); ++ii) buildTree(obj.children().at(ii), item); @@ -219,26 +268,46 @@ QTreeWidgetItem *ObjectTree::findItem(QTreeWidgetItem *item, int debugId) const return 0; } -void ObjectTree::mousePressEvent(QMouseEvent *me) +void ObjectTree::addWatch() { - QTreeWidget::mousePressEvent(me); - if (!currentItem()) - return; - if(me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) { - QAction action(tr("Add watch..."), 0); - QList<QAction *> actions; - actions << &action; - QDeclarativeDebugObjectReference obj = - currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); - 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); - } - } + QDeclarativeDebugObjectReference obj = + currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); + + 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); + } +void ObjectTree::goToFile() +{ + QDeclarativeDebugObjectReference obj = + currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>(); + + if (obj.debugId() >= 0) + emit activated(obj); } + +void ObjectTree::contextMenuEvent(QContextMenuEvent *event) +{ + + m_clickedItem = itemAt(QPoint(event->pos().x(), + event->pos().y() )); + if (!m_clickedItem) + return; + + QMenu menu; + menu.addAction(m_addWatchAction); + menu.addAction(m_goToFileAction); + if (m_currentObjectDebugId) { + menu.addSeparator(); + menu.addAction(m_toggleUninspectableItemsAction); + } + + menu.exec(event->globalPos()); } + +} // Internal +} // Qml diff --git a/src/plugins/qmlinspector/components/objecttree.h b/src/plugins/qmlinspector/components/objecttree.h index 8e800209f53..de62118de6b 100644 --- a/src/plugins/qmlinspector/components/objecttree.h +++ b/src/plugins/qmlinspector/components/objecttree.h @@ -29,6 +29,8 @@ #ifndef OBJECTTREE_H #define OBJECTTREE_H +#include "inspectorsettings.h" +#include <private/qdeclarativedebug_p.h> #include <QtGui/qtreewidget.h> QT_BEGIN_NAMESPACE @@ -54,6 +56,8 @@ public: ObjectTree(QDeclarativeEngineDebug *client = 0, QWidget *parent = 0); void setEngineDebug(QDeclarativeEngineDebug *client); + void readSettings(const InspectorSettings &settings); + void saveSettings(InspectorSettings &settings); signals: void currentObjectChanged(const QDeclarativeDebugObjectReference &); @@ -62,17 +66,21 @@ signals: void contextHelpIdChanged(const QString &contextHelpId); public slots: + void cleanup(); void reload(int objectDebugId); // set the root object void setCurrentObject(int debugId); // select an object in the tree protected: - virtual void mousePressEvent(QMouseEvent *); + virtual void contextMenuEvent(QContextMenuEvent *); private slots: - void objectFetched(); + void addWatch(); + void toggleUninspectableItems(); + void objectFetched(QDeclarativeDebugQuery::State = QDeclarativeDebugQuery::Completed); void currentItemChanged(QTreeWidgetItem *); void activated(QTreeWidgetItem *); void selectionChanged(); + void goToFile(); private: QTreeWidgetItem *findItemByObjectId(int debugId) const; @@ -83,6 +91,14 @@ private: QDeclarativeEngineDebug *m_client; QDeclarativeDebugObjectQuery *m_query; + + QTreeWidgetItem *m_clickedItem; + QAction *m_toggleUninspectableItemsAction; + QAction *m_addWatchAction; + QAction *m_goToFileAction; + bool m_showUninspectableItems; + int m_currentObjectDebugId; + bool m_showUninspectableOnInitDone; }; } // Internal diff --git a/src/plugins/qmlinspector/components/propertytypefinder.cpp b/src/plugins/qmlinspector/components/propertytypefinder.cpp new file mode 100644 index 00000000000..58e48969a6f --- /dev/null +++ b/src/plugins/qmlinspector/components/propertytypefinder.cpp @@ -0,0 +1,69 @@ +#include "propertytypefinder.h" + +#include <qmljs/parser/qmljsast_p.h> + +#include <QDebug> + +using namespace QmlJS; +using namespace QmlJS::AST; +using namespace QmlJS::Interpreter; +using namespace Qml::Internal; + +PropertyTypeFinder::PropertyTypeFinder(QmlJS::Document::Ptr doc, QmlJS::Snapshot snapshot, const QStringList &importPaths) + : m_doc(doc) + , m_snapshot(snapshot) + , m_engine() + , m_context(&m_engine) + , m_link(&m_context, doc, snapshot, importPaths), m_depth(0) +{ +} + +QString PropertyTypeFinder::operator()(int objectLine, int objectColumn, const QString &propertyName) +{ + m_objectLine = objectLine; + m_objectColumn = objectColumn; + m_typeNameId = 0; + + Node::accept(m_doc->ast(), this); + if (m_typeNameId) { + for (const ObjectValue *iter = m_context.lookupType(m_doc.data(), m_typeNameId); iter; iter = iter->prototype(&m_context)) { + if (iter->lookupMember(propertyName, &m_context, false)) { + // gotcha! + return iter->className(); + } + ++m_depth; + } + } + //### Eep: we didn't find it... + return QString(); +} + +int PropertyTypeFinder::depth() const +{ + return m_depth; +} + +bool PropertyTypeFinder::visit(QmlJS::AST::UiObjectBinding *ast) +{ + return check(ast->qualifiedTypeNameId); +} + +bool PropertyTypeFinder::visit(QmlJS::AST::UiObjectDefinition *ast) +{ + return check(ast->qualifiedTypeNameId); +} + +bool PropertyTypeFinder::check(QmlJS::AST::UiQualifiedId *qId) +{ + if (!qId) + return true; + + if (qId->identifierToken.startLine == m_objectLine + && qId->identifierToken.startColumn == m_objectColumn) { + // got it! + m_typeNameId = qId; + return false; + } + + return true; +} diff --git a/src/plugins/qmlinspector/components/propertytypefinder.h b/src/plugins/qmlinspector/components/propertytypefinder.h new file mode 100644 index 00000000000..69bc6a272b3 --- /dev/null +++ b/src/plugins/qmlinspector/components/propertytypefinder.h @@ -0,0 +1,45 @@ +#ifndef PROPERTYTYPEFINDER_H +#define PROPERTYTYPEFINDER_H + +#include <qmljs/qmljsdocument.h> +#include <qmljs/parser/qmljsastvisitor_p.h> +#include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljslink.h> + +namespace Qml { +namespace Internal { + +class PropertyTypeFinder: protected QmlJS::AST::Visitor +{ +public: + PropertyTypeFinder(QmlJS::Document::Ptr doc, QmlJS::Snapshot snapshot, const QStringList &importPaths); + + QString operator()(int objectLine, int objectColumn, const QString &propertyName); + int depth() const; +protected: + using QmlJS::AST::Visitor::visit; + + virtual bool visit(QmlJS::AST::UiObjectBinding *ast); + virtual bool visit(QmlJS::AST::UiObjectDefinition *ast); + + +private: + bool check(QmlJS::AST::UiQualifiedId *qId); + +private: + QmlJS::Document::Ptr m_doc; + QmlJS::Snapshot m_snapshot; + QmlJS::Interpreter::Engine m_engine; + QmlJS::Interpreter::Context m_context; + QmlJS::Link m_link; + + quint32 m_objectLine; + quint32 m_objectColumn; + QmlJS::AST::UiQualifiedId *m_typeNameId; + quint8 m_depth; +}; + +} // namespace Internal +} // namespace Qml + +#endif // PROPERTYTYPEFINDER_H diff --git a/src/plugins/qmlinspector/components/qmldebugger.pri b/src/plugins/qmlinspector/components/qmldebugger.pri index aad5eb14fa8..e156668d377 100644 --- a/src/plugins/qmlinspector/components/qmldebugger.pri +++ b/src/plugins/qmlinspector/components/qmldebugger.pri @@ -6,11 +6,14 @@ HEADERS += $$PWD/canvasframerate.h \ $$PWD/watchtable.h \ $$PWD/objecttree.h \ $$PWD/objectpropertiesview.h \ - $$PWD/expressionquerywidget.h + $$PWD/expressionquerywidget.h \ + components/inspectortreeitems.h \ + components/propertytypefinder.h SOURCES += $$PWD/canvasframerate.cpp \ $$PWD/watchtable.cpp \ $$PWD/objecttree.cpp \ $$PWD/objectpropertiesview.cpp \ - $$PWD/expressionquerywidget.cpp - + $$PWD/expressionquerywidget.cpp \ + components/inspectortreeitems.cpp \ + components/propertytypefinder.cpp diff --git a/src/plugins/qmlinspector/inspectorsettings.cpp b/src/plugins/qmlinspector/inspectorsettings.cpp index fcbc951c8c3..b6ad2d86f59 100644 --- a/src/plugins/qmlinspector/inspectorsettings.cpp +++ b/src/plugins/qmlinspector/inspectorsettings.cpp @@ -5,7 +5,8 @@ namespace Qml { namespace Internal { -InspectorSettings::InspectorSettings() : m_externalPort(3768), m_externalUrl("127.0.0.1") +InspectorSettings::InspectorSettings() : m_externalPort(3768), m_externalUrl("127.0.0.1"), +m_showUninspectableItems(false), m_showUnwatchableProperties(false), m_groupPropertiesByItemType(true) { } @@ -15,6 +16,9 @@ void InspectorSettings::readSettings(QSettings *settings) settings->beginGroup(QLatin1String(Qml::Constants::S_QML_INSPECTOR)); m_externalPort= settings->value(QLatin1String(Qml::Constants::S_EXTERNALPORT_KEY), 3768).toUInt(); m_externalUrl = settings->value(QLatin1String(Qml::Constants::S_EXTERNALURL_KEY), "127.0.0.1").toString(); + m_showUninspectableItems = settings->value(QLatin1String(Qml::Constants::S_SHOW_UNINSPECTABLE_ITEMS), false).toBool(); + m_showUnwatchableProperties = settings->value(QLatin1String(Qml::Constants::S_SHOW_UNWATCHABLE_PROPERTIES), false).toBool(); + m_groupPropertiesByItemType = settings->value(QLatin1String(Qml::Constants::S_GROUP_PROPERTIES_BY_ITEM_TYPE), true).toBool(); settings->endGroup(); } @@ -23,6 +27,9 @@ void InspectorSettings::saveSettings(QSettings *settings) const settings->beginGroup(QLatin1String(Qml::Constants::S_QML_INSPECTOR)); settings->setValue(QLatin1String(Qml::Constants::S_EXTERNALPORT_KEY), m_externalPort); settings->setValue(QLatin1String(Qml::Constants::S_EXTERNALURL_KEY), m_externalUrl); + settings->setValue(QLatin1String(Qml::Constants::S_SHOW_UNINSPECTABLE_ITEMS), m_showUninspectableItems); + settings->setValue(QLatin1String(Qml::Constants::S_SHOW_UNWATCHABLE_PROPERTIES), m_showUnwatchableProperties); + settings->setValue(QLatin1String(Qml::Constants::S_GROUP_PROPERTIES_BY_ITEM_TYPE), m_groupPropertiesByItemType); settings->endGroup(); } @@ -46,5 +53,35 @@ void InspectorSettings::setExternalUrl(const QString &url) m_externalUrl = url; } +bool InspectorSettings::showUninspectableItems() const +{ + return m_showUninspectableItems; +} + +bool InspectorSettings::showUnwatchableProperties() const +{ + return m_showUnwatchableProperties; +} + +bool InspectorSettings::groupPropertiesByItemType() const +{ + return m_groupPropertiesByItemType; +} + +void InspectorSettings::setShowUninspectableItems(bool value) +{ + m_showUninspectableItems = value; +} + +void InspectorSettings::setShowUnwatchableProperties(bool value) +{ + m_showUnwatchableProperties = value; +} + +void InspectorSettings::setGroupPropertiesByItemType(bool value) +{ + m_groupPropertiesByItemType = value; +} + } // Internal } // Qml diff --git a/src/plugins/qmlinspector/inspectorsettings.h b/src/plugins/qmlinspector/inspectorsettings.h index 63650721c90..e34dc67835e 100644 --- a/src/plugins/qmlinspector/inspectorsettings.h +++ b/src/plugins/qmlinspector/inspectorsettings.h @@ -17,6 +17,13 @@ public: void readSettings(QSettings *settings); void saveSettings(QSettings *settings) const; + bool groupPropertiesByItemType() const; + bool showUninspectableItems() const; + bool showUnwatchableProperties() const; + void setShowUninspectableItems(bool value); + void setShowUnwatchableProperties(bool value); + void setGroupPropertiesByItemType(bool value); + void setExternalPort(quint16 port); void setExternalUrl(const QString &url); quint16 externalPort() const; @@ -25,6 +32,9 @@ public: private: quint16 m_externalPort; QString m_externalUrl; + bool m_showUninspectableItems; + bool m_showUnwatchableProperties; + bool m_groupPropertiesByItemType; }; diff --git a/src/plugins/qmlinspector/qmlinspector.cpp b/src/plugins/qmlinspector/qmlinspector.cpp index f1fe648521f..c12b5aee756 100644 --- a/src/plugins/qmlinspector/qmlinspector.cpp +++ b/src/plugins/qmlinspector/qmlinspector.cpp @@ -161,7 +161,8 @@ QmlInspector::QmlInspector(QObject *parent) m_propertyWatcherDock(0), m_inspectorOutputDock(0), m_connectionTimer(new QTimer(this)), - m_connectionAttempts(0) + m_connectionAttempts(0), + m_simultaneousCppAndQmlDebugMode(false) { m_instance = this; m_watchTableModel = new Internal::WatchTableModel(0, this); @@ -182,6 +183,8 @@ QmlInspector::QmlInspector(QObject *parent) QmlInspector::~QmlInspector() { + m_objectTreeWidget->saveSettings(m_settings); + m_propertiesWidget->saveSettings(m_settings); m_settings.saveSettings(Core::ICore::instance()->settings()); } @@ -221,6 +224,12 @@ bool QmlInspector::setDebugConfigurationDataFromProject(ProjectExplorer::Project return true; } +void QmlInspector::startQmlProjectDebugger() +{ + m_simultaneousCppAndQmlDebugMode = false; + startConnectionTimer(); +} + void QmlInspector::startConnectionTimer() { m_connectionTimer->start(); @@ -313,7 +322,7 @@ void QmlInspector::connectionStateChanged() void QmlInspector::resetViews() { - m_objectTreeWidget->clear(); + m_objectTreeWidget->cleanup(); m_propertiesWidget->clear(); m_expressionWidget->clear(); m_watchTableModel->removeAllWatches(); @@ -354,9 +363,11 @@ void QmlInspector::createDockWidgets() QVBoxLayout *treeWindowLayout = new QVBoxLayout(treeWindow); treeWindowLayout->setMargin(0); treeWindowLayout->setSpacing(0); + treeWindowLayout->setContentsMargins(0,0,0,0); treeWindowLayout->addWidget(treeOptionBar); treeWindowLayout->addWidget(m_objectTreeWidget); + m_watchTableView->setModel(m_watchTableModel); Internal::WatchTableHeaderView *header = new Internal::WatchTableHeaderView(m_watchTableModel); m_watchTableView->setHorizontalHeader(header); @@ -386,13 +397,20 @@ void QmlInspector::createDockWidgets() m_expressionWidget, SLOT(setCurrentObject(QDeclarativeDebugObjectReference))); - Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Vertical); - propSplitter->addWidget(m_propertiesWidget); - propSplitter->addWidget(m_watchTableView); - propSplitter->setStretchFactor(0, 2); - propSplitter->setStretchFactor(1, 1); + Core::MiniSplitter *propSplitter = new Core::MiniSplitter(Qt::Horizontal); + Core::MiniSplitter *propWatcherSplitter = new Core::MiniSplitter(Qt::Vertical); + propWatcherSplitter->addWidget(m_propertiesWidget); + propWatcherSplitter->addWidget(m_watchTableView); + propWatcherSplitter->setStretchFactor(0, 2); + propWatcherSplitter->setStretchFactor(1, 1); + propWatcherSplitter->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); + propSplitter->setWindowTitle(tr("Properties and Watchers")); propSplitter->setObjectName(QLatin1String("QmlDebugProperties")); + propSplitter->addWidget(m_objectTreeWidget); + propSplitter->addWidget(propWatcherSplitter); + propSplitter->setStretchFactor(0, 1); + propSplitter->setStretchFactor(1, 3); InspectorOutputWidget *inspectorOutput = new InspectorOutputWidget(); inspectorOutput->setObjectName(QLatin1String("QmlDebugInspectorOutput")); @@ -402,8 +420,8 @@ void QmlInspector::createDockWidgets() Debugger::DebuggerUISwitcher *uiSwitcher = Debugger::DebuggerUISwitcher::instance(); m_watchTableView->hide(); - m_objectTreeDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML, - treeWindow, Qt::BottomDockWidgetArea); +// m_objectTreeDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML, +// treeWindow, Qt::BottomDockWidgetArea); // m_frameRateDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML, // m_frameRateWidget, Qt::BottomDockWidgetArea); m_propertyWatcherDock = uiSwitcher->createDockWidget(Qml::Constants::LANG_QML, @@ -417,10 +435,10 @@ void QmlInspector::createDockWidgets() m_inspectorOutputDock->setToolTip(tr("Output of the QML inspector, such as information on connecting to the server.")); - m_dockWidgets << m_objectTreeDock << /*m_frameRateDock << */ m_propertyWatcherDock + m_dockWidgets << /*m_objectTreeDock << *//*m_frameRateDock << */ m_propertyWatcherDock << m_inspectorOutputDock << m_expressionQueryDock; - m_context = new Internal::InspectorContext(m_objectTreeDock); + m_context = new Internal::InspectorContext(m_objectTreeWidget); m_propWatcherContext = new Internal::InspectorContext(m_propertyWatcherDock); Core::ICore *core = Core::ICore::instance(); @@ -440,6 +458,8 @@ void QmlInspector::createDockWidgets() mstart->addAction(cmd, Core::Constants::G_DEFAULT_ONE); m_settings.readSettings(core->settings()); + m_objectTreeWidget->readSettings(m_settings); + m_propertiesWidget->readSettings(m_settings); connect(m_objectTreeWidget, SIGNAL(contextHelpIdChanged(QString)), m_context, SLOT(setContextHelpId(QString))); @@ -503,6 +523,7 @@ void QmlInspector::attachToExternalQmlApplication() connect(debugManager, SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int))); pex->startRunControl(debuggableRunControl, ProjectExplorer::Constants::DEBUGMODE); + m_simultaneousCppAndQmlDebugMode = true; } else { errorMessage = QString(tr("A valid run control was not registered in Qt Creator for this project run configuration.")); @@ -517,22 +538,61 @@ void QmlInspector::attachToExternalQmlApplication() void QmlInspector::debuggerStateChanged(int newState) { + if (!m_simultaneousCppAndQmlDebugMode) + return; + switch(newState) { + case Debugger::EngineStarting: + { + m_connectionInitialized = false; + break; + } case Debugger::AdapterStartFailed: case Debugger::InferiorStartFailed: disconnect(Debugger::DebuggerManager::instance(), SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int))); emit statusMessage(QString(tr("Debugging failed: could not start C++ debugger."))); break; + case Debugger::InferiorRunningRequested: + { + if (m_cppDebuggerState == Debugger::InferiorStopped) { + // re-enable UI again + m_objectTreeWidget->setEnabled(true); + m_propertiesWidget->setEnabled(true); + m_expressionWidget->setEnabled(true); + } + break; + } + case Debugger::InferiorRunning: + { + if (!m_connectionInitialized) { + m_connectionInitialized = true; + m_connectionTimer->setInterval(ConnectionAttemptSimultaneousInterval); + startConnectionTimer(); + } + break; + } + case Debugger::InferiorStopped: + { + m_objectTreeWidget->setEnabled(false); + m_propertiesWidget->setEnabled(false); + m_expressionWidget->setEnabled(false); + break; + } + case Debugger::EngineShuttingDown: + { + m_connectionInitialized = false; + // here it's safe to enable the debugger windows again - + // disabled ones look ugly. + m_objectTreeWidget->setEnabled(true); + m_propertiesWidget->setEnabled(true); + m_expressionWidget->setEnabled(true); + m_simultaneousCppAndQmlDebugMode = false; + break; + } default: break; } - - if (newState == Debugger::InferiorRunning) { - disconnect(Debugger::DebuggerManager::instance(), SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int))); - m_connectionTimer->setInterval(ConnectionAttemptSimultaneousInterval); - startConnectionTimer(); - } - + m_cppDebuggerState = newState; } @@ -551,19 +611,14 @@ void QmlInspector::setSimpleDockWidgetArrangement() foreach (QDockWidget *dockWidget, dockWidgets) { if (m_dockWidgets.contains(dockWidget)) { - if (dockWidget == m_objectTreeDock) - mainWindow->addDockWidget(Qt::RightDockWidgetArea, dockWidget); - else - mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget); + mainWindow->addDockWidget(Qt::BottomDockWidgetArea, dockWidget); dockWidget->show(); - // dockwidget is not actually visible during init because debugger is - // not visible, either. we can use isVisibleTo(), though. } } - //mainWindow->tabifyDockWidget(m_frameRateDock, m_propertyWatcherDock); mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_expressionQueryDock); mainWindow->tabifyDockWidget(m_propertyWatcherDock, m_inspectorOutputDock); + m_propertyWatcherDock->raise(); m_inspectorOutputDock->setVisible(false); diff --git a/src/plugins/qmlinspector/qmlinspector.h b/src/plugins/qmlinspector/qmlinspector.h index 74681909763..a7bbdff6fcc 100644 --- a/src/plugins/qmlinspector/qmlinspector.h +++ b/src/plugins/qmlinspector/qmlinspector.h @@ -94,7 +94,7 @@ public: // returns false if project is not debuggable. bool setDebugConfigurationDataFromProject(ProjectExplorer::Project *projectToDebug); - void startConnectionTimer(); + void startQmlProjectDebugger(); static QmlInspector *instance(); bool canEditProperty(const QString &propertyType); @@ -109,6 +109,7 @@ public slots: void setSimpleDockWidgetArrangement(); private slots: + void startConnectionTimer(); void connectionStateChanged(); void connectionError(); void reloadEngines(); @@ -158,6 +159,10 @@ private: QStringList m_editablePropertyTypes; + int m_cppDebuggerState; + bool m_connectionInitialized; + bool m_simultaneousCppAndQmlDebugMode; + static QmlInspector *m_instance; }; diff --git a/src/plugins/qmlinspector/qmlinspectorconstants.h b/src/plugins/qmlinspector/qmlinspectorconstants.h index 3fd643a1add..f5b23f0ce34 100644 --- a/src/plugins/qmlinspector/qmlinspectorconstants.h +++ b/src/plugins/qmlinspector/qmlinspectorconstants.h @@ -47,6 +47,9 @@ namespace Qml { const char * const S_QML_INSPECTOR = "QML.Inspector"; const char * const S_EXTERNALPORT_KEY = "ExternalPort"; const char * const S_EXTERNALURL_KEY = "ExternalUrl"; + const char * const S_SHOW_UNINSPECTABLE_ITEMS = "ShowUninspectableProperties"; + const char * const S_SHOW_UNWATCHABLE_PROPERTIES = "ShowUninspectableItem"; + const char * const S_GROUP_PROPERTIES_BY_ITEM_TYPE = "GroupPropertiesByItemType"; }; diff --git a/src/plugins/qmlinspector/qmlinspectorplugin.cpp b/src/plugins/qmlinspector/qmlinspectorplugin.cpp index 28a0c400c11..5642682623b 100644 --- a/src/plugins/qmlinspector/qmlinspectorplugin.cpp +++ b/src/plugins/qmlinspector/qmlinspectorplugin.cpp @@ -145,7 +145,7 @@ void QmlInspectorPlugin::activateDebuggerForProject(ProjectExplorer::Project *pr // if they contain Qml files. Some kind of options should exist for this behavior. QmlProjectManager::QmlProject *qmlproj = qobject_cast<QmlProjectManager::QmlProject*>(project); if (qmlproj && m_inspector->setDebugConfigurationDataFromProject(qmlproj)) - m_inspector->startConnectionTimer(); + m_inspector->startQmlProjectDebugger(); } } -- GitLab