/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** 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 either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** 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.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qmldebugger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include QmlDebugger::QmlDebugger(QWidget *parent) : QWidget(parent), m_tree(0), m_warnings(0), m_watchTable(0), m_watches(0), m_properties(0), m_text(0), m_highlightedItem(0) { QHBoxLayout *layout = new QHBoxLayout; setLayout(layout); QSplitter *splitter = new QSplitter(this); layout->addWidget(splitter); QWidget *treeWid = new QWidget(this); QVBoxLayout *vlayout = new QVBoxLayout; vlayout->setContentsMargins(0, 0, 0, 0); treeWid->setLayout(vlayout); splitter->addWidget(treeWid); m_tree = new QmlObjectTree(treeWid); m_tree->setHeaderHidden(true); QObject::connect(m_tree, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(itemClicked(QTreeWidgetItem *))); QObject::connect(m_tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(itemDoubleClicked(QTreeWidgetItem *))); QObject::connect(m_tree, SIGNAL(addWatch(QObject*,QString)), this, SLOT(addWatch(QObject*,QString))); vlayout->addWidget(m_tree); QPushButton *pb = new QPushButton(tr("Refresh"), treeWid); QObject::connect(pb, SIGNAL(clicked()), this, SLOT(refresh())); vlayout->addWidget(pb); QTabWidget *tabs = new QTabWidget(this); m_text = new QPlainTextEdit(this); m_text->setReadOnly(true); tabs->addTab(m_text, tr("File")); m_warnings = new QTreeWidget(this); m_warnings->setHeaderHidden(true); tabs->addTab(m_warnings, tr("Warnings")); m_watches = new QmlWatches(this); m_watchTable = new QTableView(this); m_watchTable->setSelectionMode(QTableWidget::NoSelection); m_watchTable->setModel(m_watches); tabs->addTab(m_watchTable, tr("Watches")); m_properties = new QmlPropertyView(m_watches, this); QObject::connect(m_properties, SIGNAL(objectClicked(quint32)), this, SLOT(highlightObject(quint32))); tabs->addTab(m_properties, tr("Properties")); tabs->setCurrentWidget(m_properties); splitter->addWidget(tabs); splitter->setStretchFactor(1, 2); setGeometry(0, 100, 800, 600); } void QmlDebugger::itemDoubleClicked(QTreeWidgetItem *) { } void QmlDebugger::addWatch(QObject *obj, const QString &expr) { QmlContext *ctxt = qmlContext(obj); if(ctxt) { QmlExpressionObject *e= new QmlExpressionObject(ctxt, expr, obj, m_watches); m_watches->addWatch(e); } } void QmlDebugger::highlightObject(quint32 id) { QHash::ConstIterator iter = m_items.find(id); if (m_highlightedItem) { m_highlightedItem->setBackground(0, QPalette().base()); m_highlightedItem = 0; } if (iter != m_items.end()) { m_highlightedItem = *iter; m_highlightedItem->setBackground(0, QColor("cyan")); m_tree->expandItem(m_highlightedItem); m_tree->scrollToItem(m_highlightedItem); } } void QmlDebugger::itemClicked(QTreeWidgetItem *i) { QmlDebuggerItem *item = static_cast(i); if(m_selectedItem) { QmlDebuggerStatus *debug = qobject_cast(m_selectedItem); Q_ASSERT(debug); debug->setSelectedState(false); m_selectedItem = 0; } if(item->object) { QmlDebuggerStatus *debug = qobject_cast(item->object); if(debug) { debug->setSelectedState(true); m_selectedItem = item->object; } m_properties->setObject(item->object); } if(item->url.scheme() == QLatin1String("file")) { QString f = item->url.toLocalFile(); QFile file(f); file.open(QIODevice::ReadOnly); QByteArray ba = file.readAll(); QTextStream stream(ba, QIODevice::ReadOnly); const QString code = stream.readAll(); m_text->setPlainText(code); if(item->startLine != -1) { QTextDocument *document = m_text->document(); QTextCharFormat format; format.setForeground(Qt::lightGray); { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->endLine); cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor); cursor.setCharFormat(format); } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor, item->startLine - 1); cursor.setCharFormat(format); } { QTextCursor cursor(document); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); cursor.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor, item->startLine - 1); m_text->setTextCursor(cursor); m_text->centerCursor(); } } } } bool QmlDebugger::makeItem(QObject *obj, QmlDebuggerItem *item) { bool rv = true; QString text; item->object = obj; if(QmlBindableValue *bv = qobject_cast(obj)) { QmlExpressionPrivate *p = bv->d; text = bv->property().name() + QLatin1String(": ") + bv->expression(); item->setForeground(0, Qt::green); item->bindableValue = bv; if(p->log) { QTreeWidgetItem *warningItem = 0; for(int ii = 0; ii < p->log->count(); ++ii) { const QmlExpressionLog &log = p->log->at(ii); QString variant; QDebug d(&variant); d << log.result(); if(!log.warnings().isEmpty()) { if(!warningItem) { warningItem = new QTreeWidgetItem(m_warnings); warningItem->setText(0, bv->expression()); } QTreeWidgetItem *entry = new QTreeWidgetItem(warningItem); entry->setExpanded(true); entry->setText(0, variant); foreach(const QString &warning, log.warnings()) { QTreeWidgetItem *w = new QTreeWidgetItem(entry); w->setText(0, warning); } } } } delete item; return false; } else if(QmlBoundSignal *bs = qobject_cast(obj)) { delete item; return false; } else { QmlContext *context = qmlContext(obj); QmlContext *parentContext = qmlContext(obj->parent()); text = QLatin1String(obj->metaObject()->className()); if(context && context != parentContext) { QmlContextPrivate *p = static_cast(QObjectPrivate::get(context)); QString toolTipString; if(!p->url.toString().isEmpty()) { item->url = p->url; toolTipString = QLatin1String("URL: ") + p->url.toString(); } if(!p->typeName.isEmpty()) { if(!toolTipString.isEmpty()) toolTipString.prepend(QLatin1Char('\n')); toolTipString.prepend(tr("Root type: ") + text); text = QString::fromAscii(p->typeName); } if(!toolTipString.isEmpty()) item->setToolTip(0, toolTipString); item->setForeground(0, QColor("orange")); if(p->startLine != -1) { item->startLine = p->startLine; item->endLine = p->endLine; } } else { item->setExpanded(true); } if(!context) item->setForeground(0, Qt::lightGray); } m_items.insert(m_watches->objectId(obj), item); item->setText(0, text); return rv; } void QmlDebugger::buildTree(QObject *obj, QmlDebuggerItem *parent) { QObjectList children = obj->children(); for (int ii = 0; ii < children.count(); ++ii) { QmlDebuggerItem *item = new QmlDebuggerItem(parent); if(makeItem(children.at(ii), item)) buildTree(children.at(ii), item); } } void QmlDebugger::refresh() { setDebugObject(m_object); } bool operator<(const QPair > &lhs, const QPair > &rhs) { return lhs.first < rhs.first; } void QmlDebugger::setCanvas(QSimpleCanvas *c) { Q_UNUSED(c); } void QmlDebugger::setDebugObject(QObject *obj) { m_tree->clear(); m_warnings->clear(); m_items.clear(); m_highlightedItem = 0; m_object = obj; if(!obj) return; QmlDebuggerItem *item = new QmlDebuggerItem(m_tree); makeItem(obj, item); buildTree(obj, item); item->setExpanded(true); }