2010-04-19 10:48:50 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
|
**
|
|
|
|
|
** Commercial Usage
|
|
|
|
|
**
|
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
2010-07-13 15:02:37 +02:00
|
|
|
#include "qtoutputformatter.h"
|
2010-04-19 10:48:50 +02:00
|
|
|
|
|
|
|
|
#include <texteditor/basetexteditor.h>
|
2010-07-13 15:02:37 +02:00
|
|
|
#include <qt4projectmanager/qt4project.h>
|
2010-04-19 10:48:50 +02:00
|
|
|
|
2010-07-13 15:02:37 +02:00
|
|
|
#include <QtCore/QFileInfo>
|
2010-08-05 21:03:37 +02:00
|
|
|
#include <QtCore/QUrl>
|
2010-04-19 10:48:50 +02:00
|
|
|
#include <QtGui/QPlainTextEdit>
|
2010-11-03 10:03:48 +01:00
|
|
|
#include <QtGui/QTextCursor>
|
2010-04-19 10:48:50 +02:00
|
|
|
|
|
|
|
|
using namespace ProjectExplorer;
|
2010-07-13 15:02:37 +02:00
|
|
|
using namespace Qt4ProjectManager;
|
2010-04-19 10:48:50 +02:00
|
|
|
|
2010-10-18 12:39:02 +02:00
|
|
|
QtOutputFormatter::QtOutputFormatter(ProjectExplorer::Project *project)
|
2010-07-13 15:02:37 +02:00
|
|
|
: OutputFormatter()
|
2010-08-05 21:03:37 +02:00
|
|
|
, m_qmlError(QLatin1String("(file:///.+:\\d+:\\d+):"))
|
2010-07-13 15:02:37 +02:00
|
|
|
, m_qtError(QLatin1String("Object::.*in (.*:\\d+)"))
|
2010-08-26 15:31:14 +02:00
|
|
|
, m_qtAssert(QLatin1String("^ASSERT: .* in file (.+, line \\d+)$"))
|
2010-08-29 16:42:03 +00:00
|
|
|
, m_qtTestFail(QLatin1String("^ Loc: \\[(.*)\\]$"))
|
2010-07-13 15:02:37 +02:00
|
|
|
, m_project(project)
|
2010-04-19 10:48:50 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-28 13:46:12 +02:00
|
|
|
LinkResult QtOutputFormatter::matchLine(const QString &line) const
|
2010-04-19 10:48:50 +02:00
|
|
|
{
|
2010-07-28 13:46:12 +02:00
|
|
|
LinkResult lr;
|
|
|
|
|
lr.start = -1;
|
|
|
|
|
lr.end = -1;
|
2010-09-22 11:54:04 +02:00
|
|
|
|
2010-07-28 13:46:12 +02:00
|
|
|
if (m_qmlError.indexIn(line) != -1) {
|
|
|
|
|
lr.href = m_qmlError.cap(1);
|
|
|
|
|
lr.start = m_qmlError.pos(1);
|
|
|
|
|
lr.end = lr.start + lr.href.length();
|
|
|
|
|
} else if (m_qtError.indexIn(line) != -1) {
|
|
|
|
|
lr.href = m_qtError.cap(1);
|
|
|
|
|
lr.start = m_qtError.pos(1);
|
|
|
|
|
lr.end = lr.start + lr.href.length();
|
2010-08-26 15:31:14 +02:00
|
|
|
} else if (m_qtAssert.indexIn(line) != -1) {
|
|
|
|
|
lr.href = m_qtAssert.cap(1);
|
|
|
|
|
lr.start = m_qtAssert.pos(1);
|
|
|
|
|
lr.end = lr.start + lr.href.length();
|
2010-08-29 16:42:03 +00:00
|
|
|
} else if (m_qtTestFail.indexIn(line) != -1) {
|
|
|
|
|
lr.href = m_qtTestFail.cap(1);
|
|
|
|
|
lr.start = m_qtTestFail.pos(1);
|
|
|
|
|
lr.end = lr.start + lr.href.length();
|
2010-04-19 10:48:50 +02:00
|
|
|
}
|
2010-07-28 13:46:12 +02:00
|
|
|
return lr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QtOutputFormatter::appendApplicationOutput(const QString &txt, bool onStdErr)
|
|
|
|
|
{
|
2010-09-22 11:54:04 +02:00
|
|
|
QTextCursor cursor(plainTextEdit()->document());
|
|
|
|
|
cursor.movePosition(QTextCursor::End);
|
|
|
|
|
cursor.beginEditBlock();
|
|
|
|
|
|
2010-07-28 13:46:12 +02:00
|
|
|
QString text = txt;
|
|
|
|
|
text.remove(QLatin1Char('\r'));
|
|
|
|
|
|
2010-09-22 11:54:04 +02:00
|
|
|
QString deferedText;
|
|
|
|
|
|
2010-07-28 13:46:12 +02:00
|
|
|
int start = 0;
|
|
|
|
|
int pos = txt.indexOf(QLatin1Char('\n'));
|
|
|
|
|
while (pos != -1) {
|
|
|
|
|
// Line identified
|
|
|
|
|
if (!m_lastLine.isEmpty()) {
|
|
|
|
|
// Line continuation
|
|
|
|
|
const QString newPart = txt.mid(start, pos - start + 1);
|
|
|
|
|
const QString line = m_lastLine + newPart;
|
|
|
|
|
LinkResult lr = matchLine(line);
|
|
|
|
|
if (!lr.href.isEmpty()) {
|
|
|
|
|
// Found something && line continuation
|
2010-09-22 11:54:04 +02:00
|
|
|
cursor.insertText(deferedText, format(onStdErr ? StdErrFormat : StdOutFormat));
|
|
|
|
|
deferedText.clear();
|
2010-07-28 13:46:12 +02:00
|
|
|
clearLastLine();
|
2010-09-22 11:54:04 +02:00
|
|
|
appendLine(cursor, lr, line, onStdErr);
|
2010-07-28 13:46:12 +02:00
|
|
|
} else {
|
|
|
|
|
// Found nothing, just emit the new part
|
2010-09-22 11:54:04 +02:00
|
|
|
deferedText += newPart;
|
2010-07-28 13:46:12 +02:00
|
|
|
}
|
|
|
|
|
// Handled line continuation
|
|
|
|
|
m_lastLine.clear();
|
|
|
|
|
} else {
|
|
|
|
|
const QString line = txt.mid(start, pos - start + 1);
|
|
|
|
|
LinkResult lr = matchLine(line);
|
|
|
|
|
if (!lr.href.isEmpty()) {
|
2010-09-22 11:54:04 +02:00
|
|
|
cursor.insertText(deferedText, format(onStdErr ? StdErrFormat : StdOutFormat));
|
|
|
|
|
deferedText.clear();
|
|
|
|
|
appendLine(cursor, lr, line, onStdErr);
|
2010-07-28 13:46:12 +02:00
|
|
|
} else {
|
2010-09-22 11:54:04 +02:00
|
|
|
deferedText += line;
|
2010-07-28 13:46:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
start = pos + 1;
|
|
|
|
|
pos = txt.indexOf(QLatin1Char('\n'), start);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle left over stuff
|
|
|
|
|
if (start < txt.length()) {
|
|
|
|
|
if (!m_lastLine.isEmpty()) {
|
|
|
|
|
// Line continuation
|
|
|
|
|
const QString newPart = txt.mid(start);
|
|
|
|
|
m_lastLine.append(newPart);
|
|
|
|
|
LinkResult lr = matchLine(m_lastLine);
|
|
|
|
|
if (!lr.href.isEmpty()) {
|
|
|
|
|
// Found something && line continuation
|
2010-09-22 11:54:04 +02:00
|
|
|
cursor.insertText(deferedText, format(onStdErr ? StdErrFormat : StdOutFormat));
|
|
|
|
|
deferedText.clear();
|
2010-07-28 13:46:12 +02:00
|
|
|
clearLastLine();
|
2010-09-22 11:54:04 +02:00
|
|
|
appendLine(cursor, lr, m_lastLine, onStdErr);
|
2010-07-28 13:46:12 +02:00
|
|
|
} else {
|
|
|
|
|
// Found nothing, just emit the new part
|
2010-09-22 11:54:04 +02:00
|
|
|
deferedText += newPart;
|
2010-07-28 13:46:12 +02:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
m_lastLine = txt.mid(start);
|
|
|
|
|
LinkResult lr = matchLine(m_lastLine);
|
|
|
|
|
if (!lr.href.isEmpty()) {
|
2010-09-22 11:54:04 +02:00
|
|
|
cursor.insertText(deferedText, format(onStdErr ? StdErrFormat : StdOutFormat));
|
|
|
|
|
deferedText.clear();
|
|
|
|
|
appendLine(cursor, lr, m_lastLine, onStdErr);
|
2010-07-28 13:46:12 +02:00
|
|
|
} else {
|
2010-09-22 11:54:04 +02:00
|
|
|
deferedText += m_lastLine;
|
2010-07-28 13:46:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-09-22 11:54:04 +02:00
|
|
|
cursor.insertText(deferedText, format(onStdErr ? StdErrFormat : StdOutFormat));
|
|
|
|
|
// deferedText.clear();
|
|
|
|
|
cursor.endEditBlock();
|
2010-07-28 13:46:12 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-22 11:54:04 +02:00
|
|
|
void QtOutputFormatter::appendLine(QTextCursor &cursor, LinkResult lr, const QString &line, bool onStdErr)
|
2010-07-28 13:46:12 +02:00
|
|
|
{
|
2010-10-18 13:33:55 +02:00
|
|
|
const QTextCharFormat normalFormat = format(onStdErr ? StdErrFormat : StdOutFormat);
|
|
|
|
|
cursor.insertText(line.left(lr.start), normalFormat);
|
|
|
|
|
|
|
|
|
|
QTextCharFormat linkFormat = normalFormat;
|
|
|
|
|
const QColor textColor = plainTextEdit()->palette().color(QPalette::Text);
|
|
|
|
|
linkFormat.setForeground(mixColors(textColor, QColor(Qt::blue)));
|
|
|
|
|
linkFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
|
|
|
|
|
linkFormat.setAnchor(true);
|
|
|
|
|
linkFormat.setAnchorHref(lr.href);
|
|
|
|
|
cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat);
|
|
|
|
|
|
|
|
|
|
cursor.insertText(line.mid(lr.end), normalFormat);
|
2010-07-13 15:02:37 +02:00
|
|
|
}
|
2010-04-19 10:48:50 +02:00
|
|
|
|
2010-07-13 15:02:37 +02:00
|
|
|
void QtOutputFormatter::handleLink(const QString &href)
|
|
|
|
|
{
|
2010-04-19 10:48:50 +02:00
|
|
|
if (!href.isEmpty()) {
|
2010-08-05 21:03:37 +02:00
|
|
|
const QRegExp qmlErrorLink(QLatin1String("^(file:///.+):(\\d+):(\\d+)"));
|
2010-04-19 10:48:50 +02:00
|
|
|
|
|
|
|
|
if (qmlErrorLink.indexIn(href) != -1) {
|
2010-08-05 21:03:37 +02:00
|
|
|
const QString fileName = QUrl(qmlErrorLink.cap(1)).toLocalFile();
|
2010-04-19 10:48:50 +02:00
|
|
|
const int line = qmlErrorLink.cap(2).toInt();
|
|
|
|
|
const int column = qmlErrorLink.cap(3).toInt();
|
|
|
|
|
TextEditor::BaseTextEditor::openEditorAt(fileName, line, column - 1);
|
2010-07-13 15:02:37 +02:00
|
|
|
return;
|
2010-04-19 10:48:50 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-26 15:31:14 +02:00
|
|
|
QString fileName;
|
|
|
|
|
int line = -1;
|
|
|
|
|
|
2010-07-13 15:02:37 +02:00
|
|
|
QRegExp qtErrorLink(QLatin1String("^(.*):(\\d+)$"));
|
2010-08-26 15:31:14 +02:00
|
|
|
if (qtErrorLink.indexIn(href) != -1) {
|
|
|
|
|
fileName = qtErrorLink.cap(1);
|
|
|
|
|
line = qtErrorLink.cap(2).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QRegExp qtAssertLink(QLatin1String("^(.+), line (\\d+)$"));
|
|
|
|
|
if (qtAssertLink.indexIn(href) != -1) {
|
|
|
|
|
fileName = qtAssertLink.cap(1);
|
|
|
|
|
line = qtAssertLink.cap(2).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-29 16:42:03 +00:00
|
|
|
QRegExp qtTestFailLink(QLatin1String("^(.*)\\((\\d+)\\)$"));
|
|
|
|
|
if (qtTestFailLink.indexIn(href) != -1) {
|
|
|
|
|
fileName = qtTestFailLink.cap(1);
|
|
|
|
|
line = qtTestFailLink.cap(2).toInt();
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-26 15:31:14 +02:00
|
|
|
if (!fileName.isEmpty()) {
|
2010-07-13 15:02:37 +02:00
|
|
|
QFileInfo fi(fileName);
|
|
|
|
|
if (fi.isRelative()) {
|
2010-10-30 21:54:23 +02:00
|
|
|
// Yeah fileName is relative, no surprise
|
2010-10-18 12:39:02 +02:00
|
|
|
ProjectExplorer::Project *pro = m_project.data();
|
2010-07-13 15:02:37 +02:00
|
|
|
if (pro) {
|
|
|
|
|
QString baseName = fi.fileName();
|
|
|
|
|
foreach (const QString &file, pro->files(Project::AllFiles)) {
|
|
|
|
|
if (file.endsWith(baseName)) {
|
|
|
|
|
// pick the first one...
|
|
|
|
|
fileName = file;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
TextEditor::BaseTextEditor::openEditorAt(fileName, line, 0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-04-19 10:48:50 +02:00
|
|
|
}
|