comparison src/converter.cpp @ 76:1e6e7699f0b8

Add replacements.ini to configure text replacements
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 05 Oct 2016 14:23:23 +0200
parents 92139cc60121
children f230ed9022e0
comparison
equal deleted inserted replaced
75:92139cc60121 76:1e6e7699f0b8
12 #include <QRegularExpressionMatch> 12 #include <QRegularExpressionMatch>
13 #include <QTextDocument> 13 #include <QTextDocument>
14 #include <QPrinter> 14 #include <QPrinter>
15 #include <QImage> 15 #include <QImage>
16 #include <QPainter> 16 #include <QPainter>
17 #include <QMessageBox>
18 #include <QDir>
19 #include <QCoreApplication>
20 #include <QSettings>
17 21
18 #include "xlsxdocument.h" 22 #include "xlsxdocument.h"
19 #include "xlsxconditionalformatting.h" 23 #include "xlsxconditionalformatting.h"
20 24
21 #include "constants.h" 25 #include "constants.h"
133 QVariant(image)); 137 QVariant(image));
134 html << QStringLiteral("<td style='vertical-align: middle'><img src=\"internal://bar%1.png\"/></td>").arg((int)percent); 138 html << QStringLiteral("<td style='vertical-align: middle'><img src=\"internal://bar%1.png\"/></td>").arg((int)percent);
135 return; 139 return;
136 } 140 }
137 141
138 static void unescapeRegex(QString &str, const QRegularExpression &exp) 142 static const QMap<QRegularExpression*, QString> loadExpressionsFromFile(const QString &path, QStringList &errors)
139 { 143 {
140 QRegularExpressionMatch match = exp.match(str); 144 QFile file(path);
141 while (match.hasMatch()) { 145 QMap<QRegularExpression*, QString> ret;
142 str.replace(match.capturedStart(), match.capturedLength(), match.captured(1)); 146
143 match = exp.match(str); 147 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
144 } 148 errors << QObject::tr("Failed to open replacement file:") + "\n\"" + path + "\"";
145 } 149 return ret;
146 150 }
147 static void unescapeString(QString &str) 151
148 { 152 while (!file.atEnd()) {
149 static const QRegularExpression imgEx(IMAGE_PATTERN); 153 const auto line = file.readLine();
150 static const QRegularExpression texEx(LATEX_PATTERN); 154 auto strline = QString::fromUtf8(line).trimmed();
151 155 if (strline.startsWith(QStringLiteral(";")) || strline.isEmpty()) {
152 unescapeRegex(str, imgEx); 156 continue;
153 unescapeRegex(str, texEx); 157 }
158
159 auto split = strline.split("=");
160 if (split.count() != 2) {
161 errors << QObject::tr("Invalid replacement line:") + "\n\"" + strline + "\"";
162 continue;
163 }
164
165 auto exp = new QRegularExpression (split[0], QRegularExpression::MultilineOption);
166 if (!exp->isValid()) {
167 errors << QObject::tr("Invalid regular expression:") + "\n\"" + split[0] + "\"" +
168 "\n" + QObject::tr("Error: ") + exp->errorString();
169 continue;
170 }
171 const auto rep = split[1].replace("\"", "");
172 ret.insert(exp, rep);
173 qDebug() << "Loaded replacement: " << *exp << " replacement:" << rep << "";
174 }
175 /* Special one that does not fit into the ini format well. */
176 ret.insert(new QRegularExpression("^="), " =");
177 return ret;
178 }
179
180 static const QMap<QRegularExpression*, QString> loadExpressions(QStringList &errors)
181 {
182 QMap<QRegularExpression*, QString> regexs;
183 /* Look for file next to our place */
184 auto ourDir = QDir(QCoreApplication::applicationDirPath());
185 const auto filename = QStringLiteral(CONFIG_FILE_NAME);
186 if (ourDir.exists(filename)) {
187 regexs = loadExpressionsFromFile(ourDir.filePath(filename), errors);
188 return regexs;
189 }
190
191 /* Look in ../share/apps/PROJECT_NAME */
192 ourDir.cd(QStringLiteral("../share/apps/" APPNAME).toLower());
193 if (ourDir.exists(filename)) {
194 regexs = loadExpressionsFromFile(ourDir.filePath(filename), errors);
195 } else {
196 qDebug() << "Failed to find regular expressions.";
197 }
198 return regexs;
199 }
200
201 static const QStringList sanitizeInput(QString &str)
202 {
203 QStringList errors;
204 str.replace("\r\n", "\n");
205 str.replace("\n\r", "\n");
206 const auto expressions = loadExpressions(errors);
207 for (const auto regex: expressions.keys()) {
208 str.replace(*regex, expressions.value(regex));
209 delete regex;
210 }
211 return errors;
212 }
213
214 static void xlsEscape(QString &str)
215 {
154 if (str.startsWith("=")) { 216 if (str.startsWith("=")) {
155 str = " " + str; 217 str = " " + str;
156 } 218 }
157 } 219 }
158 220
201 QRegularExpression choiceEx(CHOICE_PATTERN); 263 QRegularExpression choiceEx(CHOICE_PATTERN);
202 QRegularExpression choiceAltEx(CHOICE_UNFILLED_PATTERN); 264 QRegularExpression choiceAltEx(CHOICE_UNFILLED_PATTERN);
203 QRegularExpression freetxtEx(FREETXT_PATTERN); 265 QRegularExpression freetxtEx(FREETXT_PATTERN);
204 QRegularExpression firstQuestionEx(FIRST_QUESTION_PATTERN); 266 QRegularExpression firstQuestionEx(FIRST_QUESTION_PATTERN);
205 267
206 input.replace("\r\n", "\n"); 268 mErrors += sanitizeInput(input);
207 input.replace("\n\r", "\n");
208 input.replace("#NAME?\n", "");
209 269
210 QRegularExpressionMatch match = firstQuestionEx.match(input); 270 QRegularExpressionMatch match = firstQuestionEx.match(input);
211 bool foundSomething = false; 271 bool foundSomething = false;
212 int cursor = match.capturedEnd(); 272 int cursor = match.capturedEnd();
213 while (match.hasMatch() && cursor != -1) { 273 while (match.hasMatch() && cursor != -1) {
227 unescapeString(question); 287 unescapeString(question);
228 qDebug() << "First question: " << question; 288 qDebug() << "First question: " << question;
229 const QString answerLine = match.captured(2).trimmed(); 289 const QString answerLine = match.captured(2).trimmed();
230 xlsx.write(row, 2, QString(" "), mQuestionFmt); 290 xlsx.write(row, 2, QString(" "), mQuestionFmt);
231 xlsx.write(row, 3, QString(" "), mQuestionFmt); 291 xlsx.write(row, 3, QString(" "), mQuestionFmt);
292 xlsEscape(question);
232 xlsx.write(row++, 1, question, mQuestionFmt); 293 xlsx.write(row++, 1, question, mQuestionFmt);
233 html << mQuestionStyle.arg(question.toHtmlEscaped()); 294 html << mQuestionStyle.arg(question.toHtmlEscaped());
234 295
235 if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) { 296 if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) {
236 xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT); 297 xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
246 otherwise we can't figure out when the next question begins. */ 307 otherwise we can't figure out when the next question begins. */
247 cursor = choiceMatch.capturedEnd(); 308 cursor = choiceMatch.capturedEnd();
248 309
249 /* Write the values */ 310 /* Write the values */
250 QString choiceName = choiceMatch.captured(1).trimmed(); 311 QString choiceName = choiceMatch.captured(1).trimmed();
251 if (choiceName.startsWith("=")) { 312 xlsEscape(choiceName);
252 choiceName = " " + choiceName;
253 }
254 unescapeString(choiceName);
255 xlsx.write(row, 1, choiceName, mChoiceTextFmt); 313 xlsx.write(row, 1, choiceName, mChoiceTextFmt);
256 html << mChoiceTextStyle.arg(choiceName.toHtmlEscaped()); 314 html << mChoiceTextStyle.arg(choiceName.toHtmlEscaped());
257 qDebug() << "Captured for choice: " << choiceMatch.captured(0); 315 qDebug() << "Captured for choice: " << choiceMatch.captured(0);
258 bool ok; 316 bool ok;
259 QString percentStr = choiceMatch.captured("percent"); 317 QString percentStr = choiceMatch.captured("percent");
290 while (choiceMatch.hasMatch() && choiceMatch.capturedStart() <= cursor + 1) { 348 while (choiceMatch.hasMatch() && choiceMatch.capturedStart() <= cursor + 1) {
291 additionalFound = true; 349 additionalFound = true;
292 QString choice = choiceMatch.captured(1); 350 QString choice = choiceMatch.captured(1);
293 cursor = choiceMatch.capturedEnd(); 351 cursor = choiceMatch.capturedEnd();
294 /* Alternative answer that is just a list of strings */ 352 /* Alternative answer that is just a list of strings */
295 unescapeString(choice);
296 qDebug() << "Captured unfilled choice: " << choice; 353 qDebug() << "Captured unfilled choice: " << choice;
297 html << mChoiceTextStyle.arg(choice.toHtmlEscaped()); 354 html << mChoiceTextStyle.arg(choice.toHtmlEscaped());
298 makeBar(html, 0, doc); 355 makeBar(html, 0, doc);
356 xlsEscape(choice);
299 xlsx.write(row, 1, choice); 357 xlsx.write(row, 1, choice);
300 xlsx.write(row, 2, QVariant()); 358 xlsx.write(row, 2, QVariant());
301 const QString numVotesString = QStringLiteral("Keine eingegangenen Antworten"); 359 const QString numVotesString = QStringLiteral("Keine eingegangenen Antworten");
302 html << mChoiceVotesStyle.arg(numVotesString.toHtmlEscaped()); 360 html << mChoiceVotesStyle.arg(numVotesString.toHtmlEscaped());
303 xlsx.write(row, 3, numVotesString, mChoiceVotesFmt); 361 xlsx.write(row, 3, numVotesString, mChoiceVotesFmt);
343 const QString lastRow = xlsx.read(row - 1, 26).toString(); 401 const QString lastRow = xlsx.read(row - 1, 26).toString();
344 int unquotedLen = textMatch.capturedStart() - cursor; 402 int unquotedLen = textMatch.capturedStart() - cursor;
345 const QString unquoted = input.mid(cursor, unquotedLen); 403 const QString unquoted = input.mid(cursor, unquotedLen);
346 qDebug() << "Found inner quoted string: " << unquoted; 404 qDebug() << "Found inner quoted string: " << unquoted;
347 /* Now combine */ 405 /* Now combine */
348 const QString combined = QString("%1\"%2\"%3").arg(lastRow). 406 QString combined = QString("%1\"%2\"%3").arg(lastRow).
349 arg(unquoted). 407 arg(unquoted).
350 arg(textMatch.captured(1).trimmed()); 408 arg(textMatch.captured(1).trimmed());
351 qDebug() << "Last row: " << lastRow; 409 qDebug() << "Last row: " << lastRow;
352 qDebug() << "Next Question is at: " << nextQuestion.capturedStart(); 410 qDebug() << "Next Question is at: " << nextQuestion.capturedStart();
353 qDebug() << "Text match is: " << textMatch.captured(1).trimmed(); 411 qDebug() << "Text match is: " << textMatch.captured(1).trimmed();
354 qDebug() << "cursor is at: " << cursor; 412 qDebug() << "cursor is at: " << cursor;
355 qDebug() << "text match starts at: " << textMatch.capturedStart(); 413 qDebug() << "text match starts at: " << textMatch.capturedStart();
414 xlsEscape(combined);
356 xlsx.write(row - 1, 26, combined, mFreeTextFmt); 415 xlsx.write(row - 1, 26, combined, mFreeTextFmt);
357 xlsx.write(row - 1, 1, combined, mFreeTextFmt); 416 xlsx.write(row - 1, 1, combined, mFreeTextFmt);
358 cursor = textMatch.capturedEnd(); 417 cursor = textMatch.capturedEnd();
359 textMatch = freetxtEx.match(input, cursor); 418 textMatch = freetxtEx.match(input, cursor);
360 continue; 419 continue;
372 431
373 /* Merged cells ignore wordwrap the following trick is based on: 432 /* Merged cells ignore wordwrap the following trick is based on:
374 http://excel.tips.net/T003207_Automatic_Row_Height_For_Merged_Cells_with_Text_Wrap.html 433 http://excel.tips.net/T003207_Automatic_Row_Height_For_Merged_Cells_with_Text_Wrap.html
375 */ 434 */
376 /* Write the values */ 435 /* Write the values */
436 xlsEscape(text);
377 xlsx.write(QString("Z%1").arg(row), text, mFreeTextFmt); 437 xlsx.write(QString("Z%1").arg(row), text, mFreeTextFmt);
378 xlsx.write(row, 1, text, mFreeTextFmt); 438 xlsx.write(row, 1, text, mFreeTextFmt);
379 row++; 439 row++;
380 440
381 textMatch = freetxtEx.match(input, cursor); 441 textMatch = freetxtEx.match(input, cursor);
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)