Mercurial > clickerconvert
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(); + } } }