Mercurial > clickerconvert
changeset 41:f6c53e896008 0.9
Merge
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Fri, 15 Apr 2016 15:34:51 +0200 |
parents | 7458f113314c (current diff) 5354cbda7188 (diff) |
children | 8b6cb95d00be |
files | src/converter.cpp src/l10n/main_de_DE.ts |
diffstat | 7 files changed, 125 insertions(+), 129 deletions(-) [+] |
line wrap: on
line diff
--- a/README Fri Apr 15 15:25:11 2016 +0200 +++ b/README Fri Apr 15 15:34:51 2016 +0200 @@ -26,8 +26,12 @@ - A Question is defined by last unquoted string before a line starting with "Answer" - A multiple choice Answer are all strings that match the pattern - "\"(.*)\",(\\d+),(\\d+\\.\\d+)" in all lines following a line + "\"(.*)\",(\\d+)?,(\\d+\\.+\\d+)?" in all lines following a line "Answer,Votes,Percent" before the next Question. + - A special case is made for lines in a multiple choice block that + contain multiple comma seperated quoted strings. In that case the + line is interpreted as each quotet string containing an unfilled + answer. - A free text answer is a Quoted string following a Question and the single line "Answer". All text before the next question is interpreted as free text responses.
--- a/src/cconvert_options.h Fri Apr 15 15:25:11 2016 +0200 +++ b/src/cconvert_options.h Fri Apr 15 15:34:51 2016 +0200 @@ -17,13 +17,10 @@ { QList<QCommandLineOption> options; - options << QCommandLineOption(QStringList() << QStringLiteral("format") - << QStringLiteral("f"), - QObject::tr("Output format (default xlsx)."), - QStringLiteral("xlsx pdf html")) - << QCommandLineOption(QStringList() << QStringLiteral("output") + options << QCommandLineOption(QStringList() << QStringLiteral("output") << QStringLiteral("o"), - QObject::tr("write output to file (default stdout)"), + QObject::tr("write output to file (default stdout)") + "\n" + + QObject::tr("The file type is determined by the extension\nEither: .pdf .html or .xlsx (default)"), QObject::tr("file")) << QCommandLineOption(QStringList() << QStringLiteral("title") << QStringLiteral("t"),
--- a/src/constants.h Fri Apr 15 15:25:11 2016 +0200 +++ b/src/constants.h Fri Apr 15 15:34:51 2016 +0200 @@ -63,7 +63,11 @@ /** * @brief The pattern used to match a multiple choice answer. */ -#define CHOICE_PATTERN "\"(.*)\",(\\d+),(\\d+\\.\\d+)" +#define CHOICE_PATTERN "\"(.*)\",(?<num>\\d+)?,(?<percent>\\d+\\.?\\d+)?" + +/** + * @brief The pattern used to match an unfilled choice answer. */ +#define CHOICE_UNFILLED_PATTERN "\"([^\"]*)\"," /** * @brief The pattern used to match a free text answer. */ @@ -79,8 +83,12 @@ #define DEFAULT_TITLE QStringLiteral("Clicker-Fragen und Antworten") -#define HTML_WIDTH 960 - #define BAR_COLOR "#ff9933" +#define IMAGE_WIDTH 200 + +#define HTML_COL1_PERCENT 35 +#define HTML_COL2_PERCENT 30 +#define HTML_COL3_PERCENT 35 + #endif // CONSTANTS_H
--- a/src/converter.cpp Fri Apr 15 15:25:11 2016 +0200 +++ b/src/converter.cpp Fri Apr 15 15:34:51 2016 +0200 @@ -22,12 +22,11 @@ QTXLSX_USE_NAMESPACE -Converter::Converter(const QString &input, const QString &output, - ConvertFormat fmt, const QString &title): +Converter::Converter(const QString &input, const QStringList &outputs, + const QString &title): QThread(Q_NULLPTR), mInput(input), - mOutput(output), - mFmt(fmt), + mOutputs(outputs), mTitle(title) { mTitleFmt.setFontUnderline(Format::FontUnderlineSingle); @@ -95,49 +94,49 @@ } QTextStream instream(&infile); - QFile outfile; - if (mOutput.isEmpty()) { - if (!outfile.open(stdout, QIODevice::WriteOnly)) { + QList<QFile*> outfiles; + + if (mOutputs.isEmpty()) { + QFile *outfile = new QFile(); + if (!outfile->open(stdout, QIODevice::WriteOnly)) { mErrors << tr("Failed to open standard output and no output file provided."); return; } - } else { - outfile.setFileName(mOutput); - if (!outfile.open(QIODevice::WriteOnly)) { - mErrors << tr("Failed to open %1 for writing.").arg(mOutput); + outfiles << outfile; + } + foreach (const QString &fileName, mOutputs) { + QFile *outfile = new QFile(); + outfile->setFileName(fileName); + if (!outfile->open(QIODevice::WriteOnly)) { + mErrors << tr("Failed to open %1 for writing.").arg(fileName); return; } + outfiles << outfile; } - convertToXSLX(instream, outfile); + convertToXSLX(instream, outfiles); } -static void makeBar(QTextStream &html, double percent, int width, QTextDocument &doc, bool forPDF) +static void makeBar(QTextStream &html, double percent, QTextDocument &doc) { - static int barCnt; - if (!forPDF) { - html << QStringLiteral("<td style='background:linear-gradient(to right," - BAR_COLOR ", " BAR_COLOR " %1%, #ffffff %1%)'></td>").arg(percent); - return; - } - QImage image(QSize(width, 25), QImage::Format_RGB32); + QImage image(QSize(IMAGE_WIDTH, 25), QImage::Format_RGB32); QPainter painter(&image); QRect rect = image.rect(); - qDebug() << "Image of " << width; - rect.setRight(rect.right() / (100 / percent)); - painter.fillRect(rect, QColor(BAR_COLOR)); + if (percent) { + rect.setRight(rect.right() / (100. / percent)); + painter.fillRect(rect, QColor(BAR_COLOR)); + rect.setLeft(rect.right()); + } qDebug() << "Filled " << rect << " with color"; - rect.setLeft(rect.right()); - rect.setRight(width); + rect.setRight(IMAGE_WIDTH); painter.fillRect(rect, Qt::white); qDebug() << "Filled " << rect << " with white"; - doc.addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("internal://bar%1.png").arg(barCnt)), + doc.addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("internal://bar%1.png").arg((int)percent)), QVariant(image)); - html << QStringLiteral("<td style='vertical-align: middle'><img src=\"internal://bar%1.png\"/></td>").arg(barCnt++); - image.save(QStringLiteral("/tmp/foo.png")); + html << QStringLiteral("<td style='vertical-align: middle'><img src=\"internal://bar%1.png\"/></td>").arg((int)percent); return; } -void Converter::convertToXSLX(QTextStream& instream, QFile &output) +void Converter::convertToXSLX(QTextStream& instream, QList<QFile *>outputs) { Document xlsx; QTextDocument doc; @@ -157,21 +156,16 @@ sum += colWidth[i-1]; } - double xlsx2htmlFactor = HTML_WIDTH / sum; - int col1Width = colWidth[0] * xlsx2htmlFactor; - int col2Width = colWidth[1] * xlsx2htmlFactor; - int col3Width = colWidth[2] * xlsx2htmlFactor; - /* For the merged cell wordwrap trick. */ xlsx.setColumnWidth(26, sum + 1); xlsx.setColumnHidden(26, true); int row = 1; html << "<html><meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">" - "<body><table border=\"0\" style='width:\"" << HTML_WIDTH << "px\";border-collapse:collapse'>"; - html << "<tr><th width=\"" << col1Width << "px\"</th>"; - html << "<th width=\"" << col2Width << "px\"</th>"; - html << "<th width=\"" << col3Width << "px\"</th>"; + "<body><table border=\"0\" width:\"100%\">"; + html << QStringLiteral("<tr><th width=\"%1%\"></th>").arg(HTML_COL1_PERCENT); + html << QStringLiteral("<th width=\"%1%\"></th>").arg(HTML_COL2_PERCENT); + html << QStringLiteral("<th width=\"%1%\"></th>").arg(HTML_COL3_PERCENT); const QString title = mTitle.isEmpty() ? DEFAULT_TITLE : mTitle; // Set the title of the Questionaire @@ -184,7 +178,8 @@ QRegularExpression questionEx(QUESTION_PATTERN); QRegularExpression choiceEx(CHOICE_PATTERN); - QRegularExpression freetxtEx (FREETXT_PATTERN); + QRegularExpression choiceAltEx(CHOICE_UNFILLED_PATTERN); + QRegularExpression freetxtEx(FREETXT_PATTERN); QRegularExpressionMatch match = questionEx.match(input); bool foundSomething = false; @@ -206,12 +201,13 @@ html << mQuestionStyle.arg(question.toHtmlEscaped()); if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) { - QRegularExpressionMatch choiceMatch = choiceEx.match(input, cursor); xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT); xlsx.write(row++, 1, "Answer", mAnswerChoiceFmt); html << mAnswerChoiceStyle; int firstChoiceRow = row; int lastChoiceRow = row; +repeat: + QRegularExpressionMatch choiceMatch = choiceEx.match(input, cursor); while (choiceMatch.hasMatch() && choiceMatch.capturedStart() == cursor + 1) { /* We use the cursor here to keep track of the state. Only if an answer follows immediately behind the last answer we treat it as valid as @@ -225,8 +221,16 @@ } xlsx.write(row, 1, choiceName, mChoiceTextFmt); html << mChoiceTextStyle.arg(choiceName.toHtmlEscaped()); + qDebug() << "Captured for choice: " << choiceMatch.captured(0); bool ok; - double percent = choiceMatch.captured(3).toDouble(&ok); + const QString percentStr = choiceMatch.captured("percent"); + double percent; + if (percentStr.isNull()) { + percent = 0; + ok = true; + } else { + percent = percentStr.toDouble(&ok); + } if (!ok) { mErrors << "Unparsable number in string: " + choiceMatch.captured(); } @@ -234,7 +238,8 @@ xlsx.write(row, 2, percent == 0 ? QVariant() : percent); const QString numStr = choiceMatch.captured("num"); const QString numVotesString = QString("%1% | %2 Number of votes"). - arg(choiceMatch.captured(3)).arg(choiceMatch.captured(2)); + arg(percentStr.isNull() ? QStringLiteral("0") : percentStr). + arg(numStr.isNull() ? QStringLiteral("0") : numStr); html << mChoiceVotesStyle.arg(numVotesString.toHtmlEscaped()); xlsx.write(row, 3, numVotesString, mChoiceVotesFmt); xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT); @@ -251,9 +256,6 @@ const QString choice = choiceMatch.captured(1); cursor = choiceMatch.capturedEnd(); /* Alternative answer that is just a list of strings */ - qDebug() << choiceAltEx.captureCount(); - qDebug() << choiceMatch.captured(2); - qDebug() << choiceMatch.capturedTexts(); qDebug() << "Caputured unfilled choice: " << choice; html << mChoiceTextStyle.arg(choice.toHtmlEscaped()); makeBar(html, 0, doc); @@ -356,33 +358,39 @@ mErrors << tr("Failed to parse input document."); } - if (mFmt == Format_XLSX && !xlsx.saveAs(&output)) { - mErrors << tr("Saving the XLSX document failed."); - return; - } - html << "</table></body></html>"; - - if (mFmt == Format_HTML) { - QTextStream outstream(&output); - outstream << htmlString; - return; - } + doc.setHtml(htmlString); - if (mFmt == Format_PDF) { - output.close(); - QPrinter printer(QPrinter::PrinterResolution); - printer.setOutputFormat(QPrinter::PdfFormat); - printer.setPaperSize(QPrinter::A4); - printer.setOutputFileName(output.fileName()); - doc.setHtml(htmlString); - /* - QPageLayout layout = printer.pageLayout(); - layout.setUnits(QPageLayout::Millimeter); - layout.setMargins(QMarginsF(20, 20, 20, 20)); - printer.setPageLayout(layout); - doc.setPageSize(printer.pageRect().size()); - */ - doc.print(&printer); + /* Fixup images for html */ + QRegularExpression htmlRe = QRegularExpression("<td style='vertical-align: middle'><img src=\"internal://bar(\\d+).png\"/></td>"); + htmlString.replace(htmlRe, QStringLiteral("<td style='background:linear-gradient(to right," + BAR_COLOR ", " BAR_COLOR " \\1%, #ffffff \\1%)'></td>")); + + foreach (QFile *output, outputs) { + const QString fName = output->fileName().toLower(); + if (fName.endsWith(".html")) { + QTextStream outstream(output); + outstream << htmlString; + output->close(); + } else if (fName.endsWith(".pdf")) { + output->close(); + QPrinter printer(QPrinter::PrinterResolution); + printer.setOutputFormat(QPrinter::PdfFormat); + printer.setPaperSize(QPrinter::A4); + printer.setOutputFileName(output->fileName()); + /* + QPageLayout layout = printer.pageLayout(); + layout.setUnits(QPageLayout::Millimeter); + layout.setMargins(QMarginsF(20, 20, 20, 20)); + printer.setPageLayout(layout); + doc.setPageSize(printer.pageRect().size()); + */ + doc.print(&printer); + } else { + if (!xlsx.saveAs(output)) { + mErrors << tr("Saving the XLSX document failed."); + } + output->close(); + } } }
--- a/src/converter.h Fri Apr 15 15:25:11 2016 +0200 +++ b/src/converter.h Fri Apr 15 15:34:51 2016 +0200 @@ -13,25 +13,13 @@ #include <QStringList> #include <QTextStream> #include <QFile> +#include <QList> #include "xlsxformat.h" /** @file Declaration of the Converter class. */ -/** - * @enum ConvertFormat - * @brief Possible output format values. - */ -enum ConvertFormat { - /*! XLSX (default). */ - Format_XLSX, - /*! PDF */ - Format_PDF, - /*! HTML */ - Format_HTML, -}; - /** @brief Base class of Convert operations. * * Set up an instance of this using the ctor and according setters and @@ -48,11 +36,9 @@ * is empty stdout is used. * * @param input input filename. - * @param output output filename. - * @param format the format of this. + * @param outputs the files to create. */ - Converter(const QString &input, const QString &output, - ConvertFormat fmt = Format_XLSX, + Converter(const QString &input, const QStringList &outputs, const QString &title = QString()); /** Check for errors @@ -61,11 +47,11 @@ const QStringList & errors() {return mErrors;} protected: - void convertToXSLX(QTextStream &instream, QFile &output); + void convertToXSLX(QTextStream &instream, QList<QFile*> outputs); void run(); - QString mInput, mOutput; - ConvertFormat mFmt; + QString mInput; + QStringList mOutputs; QStringList mErrors; QString mTitle;
--- a/src/l10n/main_de_DE.ts Fri Apr 15 15:25:11 2016 +0200 +++ b/src/l10n/main_de_DE.ts Fri Apr 15 15:34:51 2016 +0200 @@ -2,34 +2,41 @@ <!DOCTYPE TS> <TS version="2.0" language="de_DE"> <context> + <name></name> + <message> + <source>file</source> + <translation type="obsolete">Datei</translation> + </message> +</context> +<context> <name>Converter</name> <message> - <location filename="../converter.cpp" line="86"/> + <location filename="../converter.cpp" line="85"/> <source>Failed to open standard input and no input file provided.</source> <translation>Öffnen des Eingabekanals Fehlgeschlagen und keine Eingabedatei übergeben.</translation> </message> <message> - <location filename="../converter.cpp" line="92"/> + <location filename="../converter.cpp" line="91"/> <source>Failed to open %1 for reading.</source> <translation>Die Datei "%1" konnte nicht gelesen werden.</translation> </message> <message> - <location filename="../converter.cpp" line="101"/> + <location filename="../converter.cpp" line="102"/> <source>Failed to open standard output and no output file provided.</source> <translation>Öffnen des Ausgabekanals Fehlgeschlagen und keine Ausgabedatei übergeben.</translation> </message> <message> - <location filename="../converter.cpp" line="107"/> + <location filename="../converter.cpp" line="111"/> <source>Failed to open %1 for writing.</source> <translation>Die Datei "%1" konnte nicht geöffnet werden.</translation> </message> <message> - <location filename="../converter.cpp" line="325"/> + <location filename="../converter.cpp" line="361"/> <source>Failed to parse input document.</source> <translation>Fehler bei der verarbeitung des Eingabedokuments.</translation> </message> <message> - <location filename="../converter.cpp" line="329"/> + <location filename="../converter.cpp" line="394"/> <source>Saving the XLSX document failed.</source> <translation>Das erstellen des XLSX Dokuments ist fehlgeschlagen.</translation> </message> @@ -37,24 +44,23 @@ <context> <name>QObject</name> <message> - <location filename="../cconvert_options.h" line="26"/> + <location filename="../cconvert_options.h" line="22"/> <source>write output to file (default stdout)</source> <translation>Ausgabe in Datei schreiben (standard stdout)</translation> </message> <message> - <location filename="../cconvert_options.h" line="42"/> + <location filename="../cconvert_options.h" line="39"/> <source>[file]</source> <translation>[Datei]</translation> </message> <message> - <location filename="../cconvert_options.h" line="30"/> + <location filename="../cconvert_options.h" line="27"/> <source>Set the title of the document.</source> <translation>Titel des Dokuments.</translation> </message> <message> - <location filename="../cconvert_options.h" line="22"/> <source>Output format (default xlsx).</source> - <translation>Ausgabeformat (standard xlsx)</translation> + <translation type="vanished">Ausgabeformat (standard xlsx)</translation> </message> <message> <location filename="../cconvert_options.h" line="23"/> @@ -69,17 +75,17 @@ <translation>Datei</translation> </message> <message> - <location filename="../cconvert_options.h" line="31"/> + <location filename="../cconvert_options.h" line="28"/> <source>"The Title"</source> <translation>"Der Titel"</translation> </message> <message> - <location filename="../cconvert_options.h" line="33"/> + <location filename="../cconvert_options.h" line="30"/> <source>Print debug output.</source> <translation>Debug ausgaben aktivieren</translation> </message> <message> - <location filename="../cconvert_options.h" line="41"/> + <location filename="../cconvert_options.h" line="38"/> <source>File to process (default stdin)</source> <translation>Eingabedatei (standard stdin)</translation> </message>
--- a/src/main.cpp Fri Apr 15 15:25:11 2016 +0200 +++ b/src/main.cpp Fri Apr 15 15:34:51 2016 +0200 @@ -129,24 +129,11 @@ parser.showHelp(1); } - ConvertFormat fmt = Format_XLSX; - /* Initialize the converter. */ - const QString format = parser.value("format").toLower(); - if (format == "xlsx" || format.isEmpty()) { - fmt = Format_XLSX; - } else if (format == "html") { - fmt = Format_HTML; - } else if (format == "pdf") { - fmt = Format_PDF; - } else { - qCritical() << "Format: " << parser.value("format") << "not supported"; - exit(1); - } QString infile; if (args.size()) { infile = args.first(); } - Converter conv(infile, parser.value("output"), fmt, + Converter conv(infile, parser.values("output"), parser.value("title")); conv.start();