Commit a167498e authored by Aurindam Jana's avatar Aurindam Jana

ScriptConsole: Show File and Line Info

Show File and Line Info for items that have the info. Clicking
on the item opens the file and sets the cursor position on
the line. The context menu also provides option to copy contents
and option to clear the view.

Change-Id: I161de392ba35e37d323b049371619b01c617c798
Reviewed-by: default avatarKai Koehne <kai.koehne@nokia.com>
parent d75d70c5
......@@ -63,12 +63,21 @@ void QDebugMessageClient::messageReceived(const QByteArray &data)
int type;
QDataStream ms(messagePacket);
ms >> type >> debugMessage;
emit message(QtMsgType(type), QString::fromUtf8(debugMessage.data()));
QDebugContextInfo info;
emit message(QtMsgType(type), QString::fromUtf8(debugMessage.data()),
info);
} else {
int type;
int line;
QByteArray debugMessage;
ds >> type >> debugMessage;
emit message(QtMsgType(type), QString::fromUtf8(debugMessage));
QByteArray file;
QByteArray function;
ds >> type >> debugMessage >> file >> line >> function;
QDebugContextInfo info;
info.line = line;
info.file = QString::fromUtf8(file);
info.function = QString::fromUtf8(function);
emit message(QtMsgType(type), QString::fromUtf8(debugMessage), info);
}
}
}
......
......@@ -39,6 +39,13 @@
namespace QmlJsDebugClient {
class QDebugMessageClientPrivate;
struct QDebugContextInfo
{
int line;
QString file;
QString function;
};
class QMLJSDEBUGCLIENT_EXPORT QDebugMessageClient : public QDeclarativeDebugClient
{
Q_OBJECT
......@@ -53,7 +60,8 @@ protected:
signals:
void newStatus(QDeclarativeDebugClient::Status);
void message(QtMsgType, const QString &);
void message(QtMsgType, const QString &,
const QmlJsDebugClient::QDebugContextInfo &);
private:
class QDebugMessageClientPrivate *d;
......
......@@ -66,6 +66,7 @@
#include <utils/savedaction.h>
#include <utils/qtcassert.h>
#include <utils/fileinprojectfinder.h>
#include <QDebug>
#include <QTimer>
......@@ -312,6 +313,7 @@ public:
bool m_isStateDebugging;
Utils::FileInProjectFinder m_fileFinder;
// Testing
void handleAutoTests();
void handleAutoTestLine(int line);
......@@ -1282,6 +1284,16 @@ DebuggerLanguages DebuggerEngine::languages() const
return d->m_languages;
}
QString DebuggerEngine::toFileInProject(const QUrl &fileUrl)
{
// make sure file finder is properly initialized
d->m_fileFinder.setProjectDirectory(startParameters().projectSourceDirectory);
d->m_fileFinder.setProjectFiles(startParameters().projectSourceFiles);
d->m_fileFinder.setSysroot(startParameters().sysroot);
return d->m_fileFinder.findFile(fileUrl);
}
bool DebuggerEngine::debuggerActionsEnabled() const
{
return debuggerActionsEnabled(d->m_state);
......
......@@ -286,6 +286,8 @@ public:
virtual void notifyInferiorIll();
QString toFileInProject(const QUrl &fileUrl);
signals:
void stateChanged(const Debugger::DebuggerState &state);
// A new stack frame is on display including locals.
......
......@@ -58,11 +58,9 @@
#include <projectexplorer/applicationlauncher.h>
#include <qmljsdebugclient/qdeclarativeoutputparser.h>
#include <qmljseditor/qmljseditorconstants.h>
#include <qmljsdebugclient/qdebugmessageclient.h>
#include <utils/environment.h>
#include <utils/qtcassert.h>
#include <utils/fileinprojectfinder.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
......@@ -110,7 +108,6 @@ private:
friend class QmlEngine;
QmlAdapter m_adapter;
ApplicationLauncher m_applicationLauncher;
Utils::FileInProjectFinder fileFinder;
QTimer m_noDebugOutputTimer;
QmlJsDebugClient::QDeclarativeOutputParser m_outputParser;
QHash<QString, QTextDocument*> m_sourceDocuments;
......@@ -157,8 +154,11 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters,
SLOT(updateCurrentContext()));
connect(&d->m_adapter, SIGNAL(selectionChanged()),
SLOT(updateCurrentContext()));
connect(d->m_adapter.messageClient(), SIGNAL(message(QtMsgType,QString)),
SLOT(appendDebugOutput(QtMsgType,QString)));
connect(d->m_adapter.messageClient(),
SIGNAL(message(QtMsgType,QString,
QmlJsDebugClient::QDebugContextInfo)),
SLOT(appendDebugOutput(QtMsgType,QString,
QmlJsDebugClient::QDebugContextInfo)));
connect(&d->m_applicationLauncher,
SIGNAL(processExited(int)),
......@@ -852,16 +852,6 @@ bool QmlEngine::hasCapability(unsigned cap) const
| AddWatcherCapability;*/
}
QString QmlEngine::toFileInProject(const QUrl &fileUrl)
{
// make sure file finder is properly initialized
d->fileFinder.setProjectDirectory(startParameters().projectSourceDirectory);
d->fileFinder.setProjectFiles(startParameters().projectSourceFiles);
d->fileFinder.setSysroot(startParameters().sysroot);
return d->fileFinder.findFile(fileUrl);
}
void QmlEngine::inferiorSpontaneousStop()
{
if (state() == InferiorRunOk)
......@@ -892,7 +882,8 @@ void QmlEngine::updateCurrentContext()
showMessage(tr("Context: ").append(context), QtMessageLogStatus);
}
void QmlEngine::appendDebugOutput(QtMsgType type, const QString &message)
void QmlEngine::appendDebugOutput(QtMsgType type, const QString &message,
const QmlJsDebugClient::QDebugContextInfo &info)
{
QtMessageLogHandler::ItemType itemType;
switch (type) {
......@@ -910,7 +901,10 @@ void QmlEngine::appendDebugOutput(QtMsgType type, const QString &message)
//This case is not possible
return;
}
qtMessageLogHandler()->appendItem(new QtMessageLogItem(itemType, message));
QtMessageLogItem *item = new QtMessageLogItem(itemType, message);
item->file = info.file;
item->line = info.line;
qtMessageLogHandler()->appendItem(item);
}
void QmlEngine::executeDebuggerCommand(const QString& command)
......@@ -987,7 +981,7 @@ void QmlEngine::setSourceFiles(const QStringList &fileNames)
QMap<QString,QString> files;
foreach (const QString &file, fileNames) {
QString shortName = file;
QString fullName = d->fileFinder.findFile(file);
QString fullName = toFileInProject(file);
files.insert(shortName, fullName);
}
......@@ -1080,9 +1074,9 @@ QtMessageLogItem *QmlEngine::constructLogItemTree(
QtMessageLogItem *item = new QtMessageLogItem();
if (result.type() == QVariant::Map) {
if (key.isEmpty())
item->setText(_("Object"));
item->text = _("Object");
else
item->setText(QString(_("%1: Object")).arg(key));
item->text = QString(_("%1: Object")).arg(key);
QMapIterator<QString, QVariant> i(result.toMap());
while (i.hasNext()) {
......@@ -1093,9 +1087,9 @@ QtMessageLogItem *QmlEngine::constructLogItemTree(
}
} else if (result.type() == QVariant::List) {
if (key.isEmpty())
item->setText(_("List"));
item->text = _("List");
else
item->setText(QString(_("[%1] : List")).arg(key));
item->text = QString(_("[%1] : List")).arg(key);
QVariantList resultList = result.toList();
for (int i = 0; i < resultList.count(); i++) {
QtMessageLogItem *child = constructLogItemTree(resultList.at(i),
......@@ -1104,9 +1098,9 @@ QtMessageLogItem *QmlEngine::constructLogItemTree(
item->insertChild(item->childCount(), child);
}
} else if (result.canConvert(QVariant::String)) {
item->setText(result.toString());
item->text = result.toString();
} else {
item->setText(_("Unknown Value"));
item->text = _("Unknown Value");
}
return item;
......
......@@ -35,6 +35,7 @@
#include "debuggerengine.h"
#include <qmljsdebugclient/qdeclarativeenginedebug.h>
#include <qmljsdebugclient/qdebugmessageclient.h>
#include <utils/outputformat.h>
#include <QAbstractSocket>
......@@ -80,7 +81,6 @@ public:
void gotoLocation(const Internal::Location &location);
void filterApplicationMessage(const QString &msg, int channel);
QString toFileInProject(const QUrl &fileUrl);
void inferiorSpontaneousStop();
void logMessage(const QString &service, LogDirection direction, const QString &str);
......@@ -98,7 +98,8 @@ private slots:
void wrongSetupMessageBox(const QString &errorMessage);
void wrongSetupMessageBoxFinished(int result);
void updateCurrentContext();
void appendDebugOutput(QtMsgType type, const QString &message);
void appendDebugOutput(QtMsgType type, const QString &message,
const QmlJsDebugClient::QDebugContextInfo &info);
private:
// DebuggerEngine implementation.
......
......@@ -164,6 +164,10 @@ void QtMessageLogEditor::keyPressEvent(QKeyEvent *e)
void QtMessageLogEditor::contextMenuEvent(QContextMenuEvent *event)
{
//TODO:: on right click the editor closes
//FIXIT
return QTextEdit::contextMenuEvent(event);
QTextCursor cursor = textCursor();
bool editable = cursor.position() > m_startOfEditableArea;
QMenu *menu = new QMenu();
......
......@@ -32,6 +32,10 @@
#include "qtmessageloghandler.h"
#include <utils/qtcassert.h>
#include <QFontMetrics>
namespace Debugger {
namespace Internal {
......@@ -43,9 +47,10 @@ namespace Internal {
QtMessageLogItem::QtMessageLogItem(QtMessageLogHandler::ItemType itemType,
const QString &text, QtMessageLogItem *parent)
: m_text(text),
m_itemType(itemType),
m_parentItem(parent)
: m_parentItem(parent),
text(text),
itemType(itemType),
line(-1)
{
}
......@@ -62,34 +67,27 @@ QtMessageLogItem *QtMessageLogItem::child(int number)
int QtMessageLogItem::childCount() const
{
return m_childItems.count();
return m_childItems.size();
}
int QtMessageLogItem::childNumber() const
{
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<QtMessageLogItem *>(this));
return m_parentItem->m_childItems.indexOf(
const_cast<QtMessageLogItem *>(this));
return 0;
}
QString QtMessageLogItem::text() const
{
return m_text;
}
QtMessageLogHandler::ItemType QtMessageLogItem::itemType() const
{
return m_itemType;
}
\
bool QtMessageLogItem::insertChildren(int position, int count)
{
if (position < 0 || position > m_childItems.size())
return false;
for (int row = 0; row < count; ++row) {
QtMessageLogItem *item = new QtMessageLogItem(QtMessageLogHandler::UndefinedType, QString(), this);
QtMessageLogItem *item = new
QtMessageLogItem(QtMessageLogHandler::UndefinedType, QString(),
this);
m_childItems.insert(position, item);
}
......@@ -136,18 +134,6 @@ bool QtMessageLogItem::detachChild(int position)
return true;
}
bool QtMessageLogItem::setText(const QString &text)
{
m_text = text;
return true;
}
bool QtMessageLogItem::setItemType(QtMessageLogHandler::ItemType itemType)
{
m_itemType = itemType;
return true;
}
///////////////////////////////////////////////////////////////////////
//
// QtMessageLogHandler
......@@ -157,7 +143,8 @@ bool QtMessageLogItem::setItemType(QtMessageLogHandler::ItemType itemType)
QtMessageLogHandler::QtMessageLogHandler(QObject *parent) :
QAbstractItemModel(parent),
m_hasEditableRow(false),
m_rootItem(new QtMessageLogItem())
m_rootItem(new QtMessageLogItem()),
m_maxSizeOfFileName(0)
{
}
......@@ -222,10 +209,37 @@ void QtMessageLogHandler::appendEditableRow()
void QtMessageLogHandler::removeEditableRow()
{
if (m_rootItem->child(m_rootItem->childCount() - 1)->itemType() == QtMessageLogHandler::InputType)
if (m_rootItem->child(m_rootItem->childCount() - 1)->itemType ==
QtMessageLogHandler::InputType)
removeRow(m_rootItem->childCount() - 1);
}
int QtMessageLogHandler::sizeOfFile(const QFont &font)
{
int lastReadOnlyRow = m_rootItem->childCount();
if (m_hasEditableRow)
lastReadOnlyRow -= 2;
else
lastReadOnlyRow -= 1;
if (lastReadOnlyRow < 0)
return 0;
QString filename = m_rootItem->child(lastReadOnlyRow)->file;
const int pos = filename.lastIndexOf(QLatin1Char('/'));
if (pos != -1)
filename = filename.mid(pos + 1);
QFontMetrics fm(font);
m_maxSizeOfFileName = qMax(m_maxSizeOfFileName, fm.width(filename));
return m_maxSizeOfFileName;
}
int QtMessageLogHandler::sizeOfLineNumber(const QFont &font)
{
QFontMetrics fm(font);
return fm.width(QLatin1String("88888"));
}
QVariant QtMessageLogHandler::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
......@@ -234,9 +248,13 @@ QVariant QtMessageLogHandler::data(const QModelIndex &index, int role) const
QtMessageLogItem *item = getItem(index);
if (role == Qt::DisplayRole )
return item->text();
return item->text;
else if (role == QtMessageLogHandler::TypeRole)
return int(item->itemType());
return int(item->itemType);
else if (role == QtMessageLogHandler::FileRole)
return item->file;
else if (role == QtMessageLogHandler::LineRole)
return item->line;
else
return QVariant();
}
......@@ -270,6 +288,8 @@ QModelIndex QtMessageLogHandler::parent(const QModelIndex &index) const
if (parentItem == m_rootItem)
return QModelIndex();
//can parentItem be 0?
QTC_ASSERT(parentItem, qDebug("Parent is Null!!"));
return createIndex(parentItem->childNumber(), 0, parentItem);
}
......@@ -302,12 +322,19 @@ bool QtMessageLogHandler::setData(const QModelIndex &index, const QVariant &valu
{
QtMessageLogItem *item = getItem(index);
bool result = false;
if (role == Qt::DisplayRole )
result = item->setText(value.toString());
else if (role == QtMessageLogHandler::TypeRole)
result = item->setItemType((QtMessageLogHandler::ItemType)value.toInt());
else if (value.canConvert(QVariant::String))
result = item->setText(value.toString());
if (role == Qt::DisplayRole) {
item->text = value.toString();
result = true;
} else if (role == QtMessageLogHandler::TypeRole) {
item->itemType = (QtMessageLogHandler::ItemType)value.toInt();
result = true;
} else if (role == QtMessageLogHandler::FileRole) {
item->file = value.toString();
result = true;
} else if (role == QtMessageLogHandler::LineRole) {
item->line = value.toInt();
result = true;
}
if (result)
emit dataChanged(index, index);
......
......@@ -35,6 +35,7 @@
#include <QAbstractItemModel>
#include <QItemSelectionModel>
#include <QFont>
namespace Debugger {
namespace Internal {
......@@ -56,7 +57,7 @@ public:
};
Q_DECLARE_FLAGS(ItemTypes, ItemType)
enum Roles { TypeRole = Qt::UserRole };
enum Roles { TypeRole = Qt::UserRole, FileRole, LineRole };
explicit QtMessageLogHandler(QObject *parent = 0);
~QtMessageLogHandler();
......@@ -74,6 +75,9 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int sizeOfFile(const QFont &font);
int sizeOfLineNumber(const QFont &font);
public slots:
void clear();
......@@ -106,35 +110,36 @@ protected:
private:
bool m_hasEditableRow;
QtMessageLogItem *m_rootItem;
int m_maxSizeOfFileName;
};
class QtMessageLogItem
{
public:
{
public:
QtMessageLogItem(QtMessageLogHandler::ItemType type = QtMessageLogHandler::UndefinedType,
const QString &data = QString(),
QtMessageLogItem *parent = 0);
~QtMessageLogItem();
QtMessageLogItem *child(int number);
int childCount() const;
QString text() const;
QtMessageLogHandler::ItemType itemType() const;
bool insertChildren(int position, int count);
bool insertChild(int position, QtMessageLogItem *item);
QtMessageLogItem *parent();
bool removeChildren(int position, int count);
bool detachChild(int position);
int childNumber() const;
bool setText(const QString &text);
bool setItemType(QtMessageLogHandler::ItemType itemType);
private:
QList<QtMessageLogItem *> m_childItems;
QString m_text;
QtMessageLogHandler::ItemType m_itemType;
QtMessageLogItem *m_parentItem;
};
const QString &data = QString(),
QtMessageLogItem *parent = 0);
~QtMessageLogItem();
QtMessageLogItem *child(int number);
int childCount() const;
bool insertChildren(int position, int count);
bool insertChild(int position, QtMessageLogItem *item);
QtMessageLogItem *parent();
bool removeChildren(int position, int count);
bool detachChild(int position);
int childNumber() const;
private:
QtMessageLogItem *m_parentItem;
QList<QtMessageLogItem *> m_childItems;
public:
QString text;
QtMessageLogHandler::ItemType itemType;
QString file;
int line;
};
} //Internal
} //Debugger
......
......@@ -32,10 +32,10 @@
#include "qtmessagelogitemdelegate.h"
#include "qtmessagelogeditor.h"
#include "qtmessageloghandler.h"
#include <QPainter>
#include <QTreeView>
#include <QScrollBar>
const char CONSOLE_LOG_BACKGROUND_COLOR[] = "#E8EEF2";
const char CONSOLE_WARNING_BACKGROUND_COLOR[] = "#F6F4EB";
......@@ -54,6 +54,8 @@ const char CONSOLE_EDITOR_TEXT_COLOR[] = "#000000";
const char CONSOLE_BORDER_COLOR[] = "#C9C9C9";
const int ELLIPSIS_GRADIENT_WIDTH = 16;
namespace Debugger {
namespace Internal {
......@@ -70,7 +72,8 @@ QtMessageLogItemDelegate::QtMessageLogItemDelegate(QObject *parent) :
m_errorIcon(QLatin1String(":/debugger/images/error.png")),
m_expandIcon(QLatin1String(":/debugger/images/expand.png")),
m_collapseIcon(QLatin1String(":/debugger/images/collapse.png")),
m_prompt(QLatin1String(":/debugger/images/prompt.png"))
m_prompt(QLatin1String(":/debugger/images/prompt.png")),
m_itemModel(0)
{
}
......@@ -79,7 +82,7 @@ void QtMessageLogItemDelegate::emitSizeHintChanged(const QModelIndex &index)
emit sizeHintChanged(index);
}
void QtMessageLogItemDelegate::drawBackground(QPainter *painter, const QRect &rect,
QColor QtMessageLogItemDelegate::drawBackground(QPainter *painter, const QRect &rect,
const QModelIndex &index,
bool selected) const
{
......@@ -110,7 +113,14 @@ void QtMessageLogItemDelegate::drawBackground(QPainter *painter, const QRect &re
painter->setBrush(backgroundColor);
painter->setPen(Qt::NoPen);
painter->drawRect(rect);
// Separator lines
painter->setPen(QColor(CONSOLE_BORDER_COLOR));
if (!(index.flags() & Qt::ItemIsEditable))
painter->drawLine(0, rect.bottom(), rect.right(),
rect.bottom());
painter->restore();
return backgroundColor;
}
void QtMessageLogItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
......@@ -148,7 +158,7 @@ void QtMessageLogItemDelegate::paint(QPainter *painter, const QStyleOptionViewIt
}
//Paint background
drawBackground(painter, opt.rect, index,
QColor backgroundColor = drawBackground(painter, opt.rect, index,
bool(opt.state & QStyle::State_Selected));
//Calculate positions
......@@ -159,13 +169,14 @@ void QtMessageLogItemDelegate::paint(QPainter *painter, const QStyleOptionViewIt
idx = idx.parent();
level++;
}
int width = view->width() - level * view->indentation();
int width = view->width() - level * view->indentation() -
view->verticalScrollBar()->width();
bool showTypeIcon = index.parent() == QModelIndex();
bool showExpandableIcon = type == QtMessageLogHandler::UndefinedType;
QRect rect(opt.rect.x(), opt.rect.top(), width, opt.rect.height());
ConsoleItemPositions positions(rect, opt.font, showTypeIcon,
showExpandableIcon);
showExpandableIcon, m_itemModel);
// Paint TaskIconArea:
if (showTypeIcon)
......@@ -198,11 +209,39 @@ void QtMessageLogItemDelegate::paint(QPainter *painter, const QStyleOptionViewIt
positions.expandCollapseIconHeight()));
}
// Separator lines
painter->setPen(QColor(CONSOLE_BORDER_COLOR));
if (!(index.flags() & Qt::ItemIsEditable))
painter->drawLine(0, opt.rect.bottom(), opt.rect.right(),
opt.rect.bottom());
//Check for file info
QString file = index.data(QtMessageLogHandler::FileRole).toString();
if (!file.isEmpty()) {
QFontMetrics fm(option.font);
// Paint FileArea
const int pos = file.lastIndexOf(QLatin1Char('/'));
if (pos != -1)
file = file.mid(pos +1);
const int realFileWidth = fm.width(file);
painter->setClipRect(positions.fileArea());
painter->drawText(qMin(positions.fileAreaLeft(),
positions.fileAreaRight() - realFileWidth),
positions.adjustedTop() + fm.ascent(), file);
if (realFileWidth > positions.fileAreaWidth()) {
// draw a gradient to mask the text
int gradientStart = positions.fileAreaLeft() - 1;
QLinearGradient lg(gradientStart +
ELLIPSIS_GRADIENT_WIDTH, 0, gradientStart, 0);
lg.setColorAt(0, Qt::transparent);
lg.setColorAt(1, backgroundColor);
painter->fillRect(gradientStart, positions.adjustedTop(),
ELLIPSIS_GRADIENT_WIDTH, positions.lineHeight(),
lg);
}
// Paint LineArea
QString lineText = index.data(QtMessageLogHandler::LineRole).toString();
painter->setClipRect(positions.lineArea());
const int realLineWidth = fm.width(lineText);
painter->drawText(positions.lineAreaRight() - realLineWidth,
positions.adjustedTop() + fm.ascent(), lineText);
}
painter->setClipRect(opt.rect);
painter->restore();
}
......@@ -219,7 +258,8 @@ QSize QtMessageLogItemDelegate::sizeHint(const QStyleOptionViewItem &option,
idx = idx.parent();
level++;
}
int width = view->width() - level * view->indentation();
int width = view->width() - level * view->indentation() -
view->verticalScrollBar()->width();
if (index.flags() & Qt::ItemIsEditable)
return QSize(width, view->height() * 1/2);
......@@ -230,8 +270,7 @@ QSize QtMessageLogItemDelegate::sizeHint(const QStyleOptionViewItem &option,
QRect rect(level * view->indentation(), 0, width, 0);
ConsoleItemPositions positions(rect, opt.font,
showTypeIcon,
showExpandableIcon);
showTypeIcon, showExpandableIcon, m_itemModel);
QTextLayout tl(index.data(Qt::DisplayRole).toString(), option.font);
qreal height = layoutText(tl, positions.textAreaWidth());
......@@ -310,5 +349,10 @@ qreal QtMessageLogItemDelegate::layoutText(QTextLayout &tl, int width) const
return height;
}
void QtMessageLogItemDelegate::setItemModel(QtMessageLogHandler *model)
{
m_itemModel = model;
}