diff src/converter.cpp @ 38:5354cbda7188

Fix HTML Layout. Support multiple formats at once. More handling. This commit is a bad mix of multiple changes. It addresses: - HTML Width is now relative and should fix some pdf creation problems. - Format is now taken from the extension of the file names provided. - Multiple file names are accepted at once. - Parser now handles missing values in Multiple choice answers - Parser now handles unfilled multiple choice values
author Andre Heinecke <andre.heinecke@intevation.de>
date Fri, 15 Apr 2016 15:19:04 +0200
parents ca66763b6524
children f6c53e896008
line wrap: on
line diff
--- a/src/converter.cpp	Fri Apr 15 15:15:44 2016 +0200
+++ b/src/converter.cpp	Fri Apr 15 15:19:04 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,15 +221,25 @@
                 }
                 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();
                 }
-                makeBar(html, percent, col2Width, doc, mFmt == Format_PDF);
+                makeBar(html, percent, doc);
                 xlsx.write(row, 2, 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);
@@ -243,6 +249,36 @@
                 row++;
                 lastChoiceRow++;
             }
+            choiceMatch = choiceAltEx.match(input, cursor);
+            bool additionalFound = false;
+            while (choiceMatch.hasMatch() && choiceMatch.capturedStart() <= cursor + 1) {
+                additionalFound = true;
+                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);
+                xlsx.write(row, 2, 0);
+                const QString numVotesString = QStringLiteral("Keine eingegangenen Antworten");
+                html << mChoiceVotesStyle.arg(numVotesString.toHtmlEscaped());
+                xlsx.write(row, 3, numVotesString, mChoiceVotesFmt);
+                xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
+                row++;
+                lastChoiceRow++;
+                choiceMatch = choiceAltEx.match(input, cursor);
+                QRegularExpressionMatch realMatch = choiceEx.match(input, cursor);
+                if (choiceMatch.hasMatch() && choiceMatch.capturedStart() == realMatch.capturedStart()) {
+                    /* We have a real match so back to the other pattern. */
+                    break;
+                }
+            }
+            if (additionalFound) {
+                goto repeat;
+            }
             bars.addRange(QString("B%1:B%2").arg(firstChoiceRow).arg(lastChoiceRow));
 //            xlsx.groupRows(firstChoiceRow - 2, lastChoiceRow - 1, false);
         } else if (answerLine == QStringLiteral(TEXT_IDENTIFIER)) {
@@ -325,33 +361,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();
+        }
     }
 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)