diff src/converter.cpp @ 3:8b4c49c92451

Add initial implementation that handles choices
author Andre Heinecke <andre.heinecke@intevation.de>
date Tue, 22 Mar 2016 10:39:19 +0100
parents
children a10425e7ef98
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/converter.cpp	Tue Mar 22 10:39:19 2016 +0100
@@ -0,0 +1,183 @@
+/* Copyright (C) 2016 by ETH Zürich
+ * Software engineering by Intevation GmbH
+ *
+ * This file is Free Software under the GNU GPL (v>=2)
+ * and comes with ABSOLUTELY NO WARRANTY!
+ * See LICENSE.txt for details.
+ */
+
+#include "converter.h"
+#include <QDebug>
+#include <QRegularExpression>
+#include <QRegularExpressionMatch>
+
+#include "xlsxdocument.h"
+#include "xlsxconditionalformatting.h"
+
+#include "constants.h"
+
+QTXLSX_USE_NAMESPACE
+
+Converter::Converter(const QString &input, const QString &output,
+                     ConvertFormat fmt, const QString &title):
+    QThread(Q_NULLPTR),
+    mInput(input),
+    mOutput(output),
+    mFmt(fmt),
+    mTitle(title)
+{
+    mTitleFmt.setFontUnderline(Format::FontUnderlineSingle);
+    mTitleFmt.setFontSize(18);
+    mTitleFmt.setFontName("Calibri");
+    mTitleFmt.setFontBold(true);
+    mTitleFmt.setVerticalAlignment(Format::AlignTop);
+
+    mQuestionFmt.setFontSize(11);
+    mQuestionFmt.setFontName("Calibri");
+    mQuestionFmt.setFontBold(true);
+    mQuestionFmt.setTopBorderStyle(Format::BorderThin);
+    mQuestionFmt.setTextWarp(true);
+
+    mAnswerChoiceFmt.setFontSize(11);
+    mAnswerChoiceFmt.setFontName("Calibri");
+    mAnswerChoiceFmt.setHorizontalAlignment(Format::AlignRight);
+
+    mChoiceTextFmt = mAnswerChoiceFmt;
+    mChoiceTextFmt.setVerticalAlignment(Format::AlignVCenter);
+
+    mChoiceBarFmt = mChoiceTextFmt;
+    mChoiceBarFmt.setFontName("Webdings");
+    mChoiceBarFmt.setFontSize(9);
+    mChoiceBarFmt.setFontColor(QColor(0xFF, 0x99, 0x33));
+
+    mChoiceBarInactiveFmt = mChoiceBarFmt;
+    mChoiceBarInactiveFmt.setFontColor(QColor(0xD9, 0xD9, 0xD9));
+}
+
+void Converter::run()
+{
+    QFile infile;
+
+    if (mInput.isEmpty()) {
+        if (!infile.open(stdin, QIODevice::ReadOnly)) {
+            mErrors << tr("Failed to open standard input and no input file provided.");
+            return;
+        }
+    } else {
+        infile.setFileName(mInput);
+        if (!infile.open(QIODevice::ReadOnly)) {
+            mErrors << tr("Failed to open %1 for reading.").arg(mInput);
+            return;
+        }
+    }
+    QTextStream instream(&infile);
+
+    QFile outfile;
+    if (mOutput.isEmpty()) {
+        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);
+            return;
+        }
+    }
+    convertToXSLX(instream, outfile);
+}
+
+void Converter::convertToXSLX(QTextStream& instream, QFile &output)
+{
+    Document xlsx;
+
+    ConditionalFormatting bars;
+
+    bars.addDataBarRule(QColor(0xFF, 0x99, 0x33), ConditionalFormatting::VOT_Num, "0", ConditionalFormatting::VOT_Num, "100", false);
+
+    const double colWidth[] = COLUMN_WIDTHS;
+    for (int i = 1; i <= COLUMN_CNT; i++) {
+        xlsx.setColumnWidth(i, colWidth[i-1]);
+    }
+
+    int row = 1;
+    if (!mTitle.isEmpty()) {
+        // Set the title of the Questionaire
+        xlsx.write(row++, 1, mTitle, mTitleFmt);
+        xlsx.mergeCells("A1:C1");
+        xlsx.setRowHeight(1, TITLE_ROW_HEIGHT);
+    }
+
+    const QString input = instream.readAll();
+
+    QRegularExpression questionEx(QUESTION_PATTERN);
+    QRegularExpression choiceEx(CHOICE_PATTERN);
+    QRegularExpression freetxtEx (FREETXT_PATTERN);
+
+    QRegularExpressionMatch match = questionEx.match(input);
+    bool foundSomething = false;
+    int cursor = match.capturedEnd();
+    while (match.hasMatch() && cursor != -1) {
+        /* We've matched a question pattern. With the answer
+           line */
+        if (!match.lastCapturedIndex() == 2) {
+            /* Should not happen without misconfiguration. */
+            mErrors << "Internal parser error.";
+            return;
+        }
+        foundSomething = true;
+        const QString question = match.captured(1).trimmed();
+        const QString answerLine = match.captured(2).trimmed();
+        xlsx.write(row++, 1, question, mQuestionFmt);
+
+        if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) {
+            QRegularExpressionMatch choiceMatch = choiceEx.match(input, cursor);
+            xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT);
+            xlsx.write(row++, 1, tr("Answer"), mAnswerChoiceFmt);
+            int firstChoiceRow = row;
+            int lastChoiceRow = row;
+            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
+                   otherwise we can't figure out when the next question begins. */
+                cursor = choiceMatch.capturedEnd();
+
+                /* Write the values */
+                xlsx.write(row, 1, choiceMatch.captured(1), mChoiceTextFmt);
+                bool ok;
+                double percent = choiceMatch.captured(3).toDouble(&ok);
+                if (!ok) {
+                    mErrors << "Unparsable number in string: " + choiceMatch.captured();
+                }
+                xlsx.write(row, 2, percent);
+                xlsx.write(row, 3, tr("%1% | %2 Number of votes").
+                           arg(choiceMatch.captured(3)).arg(choiceMatch.captured(2)),
+                           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 */
+                choiceMatch = choiceEx.match(input, cursor);
+                row++;
+                lastChoiceRow++;
+            }
+            bars.addRange(QString("B%1:B%2").arg(firstChoiceRow).arg(lastChoiceRow));
+        } else if (answerLine == QStringLiteral(TEXT_IDENTIFIER)) {
+            
+        }
+        /* Insert Empty row. */
+        xlsx.setRowHeight(row++, CHOICE_ROW_HEIGHT);
+        match = questionEx.match(input, cursor);
+        cursor = match.capturedEnd();
+    }
+    xlsx.addConditionalFormatting(bars);
+
+    if (!foundSomething) {
+        mErrors << tr("Failed to parse input document.");
+    }
+
+    if (!xlsx.saveAs(&output)) {
+        mErrors << tr("Saving the XLSX document failed.");
+        return;
+    }
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)