changeset 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 e8320104979d
children 1470cb8a00a8
files src/CMakeLists.txt src/cconvert_options.h src/constants.h src/converter.cpp src/converter.h src/l10n/main_de_DE.ts src/main.cpp
diffstat 7 files changed, 130 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/CMakeLists.txt	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/CMakeLists.txt	Mon Apr 11 11:00:40 2016 +0200
@@ -57,8 +57,8 @@
 endif()
 
 target_link_libraries(${PROJECT_NAME}
-    Qt5::Core
-    Qt5::Gui
+    Qt5::Widgets
+    Qt5::PrintSupport
     ${PROJECT_NAME}_libqtxslx
     ${EXTRA_STATIC_LIBS}
 )
--- a/src/cconvert_options.h	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/cconvert_options.h	Mon Apr 11 11:00:40 2016 +0200
@@ -17,9 +17,10 @@
 {
     QList<QCommandLineOption> options;
 
-    options /*<< QCommandLineOption(QStringList() << QStringLiteral("pdf")
-                                  << QStringLiteral("p"),
-                                  QObject::tr("Output as pdf (default xlsx)")) */
+    options << QCommandLineOption(QStringList() << QStringLiteral("format")
+                                  << QStringLiteral("f"),
+                                  QObject::tr("Output format (default xlsx)."),
+                                  QStringLiteral("xlsx pdf html"))
             << QCommandLineOption(QStringList() << QStringLiteral("output")
                                   << QStringLiteral("o"),
                                   QObject::tr("write output to file (default stdout)"),
--- a/src/constants.h	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/constants.h	Mon Apr 11 11:00:40 2016 +0200
@@ -47,7 +47,7 @@
 #define COLUMN_CNT 3
 /**
  * @brief The width of the columns in characters. */
-#define COLUMN_WIDTHS { 40, 22, 27 }
+#define COLUMN_WIDTHS { 40, 20, 26 }
 
 /**
  * @brief Regular expression to define a question.
@@ -79,4 +79,6 @@
 
 #define DEFAULT_TITLE QStringLiteral("Clicker-Fragen und Antworten")
 
+#define HTML_WIDTH 960
+
 #endif // CONSTANTS_H
--- 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);
+    }
 }
--- a/src/converter.h	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/converter.h	Mon Apr 11 11:00:40 2016 +0200
@@ -27,7 +27,9 @@
     /*! XLSX (default). */
     Format_XLSX,
     /*! PDF */
-    Format_PDF
+    Format_PDF,
+    /*! HTML */
+    Format_HTML,
 };
 
 /** @brief Base class of Convert operations.
@@ -74,6 +76,13 @@
                   mFreeTextFmt,
                   mChoiceTextFmt,
                   mChoiceVotesFmt;
+    QString mTitleStyle,
+            mQuestionStyle,
+            mAnswerChoiceStyle,
+            mAnswerTextStyle,
+            mFreeTextStyle,
+            mChoiceTextStyle,
+            mChoiceVotesStyle;
 };
 
 #endif // CONVERTER_H
--- a/src/l10n/main_de_DE.ts	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/l10n/main_de_DE.ts	Mon Apr 11 11:00:40 2016 +0200
@@ -1,35 +1,35 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE TS>
-<TS version="2.0" language="de_DE">
+<TS version="2.1" language="de_DE">
 <context>
     <name>Converter</name>
     <message>
-        <location filename="../converter.cpp" line="68"/>
+        <location filename="../converter.cpp" line="78"/>
         <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="74"/>
+        <location filename="../converter.cpp" line="84"/>
         <source>Failed to open %1 for reading.</source>
         <translation>Die Datei &quot;%1&quot; konnte nicht gelesen werden.</translation>
     </message>
     <message>
-        <location filename="../converter.cpp" line="83"/>
+        <location filename="../converter.cpp" line="93"/>
         <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="89"/>
+        <location filename="../converter.cpp" line="99"/>
         <source>Failed to open %1 for writing.</source>
         <translation>Die Datei &quot;%1&quot; konnte nicht geöffnet werden.</translation>
     </message>
     <message>
-        <location filename="../converter.cpp" line="253"/>
+        <location filename="../converter.cpp" line="298"/>
         <source>Failed to parse input document.</source>
         <translation>Fehler bei der verarbeitung des Eingabedokuments.</translation>
     </message>
     <message>
-        <location filename="../converter.cpp" line="257"/>
+        <location filename="../converter.cpp" line="302"/>
         <source>Saving the XLSX document failed.</source>
         <translation>Das erstellen des XLSX Dokuments ist fehlgeschlagen.</translation>
     </message>
@@ -37,37 +37,42 @@
 <context>
     <name>QObject</name>
     <message>
-        <location filename="../cconvert_options.h" line="25"/>
+        <location filename="../cconvert_options.h" line="26"/>
         <source>write output to file (default stdout)</source>
         <translation>Ausgabe in Datei schreiben (standard stdout)</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="41"/>
+        <location filename="../cconvert_options.h" line="42"/>
         <source>[file]</source>
         <translation>[Datei]</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="29"/>
+        <location filename="../cconvert_options.h" line="30"/>
         <source>Set the title of the document.</source>
         <translation>Titel des Dokuments</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="26"/>
+        <location filename="../cconvert_options.h" line="22"/>
+        <source>Output format (default xlsx).</source>
+        <translation type="unfinished"></translation>
+    </message>
+    <message>
+        <location filename="../cconvert_options.h" line="27"/>
         <source>file</source>
         <translation>Datei</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="30"/>
+        <location filename="../cconvert_options.h" line="31"/>
         <source>&quot;The Title&quot;</source>
         <translation>&quot;Der Titel&quot;</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="32"/>
+        <location filename="../cconvert_options.h" line="33"/>
         <source>Print debug output.</source>
         <translation>Debug ausgaben aktivieren</translation>
     </message>
     <message>
-        <location filename="../cconvert_options.h" line="40"/>
+        <location filename="../cconvert_options.h" line="41"/>
         <source>File to process (default stdin)</source>
         <translation>Eingabedatei (standard stdin)</translation>
     </message>
--- a/src/main.cpp	Mon Apr 11 10:59:08 2016 +0200
+++ b/src/main.cpp	Mon Apr 11 11:00:40 2016 +0200
@@ -9,7 +9,7 @@
 /** @file Main entry point for the application.
  *
  * This file is the wrapper around the qt application.
- * Does command line parsing and preparation of the QCoreApplication.
+ * Does command line parsing and preparation of the QApplication.
  */
 #include "constants.h"
 
@@ -17,7 +17,7 @@
 #include "converter.h"
 #include "cconvert_options.h"
 
-#include <QCoreApplication>
+#include <QApplication>
 #include <QCommandLineParser>
 #include <QtPlugin>
 #include <QDebug>
@@ -97,11 +97,11 @@
  * @returns 0 on success an error code otherwise. */
 int realMain(int argc, char **argv)
 {
-    /* QCoreApplication setup */
-    QCoreApplication app (argc, argv);
-    QCoreApplication::setOrganizationName(QStringLiteral(APPNAME));
-    QCoreApplication::setApplicationName(QStringLiteral(APPNAME));
-    QCoreApplication::setApplicationVersion(QStringLiteral(VERSION));
+    /* QApplication setup */
+    QApplication app (argc, argv);
+    QApplication::setOrganizationName(QStringLiteral(APPNAME));
+    QApplication::setApplicationName(QStringLiteral(APPNAME));
+    QApplication::setApplicationVersion(QStringLiteral(VERSION));
 //    QSettings::setDefaultFormat(QSettings::IniFormat);
 
     /* Setup translations */
@@ -130,10 +130,18 @@
     }
 
     ConvertFormat fmt = Format_XLSX;
-    /* Initialize the converter.
-    if (parser.isSet(QStringLiteral("pdf"))) {
+    /* 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();
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)