QmlJsInspector: implemented Property Inspector

Reviewed-by: Kai Koehne
This commit is contained in:
Christiaan Janssen
2011-01-18 17:17:17 +01:00
parent 6a829f5a8f
commit f5039a4a02
14 changed files with 399 additions and 431 deletions

View File

@@ -57,6 +57,9 @@ public:
explicit CrumblePathButton(const QString &title, QWidget *parent = 0); explicit CrumblePathButton(const QString &title, QWidget *parent = 0);
void setSegmentType(int type); void setSegmentType(int type);
void select(bool s);
void setData(QVariant data);
QVariant data() const;
protected: protected:
void paintEvent(QPaintEvent *); void paintEvent(QPaintEvent *);
void mouseMoveEvent(QMouseEvent *e); void mouseMoveEvent(QMouseEvent *e);
@@ -70,6 +73,7 @@ private:
private: private:
bool m_isHovering; bool m_isHovering;
bool m_isPressed; bool m_isPressed;
bool m_isSelected;
bool m_isEnd; bool m_isEnd;
QColor m_baseColor; QColor m_baseColor;
QImage m_segment; QImage m_segment;
@@ -79,10 +83,12 @@ private:
QImage m_segmentHover; QImage m_segmentHover;
QImage m_segmentHoverEnd; QImage m_segmentHoverEnd;
QPoint m_textPos; QPoint m_textPos;
QVariant m_data;
}; };
CrumblePathButton::CrumblePathButton(const QString &title, QWidget *parent) CrumblePathButton::CrumblePathButton(const QString &title, QWidget *parent)
: QPushButton(title, parent), m_isHovering(false), m_isPressed(false), m_isEnd(true) : QPushButton(title, parent), m_isHovering(false), m_isPressed(false), m_isSelected(false), m_isEnd(true)
{ {
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
setToolTip(title); setToolTip(title);
@@ -114,7 +120,7 @@ void CrumblePathButton::paintEvent(QPaintEvent *)
} }
if (m_isEnd) { if (m_isEnd) {
if (m_isPressed) { if (m_isPressed || m_isSelected) {
Utils::StyleHelper::drawCornerImage(m_segmentSelectedEnd, &p, geom, 2, 0, 2, 0); Utils::StyleHelper::drawCornerImage(m_segmentSelectedEnd, &p, geom, 2, 0, 2, 0);
} else if (m_isHovering) { } else if (m_isHovering) {
Utils::StyleHelper::drawCornerImage(m_segmentHoverEnd, &p, geom, 2, 0, 2, 0); Utils::StyleHelper::drawCornerImage(m_segmentHoverEnd, &p, geom, 2, 0, 2, 0);
@@ -122,7 +128,7 @@ void CrumblePathButton::paintEvent(QPaintEvent *)
Utils::StyleHelper::drawCornerImage(m_segmentEnd, &p, geom, 2, 0, 2, 0); Utils::StyleHelper::drawCornerImage(m_segmentEnd, &p, geom, 2, 0, 2, 0);
} }
} else { } else {
if (m_isPressed) { if (m_isPressed || m_isSelected) {
Utils::StyleHelper::drawCornerImage(m_segmentSelected, &p, geom, 2, 0, 12, 0); Utils::StyleHelper::drawCornerImage(m_segmentSelected, &p, geom, 2, 0, 12, 0);
} else if (m_isHovering) { } else if (m_isHovering) {
Utils::StyleHelper::drawCornerImage(m_segmentHover, &p, geom, 2, 0, 12, 0); Utils::StyleHelper::drawCornerImage(m_segmentHover, &p, geom, 2, 0, 12, 0);
@@ -175,6 +181,12 @@ void CrumblePathButton::mouseReleaseEvent(QMouseEvent *e)
update(); update();
} }
void CrumblePathButton::select(bool s)
{
m_isSelected = s;
update();
}
void CrumblePathButton::setSegmentType(int type) void CrumblePathButton::setSegmentType(int type)
{ {
bool useLeftPadding = !(type & FirstSegment); bool useLeftPadding = !(type & FirstSegment);
@@ -182,6 +194,16 @@ void CrumblePathButton::setSegmentType(int type)
m_textPos.setX(useLeftPadding ? 18 : 4); m_textPos.setX(useLeftPadding ? 18 : 4);
} }
void CrumblePathButton::setData(QVariant data)
{
m_data = data;
}
QVariant CrumblePathButton::data() const
{
return m_data;
}
struct CrumblePathPrivate { struct CrumblePathPrivate {
explicit CrumblePathPrivate(CrumblePath *q); explicit CrumblePathPrivate(CrumblePath *q);
@@ -216,12 +238,25 @@ CrumblePath::~CrumblePath()
d->m_buttons.clear(); d->m_buttons.clear();
} }
void CrumblePath::selectIndex(int index)
{
if ((index > -1) && (index < d->m_buttons.length()))
d->m_buttons[index]->select(true);
}
QVariant CrumblePath::dataForIndex(int index) const
{
if ((index > -1) && (index < d->m_buttons.length()))
return d->m_buttons[index]->data();
return QVariant();
}
void CrumblePath::setBackgroundStyle() void CrumblePath::setBackgroundStyle()
{ {
d->m_background->setStyleSheet("QWidget { background-color:" + d->m_baseColor.name() + ";}"); d->m_background->setStyleSheet("QWidget { background-color:" + d->m_baseColor.name() + ";}");
} }
void CrumblePath::pushElement(const QString &title) void CrumblePath::pushElement(const QString &title, const QVariant data)
{ {
CrumblePathButton *newButton = new CrumblePathButton(title, this); CrumblePathButton *newButton = new CrumblePathButton(title, this);
newButton->hide(); newButton->hide();
@@ -237,6 +272,7 @@ void CrumblePath::pushElement(const QString &title)
segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment; segType = CrumblePathButton::FirstSegment | CrumblePathButton::LastSegment;
newButton->setSegmentType(segType); newButton->setSegmentType(segType);
} }
newButton->setData(data);
d->m_buttons.append(newButton); d->m_buttons.append(newButton);
resizeButtons(); resizeButtons();
@@ -272,8 +308,6 @@ void CrumblePath::resizeEvent(QResizeEvent *)
void CrumblePath::resizeButtons() void CrumblePath::resizeButtons()
{ {
int buttonMinWidth = 0;
int buttonMaxWidth = 0;
int totalWidthLeft = width(); int totalWidthLeft = width();
if (d->m_buttons.length() >= 1) { if (d->m_buttons.length() >= 1) {
@@ -281,26 +315,34 @@ void CrumblePath::resizeButtons()
d->m_buttons[0]->raise(); d->m_buttons[0]->raise();
// rearrange all items so that the first item is on top (added last). // rearrange all items so that the first item is on top (added last).
// compute relative sizes
QList <int> sizes;
int totalSize = 0;
for(int i = 0; i < d->m_buttons.length() ; ++i) { for(int i = 0; i < d->m_buttons.length() ; ++i) {
CrumblePathButton *button = d->m_buttons[i]; CrumblePathButton *button = d->m_buttons[i];
QFontMetrics fm(button->font()); QFontMetrics fm(button->font());
buttonMinWidth = ArrowBorderSize + fm.width(button->text()) + ArrowBorderSize * 2 ; int originalSize = ArrowBorderSize + fm.width(button->text()) + ArrowBorderSize + 12;
buttonMaxWidth = (totalWidthLeft + ArrowBorderSize * (d->m_buttons.length() - i)) / (d->m_buttons.length() - i); sizes << originalSize;
totalSize += originalSize - ArrowBorderSize;
}
if (buttonMinWidth > buttonMaxWidth && i < d->m_buttons.length() - 1) { for (int i = 0; i < d->m_buttons.length() ; ++i) {
buttonMinWidth = buttonMaxWidth; CrumblePathButton *button = d->m_buttons[i];
} else if (i > 3 && (i == d->m_buttons.length() - 1)) {
buttonMinWidth = width() - nextElementPosition.x();
buttonMaxWidth = buttonMinWidth;
}
button->setMinimumWidth(buttonMinWidth); int candidateSize = (sizes[i]*totalWidthLeft)/totalSize;
button->setMaximumWidth(buttonMaxWidth); if (candidateSize < ArrowBorderSize)
candidateSize = ArrowBorderSize;
if (candidateSize > sizes[i]*1.3)
candidateSize = sizes[i]*1.3;
button->setMinimumWidth(candidateSize);
button->setMaximumWidth(candidateSize);
button->move(nextElementPosition); button->move(nextElementPosition);
nextElementPosition.rx() += button->width() - ArrowBorderSize; nextElementPosition.rx() += button->width() - ArrowBorderSize;
totalWidthLeft -= button->width();
button->show(); button->show();
if (i > 0) if (i > 0)

View File

@@ -37,6 +37,7 @@
#include "utils_global.h" #include "utils_global.h"
#include <QtGui/QWidget> #include <QtGui/QWidget>
#include <QVariant>
QT_FORWARD_DECLARE_CLASS(QResizeEvent) QT_FORWARD_DECLARE_CLASS(QResizeEvent)
@@ -50,9 +51,11 @@ class QTCREATOR_UTILS_EXPORT CrumblePath : public QWidget
public: public:
explicit CrumblePath(QWidget *parent = 0); explicit CrumblePath(QWidget *parent = 0);
~CrumblePath(); ~CrumblePath();
void selectIndex(int index);
QVariant dataForIndex(int index) const;
public slots: public slots:
void pushElement(const QString &title); void pushElement(const QString &title, const QVariant data = QVariant());
void popElement(); void popElement();
void clear(); void clear();

View File

@@ -1054,22 +1054,6 @@ protected:
return 0; return 0;
} }
inline bool hasVisualPresentation(Node *ast)
{
Bind *bind = m_lookupContext->document()->bind();
const Interpreter::ObjectValue *objValue = bind->findQmlObject(ast);
if (!objValue)
return false;
QStringList prototypes;
foreach (const Interpreter::ObjectValue *value,
Interpreter::PrototypeIterator(objValue, m_lookupContext->context()).all()) {
prototypes.append(value->className());
}
return prototypes.contains(QString("QGraphicsObject"));
}
inline bool isIdBinding(UiObjectMember *member) const inline bool isIdBinding(UiObjectMember *member) const
{ {
if (UiScriptBinding *script = cast<UiScriptBinding *>(member)) { if (UiScriptBinding *script = cast<UiScriptBinding *>(member)) {
@@ -1116,7 +1100,7 @@ protected:
if ((isRangeSelected() && intersectsCursor(begin, end)) if ((isRangeSelected() && intersectsCursor(begin, end))
|| (!isRangeSelected() && containsCursor(begin, end))) || (!isRangeSelected() && containsCursor(begin, end)))
{ {
if (initializer(member) && isSelectable(member) && hasVisualPresentation(member)) { if (initializer(member) && isSelectable(member)) {
m_selectedMembers << member; m_selectedMembers << member;
// move start towards end; this facilitates multiselection so that root is usually ignored. // move start towards end; this facilitates multiselection so that root is usually ignored.
m_cursorPositionStart = qMin(end, m_cursorPositionEnd); m_cursorPositionStart = qMin(end, m_cursorPositionEnd);

View File

@@ -43,13 +43,13 @@
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <utils/styledbar.h> #include <utils/styledbar.h>
#include <utils/filterlineedit.h>
#include <QAction> #include <QAction>
#include <QActionGroup> #include <QActionGroup>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMenu> #include <QMenu>
#include <QToolButton> #include <QToolButton>
#include <QLineEdit>
namespace QmlJSInspector { namespace QmlJSInspector {
namespace Internal { namespace Internal {
@@ -78,6 +78,7 @@ QmlInspectorToolbar::QmlInspectorToolbar(QObject *parent) :
m_menuPauseAction(0), m_menuPauseAction(0),
m_playIcon(QIcon(QLatin1String(":/qml/images/play-small.png"))), m_playIcon(QIcon(QLatin1String(":/qml/images/play-small.png"))),
m_pauseIcon(QIcon(QLatin1String(":/qml/images/pause-small.png"))), m_pauseIcon(QIcon(QLatin1String(":/qml/images/pause-small.png"))),
m_filterExp(0),
m_colorBox(0), m_colorBox(0),
m_emitSignals(true), m_emitSignals(true),
m_isRunning(false), m_isRunning(false),
@@ -98,6 +99,7 @@ void QmlInspectorToolbar::setEnabled(bool value)
m_zoomAction->setEnabled(value); m_zoomAction->setEnabled(value);
m_colorPickerAction->setEnabled(value); m_colorPickerAction->setEnabled(value);
m_colorBox->setEnabled(value); m_colorBox->setEnabled(value);
m_filterExp->setEnabled(value);
} }
void QmlInspectorToolbar::enable() void QmlInspectorToolbar::enable()
@@ -295,6 +297,10 @@ void QmlInspectorToolbar::createActions(const Core::Context &context)
m_colorBox->setInnerBorderColor(QColor(192,192,192)); m_colorBox->setInnerBorderColor(QColor(192,192,192));
m_colorBox->setOuterBorderColor(QColor(58,58,58)); m_colorBox->setOuterBorderColor(QColor(58,58,58));
configBarLayout->addWidget(m_colorBox); configBarLayout->addWidget(m_colorBox);
m_filterExp = new QLineEdit(m_barWidget);
m_filterExp->setPlaceholderText("<filter property list>");
configBarLayout->addWidget(m_filterExp);
configBarLayout->addStretch(); configBarLayout->addStretch();
setEnabled(false); setEnabled(false);
@@ -307,6 +313,7 @@ void QmlInspectorToolbar::createActions(const Core::Context &context)
connect(m_selectAction, SIGNAL(triggered()), SLOT(activateSelectToolOnClick())); connect(m_selectAction, SIGNAL(triggered()), SLOT(activateSelectToolOnClick()));
connect(m_zoomAction, SIGNAL(triggered()), SLOT(activateZoomOnClick())); connect(m_zoomAction, SIGNAL(triggered()), SLOT(activateZoomOnClick()));
connect(m_colorPickerAction, SIGNAL(triggered()), SLOT(activateColorPickerOnClick())); connect(m_colorPickerAction, SIGNAL(triggered()), SLOT(activateColorPickerOnClick()));
connect(m_filterExp, SIGNAL(textChanged(QString)), SIGNAL(filterTextChanged(QString)));
} }
QWidget *QmlInspectorToolbar::widget() const QWidget *QmlInspectorToolbar::widget() const

View File

@@ -40,6 +40,7 @@
QT_FORWARD_DECLARE_CLASS(QAction) QT_FORWARD_DECLARE_CLASS(QAction)
QT_FORWARD_DECLARE_CLASS(QColor) QT_FORWARD_DECLARE_CLASS(QColor)
QT_FORWARD_DECLARE_CLASS(QToolButton) QT_FORWARD_DECLARE_CLASS(QToolButton)
QT_FORWARD_DECLARE_CLASS(QLineEdit)
namespace Core { namespace Core {
class Context; class Context;
@@ -98,6 +99,7 @@ signals:
void showAppOnTopSelected(bool isChecked); void showAppOnTopSelected(bool isChecked);
void animationSpeedChanged(qreal slowdownFactor = 1.0f); void animationSpeedChanged(qreal slowdownFactor = 1.0f);
void filterTextChanged(const QString &);
private slots: private slots:
void activateDesignModeOnClick(); void activateDesignModeOnClick();
@@ -140,6 +142,8 @@ private:
QIcon m_playIcon; QIcon m_playIcon;
QIcon m_pauseIcon; QIcon m_pauseIcon;
QLineEdit *m_filterExp;
ToolBarColorBox *m_colorBox; ToolBarColorBox *m_colorBox;
bool m_emitSignals; bool m_emitSignals;

View File

@@ -157,6 +157,8 @@ void ClientProxy::disconnectFromServer()
qDeleteAll(m_objectTreeQuery); qDeleteAll(m_objectTreeQuery);
m_objectTreeQuery.clear(); m_objectTreeQuery.clear();
removeAllObjectWatches();
updateConnected(); updateConnected();
} }
@@ -226,7 +228,7 @@ QDeclarativeDebugObjectReference ClientProxy::objectReferenceForId(int debugId,
if (objectRef.debugId() == debugId) if (objectRef.debugId() == debugId)
return objectRef; return objectRef;
foreach(const QDeclarativeDebugObjectReference &child, objectRef.children()) { foreach (const QDeclarativeDebugObjectReference &child, objectRef.children()) {
QDeclarativeDebugObjectReference result = objectReferenceForId(debugId, child); QDeclarativeDebugObjectReference result = objectReferenceForId(debugId, child);
if (result.debugId() == debugId) if (result.debugId() == debugId)
return result; return result;
@@ -261,7 +263,7 @@ QDeclarativeDebugObjectReference ClientProxy::objectReferenceForLocation(const i
QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences() const QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences() const
{ {
QList<QDeclarativeDebugObjectReference> result; QList<QDeclarativeDebugObjectReference> result;
foreach(const QDeclarativeDebugObjectReference &it, m_rootObjects) { foreach (const QDeclarativeDebugObjectReference &it, m_rootObjects) {
result.append(objectReferences(it)); result.append(objectReferences(it));
} }
return result; return result;
@@ -272,7 +274,7 @@ QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences(const QDec
QList<QDeclarativeDebugObjectReference> result; QList<QDeclarativeDebugObjectReference> result;
result.append(objectRef); result.append(objectRef);
foreach(const QDeclarativeDebugObjectReference &child, objectRef.children()) { foreach (const QDeclarativeDebugObjectReference &child, objectRef.children()) {
result.append(objectReferences(child)); result.append(objectReferences(child));
} }
@@ -331,6 +333,64 @@ void ClientProxy::clearComponentCache()
m_observerClient->clearComponentCache(); m_observerClient->clearComponentCache();
} }
bool ClientProxy::addObjectWatch(int objectDebugId)
{
if (debug)
qDebug() << "addObjectWatch():" << objectDebugId;
if (objectDebugId == -1)
return false;
// already set
if (m_objectWatches.keys().contains(objectDebugId))
return true;
QDeclarativeDebugObjectReference ref = objectReferenceForId(objectDebugId);
if (ref.debugId() != objectDebugId)
return false;
QDeclarativeDebugWatch *watch = m_engineClient->addWatch(ref, this);
m_objectWatches.insert(objectDebugId, watch);
connect(watch,SIGNAL(valueChanged(QByteArray,QVariant)),this,SLOT(objectWatchTriggered(QByteArray,QVariant)));
return false;
}
void ClientProxy::objectWatchTriggered(const QByteArray &propertyName, const QVariant &propertyValue)
{
QDeclarativeDebugWatch *watch = dynamic_cast<QDeclarativeDebugWatch *>(QObject::sender());
if (watch)
emit propertyChanged(watch->objectDebugId(),propertyName, propertyValue);
}
bool ClientProxy::removeObjectWatch(int objectDebugId)
{
if (debug)
qDebug() << "removeObjectWatch():" << objectDebugId;
if (objectDebugId == -1)
return false;
if (!m_objectWatches.keys().contains(objectDebugId))
return false;
QDeclarativeDebugWatch *watch = m_objectWatches.value(objectDebugId);
disconnect(watch,SIGNAL(valueChanged(QByteArray,QVariant)), this, SLOT(objectWatchTriggered(QByteArray,QVariant)));
m_engineClient->removeWatch(watch);
delete watch;
m_objectWatches.remove(objectDebugId);
return true;
}
void ClientProxy::removeAllObjectWatches()
{
foreach (int watchedObject, m_objectWatches.keys())
removeObjectWatch(watchedObject);
Q_ASSERT(m_objectWatches.count() == 0);
}
void ClientProxy::queryEngineContext(int id) void ClientProxy::queryEngineContext(int id)
{ {
if (id < 0) if (id < 0)
@@ -403,7 +463,7 @@ void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state)
int old_count = m_debugIdHash.count(); int old_count = m_debugIdHash.count();
m_debugIdHash.clear(); m_debugIdHash.clear();
m_debugIdHash.reserve(old_count + 1); m_debugIdHash.reserve(old_count + 1);
foreach(const QDeclarativeDebugObjectReference &it, m_rootObjects) foreach (const QDeclarativeDebugObjectReference &it, m_rootObjects)
buildDebugIdHashRecursive(it); buildDebugIdHashRecursive(it);
emit objectTreeUpdated(); emit objectTreeUpdated();
@@ -445,7 +505,7 @@ void ClientProxy::buildDebugIdHashRecursive(const QDeclarativeDebugObjectReferen
// append the debug ids in the hash // append the debug ids in the hash
m_debugIdHash[qMakePair<QString, int>(filename, rev)][qMakePair<int, int>(lineNum, colNum)].append(ref.debugId()); m_debugIdHash[qMakePair<QString, int>(filename, rev)][qMakePair<int, int>(lineNum, colNum)].append(ref.debugId());
foreach(const QDeclarativeDebugObjectReference &it, ref.children()) foreach (const QDeclarativeDebugObjectReference &it, ref.children())
buildDebugIdHashRecursive(it); buildDebugIdHashRecursive(it);
} }

View File

@@ -70,6 +70,10 @@ public:
QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent=0); QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent=0);
void clearComponentCache(); void clearComponentCache();
bool addObjectWatch(int objectDebugId);
bool removeObjectWatch(int objectDebugId);
void removeAllObjectWatches();
// returns the object references // returns the object references
QList<QDeclarativeDebugObjectReference> objectReferences() const; QList<QDeclarativeDebugObjectReference> objectReferences() const;
QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const; QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const;
@@ -108,6 +112,7 @@ signals:
void serverReloaded(); void serverReloaded();
void selectedColorChanged(const QColor &color); void selectedColorChanged(const QColor &color);
void contextPathUpdated(const QStringList &contextPath); void contextPathUpdated(const QStringList &contextPath);
void propertyChanged(int debugId, const QByteArray &propertyName, const QVariant &propertyValue);
public slots: public slots:
void refreshObjectTree(); void refreshObjectTree();
@@ -139,6 +144,7 @@ private slots:
void objectTreeFetched(QDeclarativeDebugQuery::State state = QDeclarativeDebugQuery::Completed); void objectTreeFetched(QDeclarativeDebugQuery::State state = QDeclarativeDebugQuery::Completed);
void fetchContextObjectRecursive(const QmlJsDebugClient::QDeclarativeDebugContextReference& context); void fetchContextObjectRecursive(const QmlJsDebugClient::QDeclarativeDebugContextReference& context);
void newObjects(); void newObjects();
void objectWatchTriggered(const QByteArray &propertyName, const QVariant &propertyValue);
private: private:
void updateConnected(); void updateConnected();
@@ -164,6 +170,8 @@ private:
QTimer m_requestObjectsTimer; QTimer m_requestObjectsTimer;
DebugIdHash m_debugIdHash; DebugIdHash m_debugIdHash;
QHash<int, QDeclarativeDebugWatch *> m_objectWatches;
bool m_isConnected; bool m_isConnected;
}; };

View File

@@ -42,7 +42,7 @@ ContextCrumblePath::ContextCrumblePath(QWidget *parent)
: CrumblePath(parent), m_isEmpty(true) : CrumblePath(parent), m_isEmpty(true)
{ {
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
updateContextPath(QStringList()); updateContextPath(QStringList(),QList<int>());
} }
ContextCrumblePath::~ContextCrumblePath() ContextCrumblePath::~ContextCrumblePath()
@@ -50,11 +50,14 @@ ContextCrumblePath::~ContextCrumblePath()
} }
void ContextCrumblePath::updateContextPath(const QStringList &path) void ContextCrumblePath::updateContextPath(const QStringList &path, const QList<int> &debugIds)
{ {
Q_ASSERT(path.count() == debugIds.count());
clear(); clear();
foreach(const QString &pathPart, path) {
pushElement(pathPart); for (int i=0; i<path.count(); i++) {
pushElement(path[i],QVariant(debugIds[i]));
} }
m_isEmpty = path.isEmpty(); m_isEmpty = path.isEmpty();
@@ -63,10 +66,20 @@ void ContextCrumblePath::updateContextPath(const QStringList &path)
} }
} }
void ContextCrumblePath::selectIndex(int index)
{
CrumblePath::selectIndex(index);
}
bool ContextCrumblePath::isEmpty() const bool ContextCrumblePath::isEmpty() const
{ {
return m_isEmpty; return m_isEmpty;
} }
int ContextCrumblePath::debugIdForIndex(int index) const
{
return CrumblePath::dataForIndex(index).toInt();
}
} // namespace Internal } // namespace Internal
} // namespace QmlJSInspector } // namespace QmlJSInspector

View File

@@ -46,9 +46,11 @@ public:
ContextCrumblePath(QWidget *parent = 0); ContextCrumblePath(QWidget *parent = 0);
virtual ~ContextCrumblePath(); virtual ~ContextCrumblePath();
bool isEmpty() const; bool isEmpty() const;
int debugIdForIndex(int index) const;
public slots: public slots:
void updateContextPath(const QStringList &path); void updateContextPath(const QStringList &path, const QList<int> &debugIds);
void selectIndex(int index);
private: private:
bool m_isEmpty; bool m_isEmpty;
}; };

View File

@@ -39,7 +39,7 @@
#include "qmljsprivateapi.h" #include "qmljsprivateapi.h"
#include "qmljscontextcrumblepath.h" #include "qmljscontextcrumblepath.h"
#include "qmljsinspectorsettings.h" #include "qmljsinspectorsettings.h"
#include "qmljsobjecttree.h" #include "qmljspropertyinspector.h"
#include <qmljs/qmljsmodelmanagerinterface.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljs/qmljsdocument.h> #include <qmljs/qmljsdocument.h>
@@ -126,13 +126,13 @@ InspectorUi::InspectorUi(QObject *parent)
, m_listeningToEditorManager(false) , m_listeningToEditorManager(false)
, m_toolbar(0) , m_toolbar(0)
, m_crumblePath(0) , m_crumblePath(0)
, m_objectTreeWidget(0) , m_propertyInspector(0)
, m_settings(new InspectorSettings(this)) , m_settings(new InspectorSettings(this))
, m_clientProxy(0) , m_clientProxy(0)
, m_qmlEngine(0) , m_qmlEngine(0)
, m_debugQuery(0) , m_debugQuery(0)
, m_lastSelectedDebugId(-1)
, m_debugProject(0) , m_debugProject(0)
, m_selectionCallbackExpected(false)
{ {
m_instance = this; m_instance = this;
m_toolbar = new QmlInspectorToolbar(this); m_toolbar = new QmlInspectorToolbar(this);
@@ -225,7 +225,7 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE
if ((qmlNode->kind == QmlJS::AST::Node::Kind_IdentifierExpression) && if ((qmlNode->kind == QmlJS::AST::Node::Kind_IdentifierExpression) &&
(m_clientProxy->objectReferenceForId(refToLook).debugId() == -1)) { (m_clientProxy->objectReferenceForId(refToLook).debugId() == -1)) {
query = doubleQuote + QString("local: ") + refToLook + doubleQuote; query = doubleQuote + QString("local: ") + refToLook + doubleQuote;
foreach(QDeclarativeDebugPropertyReference property, ref.properties()) { foreach (QDeclarativeDebugPropertyReference property, ref.properties()) {
if (property.name() == wordAtCursor if (property.name() == wordAtCursor
&& !property.valueTypeName().isEmpty()) { && !property.valueTypeName().isEmpty()) {
query = doubleQuote + property.name() + QLatin1Char(':') query = doubleQuote + property.name() + QLatin1Char(':')
@@ -239,7 +239,7 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE
+ QLatin1Char('+') + refToLook; + QLatin1Char('+') + refToLook;
} else { } else {
// show properties // show properties
foreach(QDeclarativeDebugPropertyReference property, ref.properties()) { foreach (QDeclarativeDebugPropertyReference property, ref.properties()) {
if (property.name() == wordAtCursor && !property.valueTypeName().isEmpty()) { if (property.name() == wordAtCursor && !property.valueTypeName().isEmpty()) {
query = doubleQuote + property.name() + QLatin1Char(':') query = doubleQuote + property.name() + QLatin1Char(':')
+ doubleQuote + QLatin1Char('+') + property.name(); + doubleQuote + QLatin1Char('+') + property.name();
@@ -250,7 +250,7 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE
} }
if (!query.isEmpty()) { if (!query.isEmpty()) {
m_debugQuery = m_clientProxy->queryExpressionResult(ref.debugId(),query); m_debugQuery = m_clientProxy->queryExpressionResult(ref.debugId(),query, this);
connect(m_debugQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)), connect(m_debugQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),
this, SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State))); this, SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State)));
} }
@@ -281,13 +281,23 @@ void InspectorUi::connected(ClientProxy *clientProxy)
{ {
m_clientProxy = clientProxy; m_clientProxy = clientProxy;
QmlJS::Snapshot snapshot = modelManager()->snapshot();
for (QHash<QString, QmlJSLiveTextPreview *>::const_iterator it = m_textPreviews.constBegin();
it != m_textPreviews.constEnd(); ++it) {
Document::Ptr doc = snapshot.document(it.key());
it.value()->resetInitialDoc(doc);
}
connect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), connect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
SLOT(gotoObjectReferenceDefinition(QList<QDeclarativeDebugObjectReference>))); SLOT(selectItems(QList<QDeclarativeDebugObjectReference>)));
connect(m_clientProxy, SIGNAL(enginesChanged()), SLOT(updateEngineList())); connect(m_clientProxy, SIGNAL(enginesChanged()), SLOT(updateEngineList()));
connect(m_clientProxy, SIGNAL(serverReloaded()), this, SLOT(serverReloaded())); connect(m_clientProxy, SIGNAL(serverReloaded()), this, SLOT(serverReloaded()));
connect(m_clientProxy, SIGNAL(contextPathUpdated(QStringList)), connect(m_clientProxy, SIGNAL(propertyChanged(int, QByteArray,QVariant)),
m_crumblePath, SLOT(updateContextPath(QStringList))); m_propertyInspector, SLOT(propertyValueChanged(int, QByteArray,QVariant)));
connect(m_propertyInspector, SIGNAL(changePropertyValue(int,QString,QString)),
this, SLOT(changePropertyValue(int,QString,QString)));
connect(m_clientProxy,SIGNAL(objectTreeUpdated()),this,SLOT(objectTreeReady()));
m_debugProject = ProjectExplorer::ProjectExplorerPlugin::instance()->startupProject(); m_debugProject = ProjectExplorer::ProjectExplorerPlugin::instance()->startupProject();
if (m_debugProject->activeTarget() if (m_debugProject->activeTarget()
@@ -307,22 +317,34 @@ void InspectorUi::connected(ClientProxy *clientProxy)
initializeDocuments(); initializeDocuments();
QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews); QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews);
while(iter.hasNext()) { while (iter.hasNext()) {
iter.next(); iter.next();
iter.value()->setClientProxy(m_clientProxy); iter.value()->setClientProxy(m_clientProxy);
iter.value()->updateDebugIds(); iter.value()->updateDebugIds();
} }
}
void InspectorUi::objectTreeReady()
{
// Should only run once, after debugger startup
if (!m_clientProxy->rootObjectReference().isEmpty()) {
selectItems(m_clientProxy->rootObjectReference());
disconnect(m_clientProxy,SIGNAL(objectTreeUpdated()),this,SLOT(objectTreeReady()));
}
} }
void InspectorUi::disconnected() void InspectorUi::disconnected()
{ {
disconnect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), disconnect(m_clientProxy, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)),
this, SLOT(gotoObjectReferenceDefinition(QList<QDeclarativeDebugObjectReference>))); this, SLOT(selectItems(QList<QDeclarativeDebugObjectReference>)));
disconnect(m_clientProxy, SIGNAL(enginesChanged()), this, SLOT(updateEngineList())); disconnect(m_clientProxy, SIGNAL(enginesChanged()), this, SLOT(updateEngineList()));
disconnect(m_clientProxy, SIGNAL(serverReloaded()), this, SLOT(serverReloaded())); disconnect(m_clientProxy, SIGNAL(serverReloaded()), this, SLOT(serverReloaded()));
disconnect(m_clientProxy, SIGNAL(contextPathUpdated(QStringList)), disconnect(m_clientProxy, SIGNAL(propertyChanged(int, QByteArray,QVariant)),
m_crumblePath, SLOT(updateContextPath(QStringList))); m_propertyInspector, SLOT(propertyValueChanged(int, QByteArray,QVariant)));
disconnect(m_propertyInspector, SIGNAL(changePropertyValue(int,QString,QString)),
this, SLOT(changePropertyValue(int,QString,QString)));
m_debugProject = 0; m_debugProject = 0;
m_qmlEngine = 0; m_qmlEngine = 0;
@@ -332,12 +354,12 @@ void InspectorUi::disconnected()
applyChangesToQmlObserverHelper(false); applyChangesToQmlObserverHelper(false);
QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews); QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews);
while(iter.hasNext()) { while (iter.hasNext()) {
iter.next(); iter.next();
iter.value()->setClientProxy(0); iter.value()->setClientProxy(0);
} }
m_clientProxy = 0; m_clientProxy = 0;
m_objectTreeWidget->clear(); m_propertyInspector->clear();
m_pendingPreviewDocumentNames.clear(); m_pendingPreviewDocumentNames.clear();
} }
@@ -357,19 +379,20 @@ void InspectorUi::updateEngineList()
void InspectorUi::changeSelectedItems(const QList<QDeclarativeDebugObjectReference> &objects) void InspectorUi::changeSelectedItems(const QList<QDeclarativeDebugObjectReference> &objects)
{ {
if (m_lastSelectedDebugId >= 0) { if (m_selectionCallbackExpected) {
foreach (const QDeclarativeDebugObjectReference &ref, objects) { m_selectionCallbackExpected = false;
if (ref.debugId() == m_lastSelectedDebugId) { return;
// this is only the 'call back' after we have programatically set a new cursor
// position in
m_lastSelectedDebugId = -1;
return;
}
}
m_lastSelectedDebugId = -1;
} }
m_clientProxy->setSelectedItemsByObjectId(objects); // QmlJSLiveTextPreview doesn't provide valid references, only correct debugIds. We need to remap them
QList <QDeclarativeDebugObjectReference> realList;
foreach (const QDeclarativeDebugObjectReference &obj, objects) {
QDeclarativeDebugObjectReference clientRef = m_clientProxy->objectReferenceForId(obj.debugId());
realList << clientRef;
}
m_clientProxy->setSelectedItemsByObjectId(realList);
selectItems(realList);
} }
void InspectorUi::initializeDocuments() void InspectorUi::initializeDocuments()
@@ -474,7 +497,8 @@ void InspectorUi::currentDebugProjectRemoved()
void InspectorUi::resetViews() void InspectorUi::resetViews()
{ {
m_crumblePath->updateContextPath(QStringList()); m_propertyInspector->clear();
m_crumblePath->clear();
} }
void InspectorUi::reloadQmlViewer() void InspectorUi::reloadQmlViewer()
@@ -483,31 +507,170 @@ void InspectorUi::reloadQmlViewer()
m_clientProxy->reloadQmlViewer(); m_clientProxy->reloadQmlViewer();
} }
void InspectorUi::gotoObjectReferenceDefinition(QList<QDeclarativeDebugObjectReference> inline QDeclarativeDebugObjectReference findParentRecursive( int goalDebugId,
objectReferences) const QList< QDeclarativeDebugObjectReference > &objectsToSearch)
{ {
if (objectReferences.length()) if (goalDebugId == -1)
gotoObjectReferenceDefinition(objectReferences.first()); return QDeclarativeDebugObjectReference();
foreach (const QDeclarativeDebugObjectReference &possibleParent, objectsToSearch) {
// Am I a root object? No parent
if ( possibleParent.debugId() == goalDebugId )
return QDeclarativeDebugObjectReference();
// Is the goal one of my children?
foreach (const QDeclarativeDebugObjectReference &child, possibleParent.children())
if ( child.debugId() == goalDebugId )
return possibleParent;
// no luck? pass this on
QDeclarativeDebugObjectReference candidate = findParentRecursive(goalDebugId, possibleParent.children());
if (candidate.debugId() != -1)
return candidate;
}
return QDeclarativeDebugObjectReference();
}
void InspectorUi::selectItems(const QList<QDeclarativeDebugObjectReference> &objectReferences)
{
foreach (const QDeclarativeDebugObjectReference &objref, objectReferences)
if (objref.debugId() != -1) {
// select only the first valid element of the list
m_clientProxy->removeAllObjectWatches();
m_clientProxy->addObjectWatch(objref.debugId());
QList <QDeclarativeDebugObjectReference> selectionList;
selectionList << objref;
m_propertyInspector->setCurrentObjects(selectionList);
populateCrumblePath(objref);
gotoObjectReferenceDefinition(objref);
return;
}
// empty list
m_propertyInspector->clear();
m_crumblePath->clear();
}
inline QString displayName(const QDeclarativeDebugObjectReference &obj)
{
// special! state names
if (obj.className() == "State") {
foreach (const QDeclarativeDebugPropertyReference &prop, obj.properties()) {
if (prop.name() == "name")
return prop.value().toString();
}
}
// has id?
if (!obj.idString().isEmpty())
return obj.idString();
// return the simplified class name then
QString objTypeName = obj.className();
QString declarativeString("QDeclarative");
if (objTypeName.startsWith(declarativeString)) {
objTypeName = objTypeName.mid(declarativeString.length()).section('_',0,0);
}
return QString("<%1>").arg(objTypeName);
}
bool InspectorUi::isRoot(const QDeclarativeDebugObjectReference &obj) const
{
foreach (const QDeclarativeDebugObjectReference &rootObj, m_clientProxy->rootObjectReference())
if (obj.debugId() == rootObj.debugId())
return true;
return false;
}
void InspectorUi::populateCrumblePath(const QDeclarativeDebugObjectReference &objRef)
{
QStringList crumbleStrings;
QList <int> crumbleData;
// first find path by climbing the hierarchy
QDeclarativeDebugObjectReference ref = objRef;
crumbleData << objRef.debugId();
crumbleStrings << displayName(objRef);
while ((!isRoot(ref)) && (ref.debugId()!=-1)) {
ref = findParentRecursive(ref.debugId(), m_clientProxy->rootObjectReference());
crumbleData.push_front( ref.debugId() );
crumbleStrings.push_front( displayName(ref) );
}
int itemIndex = crumbleData.length()-1;
// now append the children
foreach (const QDeclarativeDebugObjectReference &child, objRef.children()) {
crumbleData.push_back(child.debugId());
crumbleStrings.push_back( displayName(child) );
}
m_crumblePath->updateContextPath(crumbleStrings, crumbleData);
m_crumblePath->selectIndex(itemIndex);
}
void InspectorUi::selectItems(const QList<int> &objectIds)
{
QList<QDeclarativeDebugObjectReference> objectReferences;
foreach (int objectId, objectIds)
{
QDeclarativeDebugObjectReference ref = m_clientProxy->objectReferenceForId(objectId);
if (ref.debugId() == objectId)
objectReferences.append(ref);
}
if (objectReferences.length() > 0)
selectItems(objectReferences);
}
void InspectorUi::changePropertyValue(int debugId,const QString &propertyName, const QString &valueExpression)
{
QString query = propertyName + '=' + valueExpression;
m_clientProxy->queryExpressionResult(debugId,query, this);
} }
void InspectorUi::enable() void InspectorUi::enable()
{ {
m_toolbar->enable(); m_toolbar->enable();
m_crumblePath->setEnabled(true); m_crumblePath->setEnabled(true);
m_objectTreeWidget->setEnabled(true); m_propertyInspector->setEnabled(true);
} }
void InspectorUi::disable() void InspectorUi::disable()
{ {
m_toolbar->disable(); m_toolbar->disable();
m_crumblePath->setEnabled(false); m_crumblePath->setEnabled(false);
m_objectTreeWidget->setEnabled(false); m_propertyInspector->setEnabled(false);
}
QDeclarativeDebugObjectReference InspectorUi::objectReferenceForLocation(const QString &fileName, int cursorPosition) const
{
Core::EditorManager *editorManager = Core::EditorManager::instance();
Core::IEditor *editor = editorManager->openEditor(fileName);
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
if (textEditor && m_clientProxy && textEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
if (cursorPosition == -1)
cursorPosition = textEditor->position();
QmlJSEditor::QmlJSTextEditor *qmlEditor =
static_cast<QmlJSEditor::QmlJSTextEditor*>(textEditor->widget());
if (QmlJS::AST::Node *node
= qmlEditor->semanticInfo().declaringMemberNoProperties(cursorPosition)) {
if (QmlJS::AST::UiObjectMember *objMember = node->uiObjectMemberCast()) {
return m_clientProxy->objectReferenceForLocation(
objMember->firstSourceLocation().startLine,
objMember->firstSourceLocation().startColumn);
}
}
}
return QDeclarativeDebugObjectReference();
} }
void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectReference &obj) void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectReference &obj)
{ {
Q_UNUSED(obj);
QDeclarativeDebugFileReference source = obj.source(); QDeclarativeDebugFileReference source = obj.source();
QString fileName = source.url().toLocalFile(); QString fileName = source.url().toLocalFile();
@@ -521,11 +684,14 @@ void InspectorUi::gotoObjectReferenceDefinition(const QDeclarativeDebugObjectRef
TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor); TextEditor::ITextEditor *textEditor = qobject_cast<TextEditor::ITextEditor*>(editor);
if (textEditor) { if (textEditor) {
m_lastSelectedDebugId = obj.debugId(); QDeclarativeDebugObjectReference ref = objectReferenceForLocation(fileName);
if (ref.debugId() != obj.debugId())
editorManager->addCurrentPositionToNavigationHistory(); {
textEditor->gotoLine(source.lineNumber()); m_selectionCallbackExpected = true;
textEditor->widget()->setFocus(); editorManager->addCurrentPositionToNavigationHistory();
textEditor->gotoLine(source.lineNumber());
textEditor->widget()->setFocus();
}
} }
} }
@@ -553,7 +719,7 @@ void InspectorUi::setupDockWidgets()
m_crumblePath->setWindowTitle(tr("Context Path")); m_crumblePath->setWindowTitle(tr("Context Path"));
connect(m_crumblePath, SIGNAL(elementClicked(int)), SLOT(crumblePathElementClicked(int))); connect(m_crumblePath, SIGNAL(elementClicked(int)), SLOT(crumblePathElementClicked(int)));
m_objectTreeWidget = new QmlJSObjectTree; m_propertyInspector = new QmlJSPropertyInspector;
QWidget *observerWidget = new QWidget; QWidget *observerWidget = new QWidget;
observerWidget->setWindowTitle(tr("QML Observer")); observerWidget->setWindowTitle(tr("QML Observer"));
@@ -564,7 +730,7 @@ void InspectorUi::setupDockWidgets()
wlay->setSpacing(0); wlay->setSpacing(0);
observerWidget->setLayout(wlay); observerWidget->setLayout(wlay);
wlay->addWidget(m_toolbar->widget()); wlay->addWidget(m_toolbar->widget());
wlay->addWidget(m_objectTreeWidget); wlay->addWidget(m_propertyInspector);
wlay->addWidget(m_crumblePath); wlay->addWidget(m_crumblePath);
Debugger::DebuggerMainWindow *mw = Debugger::DebuggerPlugin::mainWindow(); Debugger::DebuggerMainWindow *mw = Debugger::DebuggerPlugin::mainWindow();
@@ -575,9 +741,9 @@ void InspectorUi::setupDockWidgets()
void InspectorUi::crumblePathElementClicked(int pathIndex) void InspectorUi::crumblePathElementClicked(int pathIndex)
{ {
if (m_clientProxy && m_clientProxy->isConnected() && !m_crumblePath->isEmpty()) { QList <int> l;
m_clientProxy->setContextPathIndex(pathIndex); l << m_crumblePath->debugIdForIndex(pathIndex);
} selectItems(l);
} }
bool InspectorUi::showExperimentalWarning() bool InspectorUi::showExperimentalWarning()
@@ -623,7 +789,7 @@ void InspectorUi::setApplyChangesToQmlObserver(bool applyChanges)
void InspectorUi::applyChangesToQmlObserverHelper(bool applyChanges) void InspectorUi::applyChangesToQmlObserverHelper(bool applyChanges)
{ {
QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews); QHashIterator<QString, QmlJSLiveTextPreview *> iter(m_textPreviews);
while(iter.hasNext()) { while (iter.hasNext()) {
iter.next(); iter.next();
iter.value()->setApplyChangesToQmlObserver(applyChanges); iter.value()->setApplyChangesToQmlObserver(applyChanges);
} }
@@ -648,7 +814,7 @@ void InspectorUi::updatePendingPreviewDocuments(QmlJS::Document::Ptr doc)
QmlJSLiveTextPreview *preview = createPreviewForEditor(editors.first()); QmlJSLiveTextPreview *preview = createPreviewForEditor(editors.first());
editors.removeFirst(); editors.removeFirst();
foreach(Core::IEditor *editor, editors) { foreach (Core::IEditor *editor, editors) {
preview->associateEditor(editor); preview->associateEditor(editor);
} }
} }
@@ -682,7 +848,8 @@ void InspectorUi::setupToolbar(bool doConnect)
this, SLOT(setApplyChangesToQmlObserver(bool))); this, SLOT(setApplyChangesToQmlObserver(bool)));
connect(m_toolbar, SIGNAL(showAppOnTopSelected(bool)), connect(m_toolbar, SIGNAL(showAppOnTopSelected(bool)),
m_clientProxy, SLOT(showAppOnTop(bool))); m_clientProxy, SLOT(showAppOnTop(bool)));
connect(m_toolbar, SIGNAL(filterTextChanged(QString)),
m_propertyInspector,SLOT(filterBy(QString)));
connect(m_clientProxy, SIGNAL(colorPickerActivated()), connect(m_clientProxy, SIGNAL(colorPickerActivated()),
m_toolbar, SLOT(activateColorPicker())); m_toolbar, SLOT(activateColorPicker()));
connect(m_clientProxy, SIGNAL(selectToolActivated()), connect(m_clientProxy, SIGNAL(selectToolActivated()),
@@ -720,7 +887,8 @@ void InspectorUi::setupToolbar(bool doConnect)
this, SLOT(setApplyChangesToQmlObserver(bool))); this, SLOT(setApplyChangesToQmlObserver(bool)));
disconnect(m_toolbar, SIGNAL(showAppOnTopSelected(bool)), disconnect(m_toolbar, SIGNAL(showAppOnTopSelected(bool)),
m_clientProxy, SLOT(showAppOnTop(bool))); m_clientProxy, SLOT(showAppOnTop(bool)));
disconnect(m_toolbar, SIGNAL(filterTextChanged(QString)),
m_propertyInspector,SLOT(filterBy(QString)));
disconnect(m_clientProxy, SIGNAL(colorPickerActivated()), disconnect(m_clientProxy, SIGNAL(colorPickerActivated()),
m_toolbar, SLOT(activateColorPicker())); m_toolbar, SLOT(activateColorPicker()));
disconnect(m_clientProxy, SIGNAL(selectToolActivated()), disconnect(m_clientProxy, SIGNAL(selectToolActivated()),

View File

@@ -67,7 +67,7 @@ namespace QmlJSInspector {
namespace Internal { namespace Internal {
class QmlInspectorToolbar; class QmlInspectorToolbar;
class QmlJSObjectTree; class QmlJSPropertyInspector;
class ClientProxy; class ClientProxy;
class InspectorSettings; class InspectorSettings;
class ContextCrumblePath; class ContextCrumblePath;
@@ -120,8 +120,11 @@ private slots:
void enable(); void enable();
void disable(); void disable();
void gotoObjectReferenceDefinition(const QDeclarativeDebugObjectReference &obj); void gotoObjectReferenceDefinition(const QDeclarativeDebugObjectReference &obj);
void gotoObjectReferenceDefinition(QList<QDeclarativeDebugObjectReference> objectReferences); void selectItems(const QList<QDeclarativeDebugObjectReference> &objectReferences);
void selectItems(const QList<int> &objectIds);
void changeSelectedItems(const QList<QDeclarativeDebugObjectReference> &objects); void changeSelectedItems(const QList<QDeclarativeDebugObjectReference> &objects);
void changePropertyValue(int debugId,const QString &propertyName, const QString &valueExpression);
void objectTreeReady();
void updateEngineList(); void updateEngineList();
@@ -146,19 +149,20 @@ private:
void setupToolbar(bool doConnect); void setupToolbar(bool doConnect);
void setupDockWidgets(); void setupDockWidgets();
QString filenameForShadowBuildFile(const QString &filename) const; QString filenameForShadowBuildFile(const QString &filename) const;
void populateCrumblePath(const QDeclarativeDebugObjectReference &objRef);
bool isRoot(const QDeclarativeDebugObjectReference &obj) const;
QDeclarativeDebugObjectReference objectReferenceForLocation(const QString &fileName, int cursorPosition=-1) const;
private: private:
bool m_listeningToEditorManager; bool m_listeningToEditorManager;
QmlInspectorToolbar *m_toolbar; QmlInspectorToolbar *m_toolbar;
ContextCrumblePath *m_crumblePath; ContextCrumblePath *m_crumblePath;
QmlJSObjectTree *m_objectTreeWidget; QmlJSPropertyInspector *m_propertyInspector;
InspectorSettings *m_settings; InspectorSettings *m_settings;
ClientProxy *m_clientProxy; ClientProxy *m_clientProxy;
QObject *m_qmlEngine; QObject *m_qmlEngine;
QDeclarativeDebugExpressionQuery *m_debugQuery; QDeclarativeDebugExpressionQuery *m_debugQuery;
int m_lastSelectedDebugId;
// Qml/JS integration // Qml/JS integration
QHash<QString, QmlJSLiveTextPreview *> m_textPreviews; QHash<QString, QmlJSLiveTextPreview *> m_textPreviews;
@@ -172,6 +176,7 @@ private:
Utils::FileInProjectFinder m_projectFinder; Utils::FileInProjectFinder m_projectFinder;
static InspectorUi *m_instance; static InspectorUi *m_instance;
bool m_selectionCallbackExpected;
}; };
} // Internal } // Internal

View File

@@ -19,7 +19,7 @@ qmljstoolbarcolorbox.h \
qmljsobserverclient.h \ qmljsobserverclient.h \
qmljscontextcrumblepath.h \ qmljscontextcrumblepath.h \
qmljsinspectorsettings.h \ qmljsinspectorsettings.h \
qmljsobjecttree.h qmljspropertyinspector.h
SOURCES += \ SOURCES += \
qmljsinspectorplugin.cpp \ qmljsinspectorplugin.cpp \
@@ -31,7 +31,7 @@ qmljstoolbarcolorbox.cpp \
qmljsobserverclient.cpp \ qmljsobserverclient.cpp \
qmljscontextcrumblepath.cpp \ qmljscontextcrumblepath.cpp \
qmljsinspectorsettings.cpp \ qmljsinspectorsettings.cpp \
qmljsobjecttree.cpp qmljspropertyinspector.cpp
include(../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri) include(../../libs/qmljsdebugclient/qmljsdebugclient-lib.pri)

View File

@@ -1,242 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "qmljsobjecttree.h"
#include <QContextMenuEvent>
#include <QEvent>
#include <QtGui/QMenu>
#include <QtGui/QAction>
#include <QApplication>
#include <QInputDialog>
#include <QDebug>
namespace QmlJSInspector {
namespace Internal {
// *************************************************************************
// ObjectTreeItem
// *************************************************************************
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;
};
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;
}
// *************************************************************************
// QmlJSObjectTree
// *************************************************************************
QmlJSObjectTree::QmlJSObjectTree(QWidget *parent)
: QTreeWidget(parent)
, m_clickedItem(0)
, m_currentObjectDebugId(0)
{
setAttribute(Qt::WA_MacShowFocusRect, false);
setFrameStyle(QFrame::NoFrame);
setHeaderHidden(true);
setExpandsOnDoubleClick(false);
m_goToFileAction = new QAction(tr("Go to file"), this);
connect(m_goToFileAction, SIGNAL(triggered()), SLOT(goToFile()));
connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)),
SLOT(currentItemChanged(QTreeWidgetItem *)));
connect(this, SIGNAL(itemActivated(QTreeWidgetItem *, int)),
SLOT(activated(QTreeWidgetItem *)));
connect(this, SIGNAL(itemSelectionChanged()), SLOT(selectionChanged()));
}
void QmlJSObjectTree::selectionChanged()
{
if (selectedItems().isEmpty())
return;
// TODO
}
void QmlJSObjectTree::setCurrentObject(int debugId)
{
QTreeWidgetItem *item = findItemByObjectId(debugId);
if (item) {
setCurrentItem(item);
scrollToItem(item);
item->setExpanded(true);
}
}
void QmlJSObjectTree::currentItemChanged(QTreeWidgetItem *item)
{
if (!item)
return;
QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit currentObjectChanged(obj);
}
void QmlJSObjectTree::activated(QTreeWidgetItem *item)
{
if (!item)
return;
QDeclarativeDebugObjectReference obj = item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit activated(obj);
}
void QmlJSObjectTree::buildTree(const QDeclarativeDebugObjectReference &obj, QTreeWidgetItem *parent)
{
if (!parent)
clear();
if (obj.contextDebugId() < 0)
return;
ObjectTreeItem *item = parent ? new ObjectTreeItem(parent) : new ObjectTreeItem(this);
if (obj.idString().isEmpty())
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())
{
QDeclarativeDebugFileReference source = obj.source();
if (!source.url().isEmpty()) {
QString toolTipString = tr("Url: ") + source.url().toString();
item->setToolTip(0, toolTipString);
}
} else {
item->setExpanded(true);
}
if (obj.contextDebugId() < 0)
item->setHasValidDebugId(false);
for (int ii = 0; ii < obj.children().count(); ++ii)
buildTree(obj.children().at(ii), item);
}
QTreeWidgetItem *QmlJSObjectTree::findItemByObjectId(int debugId) const
{
for (int i=0; i<topLevelItemCount(); ++i) {
QTreeWidgetItem *item = findItem(topLevelItem(i), debugId);
if (item)
return item;
}
return 0;
}
QTreeWidgetItem *QmlJSObjectTree::findItem(QTreeWidgetItem *item, int debugId) const
{
if (item->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>().debugId() == debugId)
return item;
QTreeWidgetItem *child;
for (int i=0; i<item->childCount(); ++i) {
child = findItem(item->child(i), debugId);
if (child)
return child;
}
return 0;
}
void QmlJSObjectTree::goToFile()
{
QDeclarativeDebugObjectReference obj =
currentItem()->data(0, Qt::UserRole).value<QDeclarativeDebugObjectReference>();
if (obj.debugId() >= 0)
emit activated(obj);
}
void QmlJSObjectTree::contextMenuEvent(QContextMenuEvent *event)
{
m_clickedItem = itemAt(QPoint(event->pos().x(),
event->pos().y() ));
if (!m_clickedItem)
return;
QMenu menu;
menu.addAction(m_goToFileAction);
menu.exec(event->globalPos());
}
} // Internal
} // QmlJSInspector

View File

@@ -1,86 +0,0 @@
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef OBJECTTREE_H
#define OBJECTTREE_H
#include <qmljsprivateapi.h>
#include <QtGui/QTreeWidget>
QT_BEGIN_NAMESPACE
class QTreeWidgetItem;
QT_END_NAMESPACE
namespace QmlJSInspector {
namespace Internal {
class QmlJSObjectTree : public QTreeWidget
{
Q_OBJECT
public:
QmlJSObjectTree(QWidget *parent = 0);
signals:
void currentObjectChanged(const QDeclarativeDebugObjectReference &);
void activated(const QDeclarativeDebugObjectReference &);
void expressionWatchRequested(const QDeclarativeDebugObjectReference &, const QString &);
void contextHelpIdChanged(const QString &contextHelpId);
public slots:
void setCurrentObject(int debugId); // select an object in the tree
protected:
virtual void contextMenuEvent(QContextMenuEvent *);
private slots:
void currentItemChanged(QTreeWidgetItem *);
void activated(QTreeWidgetItem *);
void selectionChanged();
void goToFile();
private:
QTreeWidgetItem *findItemByObjectId(int debugId) const;
QTreeWidgetItem *findItem(QTreeWidgetItem *item, int debugId) const;
void buildTree(const QDeclarativeDebugObjectReference &, QTreeWidgetItem *parent);
QTreeWidgetItem *m_clickedItem;
QAction *m_addWatchAction;
QAction *m_goToFileAction;
int m_currentObjectDebugId;
};
} // Internal
} // QmlJSInspector
#endif