OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qtoutputformatter.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "qtoutputformatter.h"
34
35 #include <texteditor/basetexteditor.h>
36 #include <qt4projectmanager/qt4project.h>
37 #include <utils/qtcassert.h>
38
39 #include <QtCore/QFileInfo>
40 #include <QtCore/QUrl>
41 #include <QtGui/QPlainTextEdit>
42 #include <QtGui/QTextCursor>
43
44 using namespace ProjectExplorer;
45 using namespace Qt4ProjectManager;
46
47 QtOutputFormatter::QtOutputFormatter(ProjectExplorer::Project *project)
48     : OutputFormatter()
49     , m_qmlError(QLatin1String("^(?:\\[Qt Message\\] )?" // '[Qt Message] ' prefix (optional, on Symbian)
50                                "(file:///.+"      // file url
51                                ":\\d+"           // colon, line
52                                "(?::\\d+)?)"     // colon, column (optional)
53                                ":"))             // colon
54     , m_qtError(QLatin1String("Object::.*in (.*:\\d+)"))
55     , m_qtAssert(QLatin1String("ASSERT: .* in file (.+, line \\d+)"))
56     , m_qtTestFail(QLatin1String("^   Loc: \\[(.*)\\]"))
57     , m_project(project)
58 {
59     if(project) {
60         m_projectFinder.setProjectFiles(project->files(Qt4Project::ExcludeGeneratedFiles));
61         m_projectFinder.setProjectDirectory(project->projectDirectory());
62
63         connect(project, SIGNAL(fileListChanged()),
64                 this, SLOT(updateProjectFileList()));
65     }
66 }
67
68 LinkResult QtOutputFormatter::matchLine(const QString &line) const
69 {
70     LinkResult lr;
71     lr.start = -1;
72     lr.end = -1;
73
74     if (m_qmlError.indexIn(line) != -1) {
75         lr.href = m_qmlError.cap(1);
76         lr.start = m_qmlError.pos(1);
77         lr.end = lr.start + lr.href.length();
78     } else if (m_qtError.indexIn(line) != -1) {
79         lr.href = m_qtError.cap(1);
80         lr.start = m_qtError.pos(1);
81         lr.end = lr.start + lr.href.length();
82     } else if (m_qtAssert.indexIn(line) != -1) {
83         lr.href = m_qtAssert.cap(1);
84         lr.start = m_qtAssert.pos(1);
85         lr.end = lr.start + lr.href.length();
86     } else if (m_qtTestFail.indexIn(line) != -1) {
87         lr.href = m_qtTestFail.cap(1);
88         lr.start = m_qtTestFail.pos(1);
89         lr.end = lr.start + lr.href.length();
90     }
91     return lr;
92 }
93
94 void QtOutputFormatter::appendMessage(const QString &txt, OutputFormat format)
95 {
96     QTextCursor cursor(plainTextEdit()->document());
97     cursor.movePosition(QTextCursor::End);
98     cursor.beginEditBlock();
99
100     QString text = txt;
101     text.remove(QLatin1Char('\r'));
102
103     QString deferedText;
104
105     int start = 0;
106     int pos = txt.indexOf(QLatin1Char('\n'));
107     while (pos != -1) {
108         // Line identified
109         if (!m_lastLine.isEmpty()) {
110             // Line continuation
111             const QString newPart = txt.mid(start, pos - start + 1);
112             const QString line = m_lastLine + newPart;
113             LinkResult lr = matchLine(line);
114             if (!lr.href.isEmpty()) {
115                 // Found something && line continuation
116                 cursor.insertText(deferedText, charFormat(format));
117                 deferedText.clear();
118                 clearLastLine();
119                 appendLine(cursor, lr, line, format);
120             } else {
121                 // Found nothing, just emit the new part
122                 deferedText += newPart;
123             }
124             // Handled line continuation
125             m_lastLine.clear();
126         } else {
127             const QString line = txt.mid(start, pos - start + 1);
128             LinkResult lr = matchLine(line);
129             if (!lr.href.isEmpty()) {
130                 cursor.insertText(deferedText, charFormat(format));
131                 deferedText.clear();
132                 appendLine(cursor, lr, line, format);
133             } else {
134                 deferedText += line;
135             }
136         }
137         start = pos + 1;
138         pos = txt.indexOf(QLatin1Char('\n'), start);
139     }
140
141     // Handle left over stuff
142     if (start < txt.length()) {
143         if (!m_lastLine.isEmpty()) {
144             // Line continuation
145             const QString newPart = txt.mid(start);
146             m_lastLine.append(newPart);
147             LinkResult lr = matchLine(m_lastLine);
148             if (!lr.href.isEmpty()) {
149                 // Found something && line continuation
150                 cursor.insertText(deferedText, charFormat(format));
151                 deferedText.clear();
152                 clearLastLine();
153                 appendLine(cursor, lr, m_lastLine, format);
154             } else {
155                 // Found nothing, just emit the new part
156                 deferedText += newPart;
157             }
158         } else {
159             m_lastLine = txt.mid(start);
160             LinkResult lr = matchLine(m_lastLine);
161             if (!lr.href.isEmpty()) {
162                 cursor.insertText(deferedText, charFormat(format));
163                 deferedText.clear();
164                 appendLine(cursor, lr, m_lastLine, format);
165             } else {
166                 deferedText += m_lastLine;
167             }
168         }
169     }
170     cursor.insertText(deferedText, charFormat(format));
171     // deferedText.clear();
172     cursor.endEditBlock();
173 }
174
175 void QtOutputFormatter::appendLine(QTextCursor &cursor, LinkResult lr,
176     const QString &line, ProjectExplorer::OutputFormat format)
177 {
178     const QTextCharFormat normalFormat = charFormat(format);
179     cursor.insertText(line.left(lr.start), normalFormat);
180
181     QTextCharFormat linkFormat = normalFormat;
182     const QColor textColor = plainTextEdit()->palette().color(QPalette::Text);
183     linkFormat.setForeground(mixColors(textColor, QColor(Qt::blue)));
184     linkFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
185     linkFormat.setAnchor(true);
186     linkFormat.setAnchorHref(lr.href);
187     cursor.insertText(line.mid(lr.start, lr.end - lr.start), linkFormat);
188     cursor.insertText(line.mid(lr.end), normalFormat);
189 }
190
191 void QtOutputFormatter::handleLink(const QString &href)
192 {
193     if (!href.isEmpty()) {
194         const QRegExp qmlLineColumnLink(QLatin1String("^(file:///.+)" // file url
195                                                  ":(\\d+)"            // line
196                                                  ":(\\d+)$"));        // column
197
198         if (qmlLineColumnLink.indexIn(href) != -1) {
199             const QString fileName = QUrl(qmlLineColumnLink.cap(1)).toLocalFile();
200             const int line = qmlLineColumnLink.cap(2).toInt();
201             const int column = qmlLineColumnLink.cap(3).toInt();
202
203             TextEditor::BaseTextEditorWidget::openEditorAt(m_projectFinder.findFile(fileName), line, column - 1);
204
205             return;
206         }
207
208         const QRegExp qmlLineLink(QLatin1String("^(file:///.+)" // file url
209                                                  ":(\\d+)$"));  // line
210
211         if (qmlLineLink.indexIn(href) != -1) {
212             const QString fileName = QUrl(qmlLineLink.cap(1)).toLocalFile();
213             const int line = qmlLineLink.cap(2).toInt();
214             TextEditor::BaseTextEditorWidget::openEditorAt(m_projectFinder.findFile(fileName), line);
215             return;
216         }
217
218         QString fileName;
219         int line = -1;
220
221         QRegExp qtErrorLink(QLatin1String("^(.*):(\\d+)$"));
222         if (qtErrorLink.indexIn(href) != -1) {
223             fileName = qtErrorLink.cap(1);
224             line = qtErrorLink.cap(2).toInt();
225         }
226
227         QRegExp qtAssertLink(QLatin1String("^(.+), line (\\d+)$"));
228         if (qtAssertLink.indexIn(href) != -1) {
229             fileName = qtAssertLink.cap(1);
230             line = qtAssertLink.cap(2).toInt();
231         }
232
233         QRegExp qtTestFailLink(QLatin1String("^(.*)\\((\\d+)\\)$"));
234         if (qtTestFailLink.indexIn(href) != -1) {
235             fileName = qtTestFailLink.cap(1);
236             line = qtTestFailLink.cap(2).toInt();
237         }
238
239         if (!fileName.isEmpty()) {
240             QFileInfo fi(fileName);
241             if (fi.isRelative()) {
242                 // Yeah fileName is relative, no surprise
243                 ProjectExplorer::Project *pro = m_project.data();
244                 if (pro) {
245                     QString baseName = fi.fileName();
246                     foreach (const QString &file, pro->files(Project::AllFiles)) {
247                         if (file.endsWith(baseName)) {
248                             // pick the first one...
249                             fileName = file;
250                             break;
251                         }
252                     }
253                 }
254             } else if (!fi.exists()) {
255                 // map possible on-device path to source path
256                 fileName = m_projectFinder.findFile(fileName);
257             }
258             TextEditor::BaseTextEditorWidget::openEditorAt(fileName, line, 0);
259             return;
260         }
261     }
262 }
263
264 void QtOutputFormatter::updateProjectFileList()
265 {
266     if (m_project)
267         m_projectFinder.setProjectFiles(m_project.data()->files(Qt4Project::ExcludeGeneratedFiles));
268 }