diff src/converter.cpp @ 23:927794e3cc52

Add HTML output and some pdf support PDF does not look well as the CSS used for HTML is not supported.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 11 Apr 2016 11:00:40 +0200
parents 0b66b10a287d
children e5c5ebfa4205
line wrap: on
line diff
--- a/src/converter.cpp	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/converter.cpp	Mon Apr 11 11:00:40 2016 +0200
@@ -10,6 +10,8 @@
 #include <QDebug>
 #include <QRegularExpression>
 #include <QRegularExpressionMatch>
+#include <QTextDocument>
+#include <QPrinter>
 
 #include "xlsxdocument.h"
 #include "xlsxconditionalformatting.h"
@@ -32,31 +34,38 @@
     mTitleFmt.setFontBold(true);
     mTitleFmt.setVerticalAlignment(Format::AlignTop);
 
+    mTitleStyle = QStringLiteral("style='vertical-align: top;font-weight: bold;font-size:18; text-decoration: underline;'");
+
     mQuestionFmt.setFontSize(11);
     mQuestionFmt.setFontName("Calibri");
     mQuestionFmt.setFontBold(true);
     mQuestionFmt.setTopBorderStyle(Format::BorderThin);
     mQuestionFmt.setBottomBorderStyle(Format::BorderThin);
     mQuestionFmt.setTextWarp(true);
+    mQuestionStyle = QStringLiteral("style='border-bottom: 1pt solid black;border-top: 1pt solid black;font-weight: bold;font-size:11;'");
 
     mAnswerChoiceFmt.setFontSize(11);
     mAnswerChoiceFmt.setFontName("Calibri");
-    mAnswerChoiceFmt.setHorizontalAlignment(Format::AlignRight);
+    mAnswerChoiceFmt.setHorizontalAlignment(Format::AlignLeft);
     mAnswerChoiceFmt.setTextWarp(true);
+    mAnswerChoiceStyle= QStringLiteral("style='text-align: left;font-size:11;'");
 
     mChoiceTextFmt = mAnswerChoiceFmt;
     mChoiceTextFmt.setVerticalAlignment(Format::AlignVCenter);
+    mChoiceTextStyle= QStringLiteral("style='text-align: right;vertical-algin: center; font-size:11;'");
 
     mChoiceVotesFmt = mChoiceTextFmt;
     mChoiceVotesFmt.setFontSize(10);
-    mAnswerChoiceFmt.setHorizontalAlignment(Format::AlignLeft);
+    mChoiceVotesStyle = QStringLiteral("style='text-align: left;vertical-algin: center; font-size:10;'");
 
     mFreeTextFmt = mQuestionFmt;
     mFreeTextFmt.setFontBold(false);
+    mFreeTextStyle = QStringLiteral("style='border-bottom: 1pt solid black;border-top: 1pt solid black;font-size:11;'");
 
     mAnswerTextFmt = mQuestionFmt;
     mAnswerTextFmt.setVerticalAlignment(Format::AlignVCenter);
     mAnswerTextFmt.setHorizontalAlignment(Format::AlignLeft);
+    mAnswerTextStyle = QStringLiteral("style='text-align: left;font-weight: bold;vertical-algin: center; border-bottom: 1pt solid black;border-top: 1pt solid black;font-size:11;'");
 }
 
 void Converter::run()
@@ -96,6 +105,9 @@
 void Converter::convertToXSLX(QTextStream& instream, QFile &output)
 {
     Document xlsx;
+    QTextDocument doc;
+    QString htmlString;
+    QTextStream html (&htmlString);
 
     ConditionalFormatting bars;
 
@@ -104,22 +116,33 @@
 
     const double colWidth[] = COLUMN_WIDTHS;
     double sum = 0;
+
     for (int i = 1; i <= COLUMN_CNT; i++) {
         xlsx.setColumnWidth(i, colWidth[i-1]);
         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);
 
+    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'>";
+
     int row = 1;
-    if (!mTitle.isEmpty()) {
-        // Set the title of the Questionaire
-        xlsx.write(row++, 1, mTitle, mTitleFmt);
-    } else {
-        xlsx.write(row++, 1, DEFAULT_TITLE, mTitleFmt);
-    }
+    html << "<tr><th width=\"" << col1Width << "\"</th>";
+    html << "<th width=\"" << col2Width << "\"</th>";
+    html << "<th width=\"" << col3Width << "\"</th>";
+    html << "<tr><td colspan='3' " << mTitleStyle << "/>";
+    const QString title = mTitle.isEmpty() ? DEFAULT_TITLE : mTitle;
+    // Set the title of the Questionaire
+    xlsx.write(row++, 1, title, mTitleFmt);
+    html << title.toHtmlEscaped() << "</td></tr>";
     xlsx.mergeCells("A1:C1");
     xlsx.setRowHeight(1, TITLE_ROW_HEIGHT);
 
@@ -146,11 +169,15 @@
         xlsx.write(row, 2, QString(" "), mQuestionFmt);
         xlsx.write(row, 3, QString(" "), mQuestionFmt);
         xlsx.write(row++, 1, question, mQuestionFmt);
+        html << "<tr><td " << mQuestionStyle << ">" << question.toHtmlEscaped() << "</td>"
+            "<td " << mQuestionStyle << "/>"
+            "<td " << mQuestionStyle << "/></tr>";
 
         if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) {
             QRegularExpressionMatch choiceMatch = choiceEx.match(input, cursor);
             xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
             xlsx.write(row++, 1, "Answer", mAnswerChoiceFmt);
+            html << "<tr><td " << mAnswerChoiceStyle << ">" << "Answer" << "</td><td/><td/></tr>";
             int firstChoiceRow = row;
             int lastChoiceRow = row;
             while (choiceMatch.hasMatch() && choiceMatch.capturedStart() == cursor + 1) {
@@ -165,15 +192,20 @@
                     choiceName = " " + choiceName;
                 }
                 xlsx.write(row, 1, choiceName, mChoiceTextFmt);
+                html << "<tr><td " << mChoiceTextStyle << ">" << choiceName.toHtmlEscaped() << "</td>";
                 bool ok;
                 double percent = choiceMatch.captured(3).toDouble(&ok);
                 if (!ok) {
                     mErrors << "Unparsable number in string: " + choiceMatch.captured();
                 }
+                html << QStringLiteral("<td style='background:linear-gradient(to right,"
+                        "#ff9933, #ff9933 %1%, #ffffff %1%)'>").arg(percent);
+                html << "</td>";
                 xlsx.write(row, 2, percent);
-                xlsx.write(row, 3, QString("%1% | %2 Number of votes").
-                           arg(choiceMatch.captured(3)).arg(choiceMatch.captured(2)),
-                           mChoiceVotesFmt);
+                const QString numVotesString = QString("%1% | %2 Number of votes").
+                           arg(choiceMatch.captured(3)).arg(choiceMatch.captured(2));
+                html << "<td " << mChoiceVotesStyle << ">" << numVotesString.toHtmlEscaped() << "</td></tr>";
+                xlsx.write(row, 3, numVotesString, mChoiceVotesFmt);
                 xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
                 /* As long as we can match a choice which is either before the next question
                    or before the end of the document */
@@ -187,6 +219,11 @@
             QRegularExpressionMatch textMatch = freetxtEx.match(input, cursor);
             xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
             xlsx.write(row++, 1, "Answer", mAnswerTextFmt);
+            html << "<tr><td " << mAnswerTextStyle << ">" << "Answer" << "</td><td/><td/></tr>";
+
+            /* To handle the workaround for quotes in answers we store
+             * the number of rows and only afterwards create the html rows. */
+            int firstFreeRow = row;
             while (textMatch.hasMatch()) {
                 if (textMatch.capturedStart() != cursor + 1) {
                     /* The format allows unescaped quotes in the text.
@@ -239,13 +276,20 @@
                 xlsx.write(QString("Z%1").arg(row), text, mFreeTextFmt);
                 xlsx.write(row, 1, text, mFreeTextFmt);
                 row++;
+
                 textMatch = freetxtEx.match(input, cursor);
             }
+            for (int i = firstFreeRow; i < row; i++) {
+                html << "<tr><td colspan='3' " << mFreeTextStyle << ">";
+                html << xlsx.read(i, 1).toString().toHtmlEscaped();
+                html << "</td></tr>";
+            }
         }
         /* Insert Empty row. */
         xlsx.setRowHeight(row++, CHOICE_ROW_HEIGHT);
         match = questionEx.match(input, cursor);
         cursor = match.capturedEnd();
+        html << QStringLiteral("<tr style='height: %1px'/>").arg(CHOICE_ROW_HEIGHT);
     }
     xlsx.addConditionalFormatting(bars);
 
@@ -253,8 +297,26 @@
         mErrors << tr("Failed to parse input document.");
     }
 
-    if (!xlsx.saveAs(&output)) {
+    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;
+    }
+
+    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);
+        doc.print(&printer);
+    }
 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)