# HG changeset patch # User Andre Heinecke # Date 1460365240 -7200 # Node ID 927794e3cc526af54ad15ef780f3c50e274af440 # Parent e8320104979df0581059578d99a44d7af96ec17b Add HTML output and some pdf support PDF does not look well as the CSS used for HTML is not supported. diff -r e8320104979d -r 927794e3cc52 src/CMakeLists.txt --- 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} ) diff -r e8320104979d -r 927794e3cc52 src/cconvert_options.h --- 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 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)"), diff -r e8320104979d -r 927794e3cc52 src/constants.h --- 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 diff -r e8320104979d -r 927794e3cc52 src/converter.cpp --- 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 #include #include +#include +#include #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 << "" + ""; + 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 << ""; 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 << "" + ""; if (answerLine == QStringLiteral(CHOICE_IDENTIFIER)) { QRegularExpressionMatch choiceMatch = choiceEx.match(input, cursor); xlsx.setRowHeight(row, CHOICE_ROW_HEIGHT); xlsx.write(row++, 1, "Answer", mAnswerChoiceFmt); + html << ""; 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 << ""; bool ok; double percent = choiceMatch.captured(3).toDouble(&ok); if (!ok) { mErrors << "Unparsable number in string: " + choiceMatch.captured(); } + html << QStringLiteral(""; 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 << ""; + 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 << ""; + + /* 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 << ""; + } } /* Insert Empty row. */ xlsx.setRowHeight(row++, CHOICE_ROW_HEIGHT); match = questionEx.match(input, cursor); cursor = match.capturedEnd(); + html << QStringLiteral("").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 << "
"; + html << ""; + html << ""; + html << "
"; + const QString title = mTitle.isEmpty() ? DEFAULT_TITLE : mTitle; + // Set the title of the Questionaire + xlsx.write(row++, 1, title, mTitleFmt); + html << title.toHtmlEscaped() << "
" << question.toHtmlEscaped() << "" + "
" << "Answer" << "
" << choiceName.toHtmlEscaped() << "").arg(percent); + html << "" << numVotesString.toHtmlEscaped() << "
" << "Answer" << "
"; + html << xlsx.read(i, 1).toString().toHtmlEscaped(); + 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); + } } diff -r e8320104979d -r 927794e3cc52 src/converter.h --- 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 diff -r e8320104979d -r 927794e3cc52 src/l10n/main_de_DE.ts --- 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 @@ - + Converter - + Failed to open standard input and no input file provided. Öffnen des Eingabekanals Fehlgeschlagen und keine Eingabedatei übergeben. - + Failed to open %1 for reading. Die Datei "%1" konnte nicht gelesen werden. - + Failed to open standard output and no output file provided. Öffnen des Ausgabekanals Fehlgeschlagen und keine Ausgabedatei übergeben. - + Failed to open %1 for writing. Die Datei "%1" konnte nicht geöffnet werden. - + Failed to parse input document. Fehler bei der verarbeitung des Eingabedokuments. - + Saving the XLSX document failed. Das erstellen des XLSX Dokuments ist fehlgeschlagen. @@ -37,37 +37,42 @@ QObject - + write output to file (default stdout) Ausgabe in Datei schreiben (standard stdout) - + [file] [Datei] - + Set the title of the document. Titel des Dokuments - + + Output format (default xlsx). + + + + file Datei - + "The Title" "Der Titel" - + Print debug output. Debug ausgaben aktivieren - + File to process (default stdin) Eingabedatei (standard stdin) diff -r e8320104979d -r 927794e3cc52 src/main.cpp --- 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 +#include #include #include #include @@ -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();