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