# HG changeset patch # User Andre Heinecke # Date 1460727291 -7200 # Node ID f6c53e896008fde83a262e075f67ce7ab163829a # Parent 7458f113314c6eb35540f8a52b0558e2b064deea# Parent 5354cbda7188eacf5128830e246de409028fbb6b Merge diff -r 7458f113314c -r f6c53e896008 README --- 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. diff -r 7458f113314c -r f6c53e896008 src/cconvert_options.h --- 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 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"), diff -r 7458f113314c -r f6c53e896008 src/constants.h --- 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 "\"(.*)\",(?\\d+)?,(?\\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 diff -r 7458f113314c -r f6c53e896008 src/converter.cpp --- 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 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("").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("").arg(barCnt++); - image.save(QStringLiteral("/tmp/foo.png")); + html << QStringLiteral("").arg((int)percent); return; } -void Converter::convertToXSLX(QTextStream& instream, QFile &output) +void Converter::convertToXSLX(QTextStream& instream, QListoutputs) { 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 << ""); + htmlString.replace(htmlRe, QStringLiteral("")); + + 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(); + } } } diff -r 7458f113314c -r f6c53e896008 src/converter.h --- 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 #include #include +#include #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 outputs); void run(); - QString mInput, mOutput; - ConvertFormat mFmt; + QString mInput; + QStringList mOutputs; QStringList mErrors; QString mTitle; diff -r 7458f113314c -r f6c53e896008 src/l10n/main_de_DE.ts --- 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 @@ + + + file + Datei + + + Converter - + Failed to open standard input and no input file provided. Öffnen des Eingabekanals Fehlgeschlagen und keine Eingabedatei übergeben. - + Failed to open %1 for reading. Die Datei "%1" konnte nicht gelesen werden. - + Failed to open standard output and no output file provided. Öffnen des Ausgabekanals Fehlgeschlagen und keine Ausgabedatei übergeben. - + Failed to open %1 for writing. Die Datei "%1" konnte nicht geöffnet werden. - + Failed to parse input document. Fehler bei der verarbeitung des Eingabedokuments. - + Saving the XLSX document failed. Das erstellen des XLSX Dokuments ist fehlgeschlagen. @@ -37,24 +44,23 @@ QObject - + write output to file (default stdout) Ausgabe in Datei schreiben (standard stdout) - + [file] [Datei] - + Set the title of the document. Titel des Dokuments. - Output format (default xlsx). - Ausgabeformat (standard xlsx) + Ausgabeformat (standard xlsx) @@ -69,17 +75,17 @@ Datei - + "The Title" "Der Titel" - + Print debug output. Debug ausgaben aktivieren - + File to process (default stdin) Eingabedatei (standard stdin) diff -r 7458f113314c -r f6c53e896008 src/main.cpp --- 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();
"; - html << ""; - html << ""; + ""; + html << QStringLiteral("").arg(HTML_COL1_PERCENT); + html << QStringLiteral("").arg(HTML_COL2_PERCENT); + html << QStringLiteral("").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 << "
"; - - 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("