Commit 90abf1bf authored by Lasse Holmstedt's avatar Lasse Holmstedt

Highlighting and more sensible watchers to qml inspector

parent d5818417
......@@ -24,7 +24,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
<dependency name="ProjectExplorer" version="1.3.82"/>
<dependency name="CppTools" version="1.3.82"/>
<dependency name="CppEditor" version="1.3.82"/>
<dependency name="Help" version="1.3.82"/>
<dependency name="Debugger" version="1.3.82"/>
</dependencyList>
</plugin>
......@@ -27,27 +27,40 @@
**
**************************************************************************/
#include "expressionquerywidget.h"
#include "qmlinspectorconstants.h"
#include <QtCore/qdebug.h>
#include <utils/fancylineedit.h>
#include <texteditor/texteditorconstants.h>
#include <texteditor/texteditorsettings.h>
#include <texteditor/fontsettings.h>
#include <qmljseditor/qmljshighlighter.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <QtGui/qlabel.h>
#include <QtGui/qtextedit.h>
#include <QtGui/qlineedit.h>
#include <QtGui/qpushbutton.h>
#include <QtGui/qevent.h>
#include <QtGui/qgroupbox.h>
#include <QtGui/qtextobject.h>
#include <QtGui/qlayout.h>
#include <QtCore/QEvent>
#include <QtGui/QTextCharFormat>
#include <QtGui/QKeySequence>
#include <QtGui/QLabel>
#include <QtGui/QTextEdit>
#include <QtGui/QLineEdit>
#include <QtGui/QPushButton>
#include <QtGui/QGroupBox>
#include <QtGui/QTextObject>
#include <QtGui/QLayout>
#include <QtGui/QShortcut>
#include <QtCore/QDebug>
ExpressionQueryWidget::ExpressionQueryWidget(Mode mode, QDeclarativeEngineDebug *client, QWidget *parent)
: QWidget(parent),
m_mode(mode),
m_client(client),
m_query(0),
m_textEdit(new QTextEdit),
m_textEdit(new QPlainTextEdit),
m_lineEdit(0)
{
m_prompt = QLatin1String(">> ");
m_prompt = QLatin1String(">");
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
......@@ -56,13 +69,17 @@ ExpressionQueryWidget::ExpressionQueryWidget(Mode mode, QDeclarativeEngineDebug
updateTitle();
m_highlighter = new QmlJSEditor::Highlighter(m_textEdit->document());
m_highlighter->setParent(m_textEdit->document());
if (m_mode == SeparateEntryMode) {
m_lineEdit = new QLineEdit;
m_lineEdit = new Utils::FancyLineEdit;
m_lineEdit->setHintText(tr("<Expression>"));
connect(m_lineEdit, SIGNAL(returnPressed()), SLOT(executeExpression()));
QHBoxLayout *hbox = new QHBoxLayout;
hbox->setMargin(5);
hbox->setSpacing(5);
hbox->addWidget(new QLabel(tr("Expression:")));
hbox->setMargin(1);
hbox->setSpacing(1);
//hbox->addWidget(new QLabel(tr("Expression:")));
hbox->addWidget(m_lineEdit);
layout->addLayout(hbox);
......@@ -72,6 +89,53 @@ ExpressionQueryWidget::ExpressionQueryWidget(Mode mode, QDeclarativeEngineDebug
m_textEdit->installEventFilter(this);
appendPrompt();
}
setFontSettings();
}
void ExpressionQueryWidget::setFontSettings()
{
const TextEditor::FontSettings &fs = TextEditor::TextEditorSettings::instance()->fontSettings();
static QVector<QString> categories;
if (categories.isEmpty()) {
categories << QLatin1String(TextEditor::Constants::C_NUMBER)
<< QLatin1String(TextEditor::Constants::C_STRING)
<< QLatin1String(TextEditor::Constants::C_TYPE)
<< QLatin1String(TextEditor::Constants::C_KEYWORD)
<< QLatin1String(TextEditor::Constants::C_LABEL)
<< QLatin1String(TextEditor::Constants::C_COMMENT)
<< QLatin1String(TextEditor::Constants::C_VISUAL_WHITESPACE);
}
const QVector<QTextCharFormat> formats = fs.toTextCharFormats(categories);
m_highlighter->setFormats(formats.constBegin(), formats.constEnd());
m_highlighter->rehighlight();
m_textEdit->setFont(fs.font());
if (m_mode == SeparateEntryMode)
m_lineEdit->setFont(fs.font());
}
void ExpressionQueryWidget::createCommands(Core::IContext *context)
{
Core::ICore *core = Core::ICore::instance();
Core::ActionManager *am = core->actionManager();
// Add shortcut for invoking automatic completion
QShortcut *completionShortcut = new QShortcut(m_lineEdit);
completionShortcut->setWhatsThis(tr("Triggers a completion in this scope"));
// Make sure the shortcut still works when the completion widget is active
completionShortcut->setContext(Qt::ApplicationShortcut);
Core::Command *command = am->registerShortcut(completionShortcut, Qml::Constants::COMPLETE_THIS, context->context());
#ifndef Q_WS_MAC
command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Space")));
#else
command->setDefaultKeySequence(QKeySequence(tr("Meta+Space")));
#endif
connect(completionShortcut, SIGNAL(activated()), this, SLOT(invokeCompletion()));
}
void ExpressionQueryWidget::invokeCompletion()
{
qDebug() << "TODO autocomplete";
}
void ExpressionQueryWidget::setEngineDebug(QDeclarativeEngineDebug *client)
......@@ -108,8 +172,7 @@ void ExpressionQueryWidget::appendPrompt()
if (m_mode == SeparateEntryMode) {
m_textEdit->insertPlainText("\n");
} else {
m_textEdit->setTextColor(Qt::gray);
m_textEdit->append(m_prompt);
m_textEdit->appendPlainText(m_prompt);
}
}
......@@ -137,8 +200,7 @@ void ExpressionQueryWidget::showCurrentContext()
}
m_textEdit->moveCursor(QTextCursor::End);
m_textEdit->setTextColor(Qt::darkGreen);
m_textEdit->append(m_currObject.className()
m_textEdit->appendPlainText(m_currObject.className()
+ QLatin1String(": ")
+ (m_currObject.name().isEmpty() ? QLatin1String("<unnamed object>") : m_currObject.name()));
appendPrompt();
......@@ -186,15 +248,10 @@ void ExpressionQueryWidget::showResult()
}
if (m_mode == SeparateEntryMode) {
m_textEdit->setTextColor(Qt::black);
m_textEdit->setFontWeight(QFont::Bold);
m_textEdit->insertPlainText(m_expr + " : ");
m_textEdit->setFontWeight(QFont::Normal);
m_textEdit->insertPlainText(result);
} else {
m_textEdit->setTextColor(Qt::darkGreen);
m_textEdit->insertPlainText(" => ");
m_textEdit->setTextColor(Qt::black);
m_textEdit->insertPlainText(result);
}
appendPrompt();
......@@ -226,7 +283,6 @@ bool ExpressionQueryWidget::eventFilter(QObject *obj, QEvent *event)
return true;
} else {
m_textEdit->moveCursor(QTextCursor::End);
m_textEdit->setTextColor(Qt::black);
m_expr += keyEvent->text();
}
break;
......
......@@ -37,10 +37,21 @@
QT_BEGIN_NAMESPACE
class QGroupBox;
class QTextEdit;
class QPlainTextEdit;
class QLineEdit;
class QPushButton;
namespace Utils {
class FancyLineEdit;
}
namespace Core {
class IContext;
}
namespace QmlJSEditor {
class Highlighter;
}
class ExpressionQueryWidget : public QWidget
{
Q_OBJECT
......@@ -52,6 +63,7 @@ public:
ExpressionQueryWidget(Mode mode = SeparateEntryMode, QDeclarativeEngineDebug *client = 0, QWidget *parent = 0);
void createCommands(Core::IContext *context);
void setEngineDebug(QDeclarativeEngineDebug *client);
void clear();
......@@ -64,8 +76,10 @@ public slots:
private slots:
void executeExpression();
void showResult();
void invokeCompletion();
private:
void setFontSettings();
void appendPrompt();
void checkCurrentContext();
void showCurrentContext();
......@@ -75,14 +89,15 @@ private:
QDeclarativeEngineDebug *m_client;
QDeclarativeDebugExpressionQuery *m_query;
QTextEdit *m_textEdit;
QLineEdit *m_lineEdit;
QPlainTextEdit *m_textEdit;
Utils::FancyLineEdit *m_lineEdit;
QPushButton *m_button;
QString m_prompt;
QString m_expr;
QString m_lastExpr;
QString m_title;
QmlJSEditor::Highlighter *m_highlighter;
QDeclarativeDebugObjectReference m_currObject;
QDeclarativeDebugObjectReference m_objectAtLastFocus;
......
......@@ -38,17 +38,21 @@
QT_BEGIN_NAMESPACE
const int C_NAME = 0;
const int C_VALUE = 1;
const int C_COLUMNS = 2;
WatchTableModel::WatchTableModel(QDeclarativeEngineDebug *client, QObject *parent)
: QAbstractTableModel(parent),
m_client(client)
{
}
WatchTableModel::~WatchTableModel()
{
for (int i=0; i<m_columns.count(); ++i)
delete m_columns[i].watch;
for (int i=0; i < m_entities.count(); ++i)
delete m_entities[i].watch;
}
void WatchTableModel::setEngineDebug(QDeclarativeEngineDebug *client)
......@@ -67,67 +71,55 @@ void WatchTableModel::addWatch(QDeclarativeDebugWatch *watch, const QString &tit
connect(watch, SIGNAL(stateChanged(QDeclarativeDebugWatch::State)), SLOT(watchStateChanged()));
int col = columnCount(QModelIndex());
beginInsertColumns(QModelIndex(), col, col);
int row = rowCount(QModelIndex());
beginInsertRows(QModelIndex(), row, row);
WatchedEntity e;
e.title = title;
e.hasFirstValue = false;
e.property = property;
e.watch = watch;
m_columns.append(e);
endInsertColumns();
m_entities.append(e);
endInsertRows();
}
void WatchTableModel::removeWatch(QDeclarativeDebugWatch *watch)
{
int column = columnForWatch(watch);
int column = rowForWatch(watch);
if (column == -1)
return;
WatchedEntity entity = m_columns.takeAt(column);
for (QList<Value>::Iterator iter = m_values.begin(); iter != m_values.end();) {
if (iter->column == column) {
iter = m_values.erase(iter);
} else {
if(iter->column > column)
--iter->column;
++iter;
}
}
m_entities.takeAt(column);
reset();
}
void WatchTableModel::updateWatch(QDeclarativeDebugWatch *watch, const QVariant &value)
{
int column = columnForWatch(watch);
if (column == -1)
int row = rowForWatch(watch);
if (row == -1)
return;
addValue(column, value);
m_entities[row].value = value;
const QModelIndex &idx = index(row, C_VALUE);
emit dataChanged(idx, idx);
if (!m_columns[column].hasFirstValue) {
m_columns[column].hasFirstValue = true;
m_values[m_values.count() - 1].first = true;
}
}
QDeclarativeDebugWatch *WatchTableModel::findWatch(int column) const
QDeclarativeDebugWatch *WatchTableModel::findWatch(int row) const
{
if (column < m_columns.count())
return m_columns.at(column).watch;
if (row < m_entities.count())
return m_entities.at(row).watch;
return 0;
}
QDeclarativeDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QString &property) const
{
for (int i=0; i<m_columns.count(); ++i) {
if (m_columns[i].watch->objectDebugId() == objectDebugId
&& m_columns[i].property == property) {
return m_columns[i].watch;
for (int i=0; i < m_entities.count(); ++i) {
if (m_entities[i].watch->objectDebugId() == objectDebugId
&& m_entities[i].property == property) {
return m_entities[i].watch;
}
}
return 0;
......@@ -135,60 +127,41 @@ QDeclarativeDebugWatch *WatchTableModel::findWatch(int objectDebugId, const QStr
int WatchTableModel::rowCount(const QModelIndex &) const
{
return m_values.count();
return m_entities.count();
}
int WatchTableModel::columnCount(const QModelIndex &) const
{
return m_columns.count();
return C_COLUMNS;
}
QVariant WatchTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal) {
if (section < m_columns.count() && role == Qt::DisplayRole)
return m_columns.at(section).title;
} else {
if (role == Qt::DisplayRole)
return section + 1;
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
if (section == C_NAME)
return tr("Name");
else if (section == C_VALUE)
return tr("Value");
}
return QVariant();
}
QVariant WatchTableModel::data(const QModelIndex &idx, int role) const
{
if (m_values.at(idx.row()).column == idx.column()) {
if (idx.column() == C_NAME) {
if (role == Qt::DisplayRole)
return QVariant(m_entities.at(idx.row()).title);
} else if (idx.column() == C_VALUE) {
if (role == Qt::DisplayRole) {
const QVariant &value = m_values.at(idx.row()).variant;
QString str = value.toString();
if (str.isEmpty() && QDeclarativeMetaType::isQObject(value.userType())) {
QObject *o = QDeclarativeMetaType::toQObject(value);
if(o) {
QString objectName = o->objectName();
if(objectName.isEmpty())
objectName = QLatin1String("<unnamed>");
str = QLatin1String(o->metaObject()->className()) +
QLatin1String(": ") + objectName;
}
}
if(str.isEmpty()) {
QDebug d(&str);
d << value;
}
return QVariant(str);
return QVariant(m_entities.at(idx.row()).value);
} else if(role == Qt::BackgroundRole) {
if(m_values.at(idx.row()).first)
return QColor(Qt::green);
else
return QVariant();
} else {
return QVariant();
//return QColor(Qt::green);
}
} else {
return QVariant();
}
return QVariant();
}
void WatchTableModel::watchStateChanged()
......@@ -201,29 +174,15 @@ void WatchTableModel::watchStateChanged()
}
}
int WatchTableModel::columnForWatch(QDeclarativeDebugWatch *watch) const
int WatchTableModel::rowForWatch(QDeclarativeDebugWatch *watch) const
{
for (int i=0; i<m_columns.count(); ++i) {
if (m_columns.at(i).watch == watch)
for (int i=0; i < m_entities.count(); ++i) {
if (m_entities.at(i).watch == watch)
return i;
}
return -1;
}
void WatchTableModel::addValue(int column, const QVariant &value)
{
int row = columnCount(QModelIndex());
beginInsertRows(QModelIndex(), row, row);
Value v;
v.column = column;
v.variant = value;
v.first = false;
m_values.append(v);
endInsertRows();
}
void WatchTableModel::togglePropertyWatch(const QDeclarativeDebugObjectReference &object, const QDeclarativeDebugPropertyReference &property)
{
if (!m_client || !property.hasNotifySignal())
......@@ -241,11 +200,10 @@ void WatchTableModel::togglePropertyWatch(const QDeclarativeDebugObjectReference
delete watch;
watch = 0;
} else {
QString desc = property.name()
+ QLatin1String(" on\n")
+ object.className()
+ QLatin1String(":\n")
+ (object.name().isEmpty() ? QLatin1String("<unnamed object>") : object.name());
QString desc = (object.name().isEmpty() ? QLatin1String("<unnamed object>") : object.name())
+ QLatin1String(".") + property.name()
+ object.className();
addWatch(watch, desc);
emit watchCreated(watch);
}
......@@ -275,12 +233,12 @@ void WatchTableModel::expressionWatchRequested(const QDeclarativeDebugObjectRefe
}
}
void WatchTableModel::removeWatchAt(int column)
void WatchTableModel::removeWatchAt(int row)
{
if (!m_client)
return;
QDeclarativeDebugWatch *watch = findWatch(column);
QDeclarativeDebugWatch *watch = findWatch(row);
if (watch) {
m_client->removeWatch(watch);
delete watch;
......@@ -290,14 +248,13 @@ void WatchTableModel::removeWatchAt(int column)
void WatchTableModel::removeAllWatches()
{
for (int i=0; i<m_columns.count(); ++i) {
for (int i=0; i<m_entities.count(); ++i) {
if (m_client)
m_client->removeWatch(m_columns[i].watch);
m_client->removeWatch(m_entities[i].watch);
else
delete m_columns[i].watch;
delete m_entities[i].watch;
}
m_columns.clear();
m_values.clear();
m_entities.clear();
reset();
}
......@@ -308,25 +265,11 @@ WatchTableHeaderView::WatchTableHeaderView(WatchTableModel *model, QWidget *pare
m_model(model)
{
setClickable(true);
setResizeMode(QHeaderView::ResizeToContents);
setMinimumSectionSize(100);
setStretchLastSection(true);
}
void WatchTableHeaderView::mousePressEvent(QMouseEvent *me)
{
QHeaderView::mousePressEvent(me);
if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
int col = logicalIndexAt(me->pos());
if (col >= 0) {
QAction action(tr("Stop watching"), 0);
QList<QAction *> actions;
actions << &action;
if (QMenu::exec(actions, me->globalPos()))
m_model->removeWatchAt(col);
}
}
}
//----------------------------------------------
WatchTableView::WatchTableView(WatchTableModel *model, QWidget *parent)
......@@ -334,6 +277,7 @@ WatchTableView::WatchTableView(WatchTableModel *model, QWidget *parent)
m_model(model)
{
setAlternatingRowColors(true);
connect(model, SIGNAL(watchCreated(QDeclarativeDebugWatch*)), SLOT(watchCreated(QDeclarativeDebugWatch*)));
connect(this, SIGNAL(activated(QModelIndex)), SLOT(indexActivated(QModelIndex)));
}
......@@ -347,8 +291,24 @@ void WatchTableView::indexActivated(const QModelIndex &index)
void WatchTableView::watchCreated(QDeclarativeDebugWatch *watch)
{
int column = m_model->columnForWatch(watch);
int column = m_model->rowForWatch(watch);
resizeColumnToContents(column);
}
void WatchTableView::mousePressEvent(QMouseEvent *me)
{
QTableView::mousePressEvent(me);
if (me->button() == Qt::RightButton && me->type() == QEvent::MouseButtonPress) {
int row = rowAt(me->pos().y());
if (row >= 0) {
QAction action(tr("Stop watching"), 0);
QList<QAction *> actions;
actions << &action;
if (QMenu::exec(actions, me->globalPos()))
m_model->removeWatchAt(row);
}
}
}
QT_END_NAMESPACE
......@@ -55,9 +55,9 @@ public:
void setEngineDebug(QDeclarativeEngineDebug *client);
QDeclarativeDebugWatch *findWatch(int column) const;
int columnForWatch(QDeclarativeDebugWatch *watch) const;
int rowForWatch(QDeclarativeDebugWatch *watch) const;
void removeWatchAt(int column);
void removeWatchAt(int row);
void removeAllWatches();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
......@@ -83,25 +83,16 @@ private:
QDeclarativeDebugWatch *findWatch(int objectDebugId, const QString &property) const;
void addValue(int column, const QVariant &value);
struct WatchedEntity
{
QString title;
bool hasFirstValue;
QString property;
QPointer<QDeclarativeDebugWatch> watch;
};