1 #include "latexlog.h"
2 #include "qlinemarksinfocenter.h"
3
LatexLogModel(QObject * parent)4 LatexLogModel::LatexLogModel(QObject *parent): QAbstractTableModel(parent)
5 {
6 markIDs[LT_NONE] = -1;
7 markIDs[LT_ERROR] = QLineMarksInfoCenter::instance()->markTypeId("error");
8 markIDs[LT_WARNING] = QLineMarksInfoCenter::instance()->markTypeId("warning");
9 markIDs[LT_BADBOX] = QLineMarksInfoCenter::instance()->markTypeId("badbox");
10 foundType[LT_NONE] = foundType[LT_ERROR] = foundType[LT_WARNING] = foundType[LT_BADBOX] = false;
11 }
12
columnCount(const QModelIndex & parent) const13 int LatexLogModel::columnCount(const QModelIndex &parent) const
14 {
15 return parent.isValid() ? 0 : 4;
16 }
17
rowCount(const QModelIndex & parent) const18 int LatexLogModel::rowCount(const QModelIndex &parent) const
19 {
20 return parent.isValid() ? 0 : log.count();
21 }
22
data(const QModelIndex & index,int role) const23 QVariant LatexLogModel::data(const QModelIndex &index, int role) const
24 {
25 if (!index.isValid()) return QVariant();
26 if (index.row() >= log.count() || index.row() < 0) return QVariant();
27 if (role == Qt::ToolTipRole) return tr("Click to jump to the line");
28 if (role == Qt::ForegroundRole) return LatexLogEntry::textColor(log.at(index.row()).type);
29 if (role != Qt::DisplayRole) return QVariant();
30 switch (index.column()) {
31 case 0:
32 return log.at(index.row()).file.mid(log.at(index.row()).file.lastIndexOf("/") + 1); //show relative names
33 case 1:
34 switch (log.at(index.row()).type) {
35 case LT_ERROR:
36 return tr("error");
37 case LT_WARNING:
38 return tr("warning");
39 case LT_BADBOX:
40 return tr("bad box");
41 default:
42 return QVariant(); //return Texstudio::tr("unknown");
43 }
44 case 2: {
45 int line = log.at(index.row()).oldline;
46 if (line > 0)
47 return tr("line") + QString(" %1").arg(line);
48 return QString();
49 }
50 case 3:
51 return log.at(index.row()).message;
52 default:
53 return QVariant();
54 }
55 }
56
headerData(int section,Qt::Orientation orientation,int role) const57 QVariant LatexLogModel::headerData(int section, Qt::Orientation orientation, int role) const
58 {
59 if (role != Qt::DisplayRole) return QVariant();
60 if (orientation != Qt::Horizontal) return QVariant();
61 switch (section) {
62 case 0:
63 return tr("File");
64 case 1:
65 return tr("Type");
66 case 2:
67 return tr("Line");
68 case 3:
69 return tr("Message");
70 default:
71 return QVariant();
72 }
73 }
74
count() const75 int LatexLogModel::count() const
76 {
77 return log.count();
78 }
79
clear()80 void LatexLogModel::clear()
81 {
82 beginResetModel();
83 log.clear();
84 endResetModel();
85 }
86
at(int i)87 const LatexLogEntry &LatexLogModel::at(int i)
88 {
89 return log.at(i);
90 }
91
92 //Parse a latex log file to find errors, warnings, bad boxes...
parseLogDocument(QTextDocument * doc,QString baseFileName)93 void LatexLogModel::parseLogDocument(QTextDocument *doc, QString baseFileName)
94 {
95 LatexOutputFilter outputFilter;
96 //TODO: investigate why it crashes if outputFilter is a member variable, m_infoList is set to a global variable by the LatexLogModel constructor instead here, but only if the m_filelookup member of LatexOutputFilter does exist
97 outputFilter.setSource(baseFileName);
98 outputFilter.run(doc);
99
100 beginResetModel();
101 log.clear();
102 QList<LatexLogEntry> laterLog;
103 for (int i = 0; i < outputFilter.m_infoList.count(); i++) {
104 LatexLogEntry cur = outputFilter.m_infoList.at(i);
105 if (cur.type == LT_ERROR) log << cur;
106 else laterLog << cur;
107 }
108 log << laterLog;
109
110 foundType[LT_ERROR] = outputFilter.m_nErrors > 0;
111 foundType[LT_BADBOX] = outputFilter.m_nBadBoxes > 0;
112 foundType[LT_WARNING] = outputFilter.m_nWarnings > 0;
113 endResetModel();
114 }
115
found(LogType lt) const116 bool LatexLogModel::found(LogType lt) const
117 {
118 Q_ASSERT_X(lt > 0 && lt < 4, "found logtype", "unbound array index");
119 return foundType[lt];
120 }
121
markID(LogType lt) const122 int LatexLogModel::markID(LogType lt) const
123 {
124 Q_ASSERT_X(lt > 0 && lt < 4, "markID logtype", "unbound array index");
125 return markIDs[lt];
126 }
127
logLineNumberToLogEntryNumber(int logLine) const128 int LatexLogModel::logLineNumberToLogEntryNumber(int logLine) const
129 {
130 int res = -1;
131 for (int i = 0; i < log.count(); i++)
132 if (log.at(i).logline <= logLine)
133 if (res == -1 || log.at(i).logline > log.at(res).logline)
134 res = i;
135 return res;
136 }
137
existsReRunWarning() const138 bool LatexLogModel::existsReRunWarning() const
139 {
140 if (!found(LT_WARNING)) return false;
141 const QRegularExpression rReRun ("(No file.*\\.(aux|toc))|"
142 "( Rerun )");
143 foreach (const LatexLogEntry &l, log) {
144 if (l.type != LT_WARNING || l.oldline != 0) continue;
145 if (l.message.contains(rReRun) && !l.message.contains("No file \\jobname .aux")) return true;
146 }
147 return false;
148 }
149
getMissingCitations() const150 QStringList LatexLogModel::getMissingCitations() const
151 {
152 QStringList sl;
153 static QRegExp rCitation ("Citation +[`'\"]([^`'\"]+)[`'\"] +.*undefined");
154 foreach (const LatexLogEntry &l, log) {
155 if (l.type != LT_WARNING) continue;
156 if (rCitation.indexIn(l.message) >= 0)
157 sl.append(rCitation.cap(1));
158 }
159 return sl;
160 }
161
htmlErrorTable(const QList<int> & errors)162 QString LatexLogModel::htmlErrorTable(const QList<int> &errors)
163 {
164 QString msg = "<table>";
165 foreach (int error, errors) {
166 if (error < 0 || error >= count()) continue;
167 msg.append(at(error).niceMessage());
168 }
169 return msg.append("</table>");
170 }
171
returnString(LogType type)172 QString LatexLogModel::returnString(LogType type)
173 {
174 switch (type) {
175 case LT_ERROR:
176 return tr("error");
177 case LT_WARNING:
178 return tr("warning");
179 case LT_BADBOX:
180 return tr("bad box");
181 default:
182 return QString();
183 }
184 }
185