diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 6c4f314..063ff65 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -78,6 +78,7 @@ target_link_libraries(${PROJECT_NAME} CheckableItem CheckableTest CheckableTestModel + PrintableModel MetaData VerbEnd Plural @@ -95,6 +96,7 @@ add_subdirectory(Age) add_subdirectory(CheckableItem) add_subdirectory(CheckableTest) add_subdirectory(CheckableTestModel) +add_subdirectory(PrintableModel) add_subdirectory(MetaData) add_subdirectory(SubTests) diff --git a/source/CheckableItem/CheckableItem.cpp b/source/CheckableItem/CheckableItem.cpp index 6d6a16a..faed665 100644 --- a/source/CheckableItem/CheckableItem.cpp +++ b/source/CheckableItem/CheckableItem.cpp @@ -34,24 +34,3 @@ unsigned int CheckableItem::points() const { return m_checked ? m_value : 0; } - -void CheckableItem::write(QJsonObject &json) const -{ - json["text"] = m_text.c_str(); - json["checked"] = m_checked; -} - -void CheckableItem::read(const QJsonObject &json) -{ - const auto &text = json["text"]; - if (text.isString()) - { - m_text = text.toString().toStdString(); - } - - const auto &checked = json["checked"]; - if (checked.isBool()) - { - m_checked = checked.toBool(); - } -} diff --git a/source/CheckableItem/CheckableItem.h b/source/CheckableItem/CheckableItem.h index a37086e..89feffe 100644 --- a/source/CheckableItem/CheckableItem.h +++ b/source/CheckableItem/CheckableItem.h @@ -24,7 +24,4 @@ public: void setValue(unsigned int value); unsigned int points() const; - - void write(QJsonObject &json) const; - void read(const QJsonObject &json); }; diff --git a/source/CheckableItem/CheckableItems.cpp b/source/CheckableItem/CheckableItems.cpp index 30532f3..f9b59f3 100644 --- a/source/CheckableItem/CheckableItems.cpp +++ b/source/CheckableItem/CheckableItems.cpp @@ -2,6 +2,8 @@ #include +#include + CheckableItems::CheckableItems(std::initializer_list itemNames) { for (const auto &itemName : itemNames) @@ -10,27 +12,9 @@ CheckableItems::CheckableItems(std::initializer_list itemNames) } } -void CheckableItems::write(QJsonArray &json) const +unsigned int CheckableItems::getPoints() const { - for (const auto &item : *this) - { - QJsonObject itemObject; - item.write(itemObject); - json.append(itemObject); - } -} - -void CheckableItems::read(const QJsonArray &json) -{ - clear(); - - for (const auto &itemObject : json) - { - if (itemObject.isObject()) - { - CheckableItem item; - item.read(itemObject.toObject()); - emplace_back(item); - } - } + return std::accumulate(begin(), end(), 0, [](int base, const CheckableItem &item) { + return base + item.points(); + }); } diff --git a/source/CheckableItem/CheckableItems.h b/source/CheckableItem/CheckableItems.h index 164f829..b147e27 100644 --- a/source/CheckableItem/CheckableItems.h +++ b/source/CheckableItem/CheckableItems.h @@ -10,6 +10,5 @@ class CheckableItems : public std::vector public: CheckableItems(std::initializer_list itemNames); - void write(QJsonArray &json) const; - void read(const QJsonArray &json); + unsigned int getPoints() const; }; diff --git a/source/CheckableTest/CheckableTest.cpp b/source/CheckableTest/CheckableTest.cpp index 0d0cbf5..fabf0c3 100644 --- a/source/CheckableTest/CheckableTest.cpp +++ b/source/CheckableTest/CheckableTest.cpp @@ -1,5 +1,7 @@ #include "CheckableTest.h" +#include + CheckableTest::CheckableTest( const char *name, std::initializer_list items) : m_name(name) @@ -26,3 +28,8 @@ CheckableItems &CheckableTest::items() { return m_items; } + +unsigned int CheckableTest::getPoints() const +{ + return m_items.getPoints(); +} diff --git a/source/CheckableTest/CheckableTest.h b/source/CheckableTest/CheckableTest.h index 32f6da0..f4a0c20 100644 --- a/source/CheckableTest/CheckableTest.h +++ b/source/CheckableTest/CheckableTest.h @@ -17,6 +17,8 @@ public: const QString &name() const; const CheckableItems &items() const; CheckableItems &items(); + + unsigned int getPoints() const; }; using CheckableTests = std::vector; diff --git a/source/CheckableTestModel/CMakeLists.txt b/source/CheckableTestModel/CMakeLists.txt index 2ce7c3b..c7426fc 100644 --- a/source/CheckableTestModel/CMakeLists.txt +++ b/source/CheckableTestModel/CMakeLists.txt @@ -18,8 +18,9 @@ target_include_directories(${PROJECT_NAME} ) target_link_libraries(${PROJECT_NAME} - PRIVATE + PUBLIC CheckableItem CheckableTest + PRIVATE Qt5::Core ) diff --git a/source/CheckableTestModel/CheckableTestModel.cpp b/source/CheckableTestModel/CheckableTestModel.cpp index 9c46e03..685ea1a 100644 --- a/source/CheckableTestModel/CheckableTestModel.cpp +++ b/source/CheckableTestModel/CheckableTestModel.cpp @@ -121,30 +121,6 @@ QVariant CheckableTestModel::headerData(int section, Qt::Orientation orientation return QAbstractTableModel::headerData(section, orientation, role); } -void CheckableTestModel::write(QJsonObject &json) const -{ - for (const auto &test : m_tests) - { - QJsonArray testData; - test.items().write(testData); - json[test.name()] = testData; - } -} - -void CheckableTestModel::read(const QJsonObject &json) -{ - for (auto &test : m_tests) - { - auto testData = json[test.name()]; - if (testData.isArray()) - { - test.items().read(testData.toArray()); - } - } - - emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); -} - bool CheckableTestModel::isValidIndex(const QModelIndex &index) const { if (index.row() < m_tests.size()) @@ -211,3 +187,8 @@ unsigned int CheckableTestModel::getPoints() const return points; } + +QString CheckableTestModel::getTitle() const +{ + return m_title; +} diff --git a/source/CheckableTestModel/CheckableTestModel.h b/source/CheckableTestModel/CheckableTestModel.h index 7b4ed9d..2201cec 100644 --- a/source/CheckableTestModel/CheckableTestModel.h +++ b/source/CheckableTestModel/CheckableTestModel.h @@ -8,6 +8,7 @@ class CheckableTestModel : public QAbstractTableModel Q_OBJECT protected: + QString m_title; CheckableTests m_tests; public: @@ -16,20 +17,17 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data( - const QModelIndex &index, int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; Qt::ItemFlags flags(const QModelIndex &index) const override; - bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole) override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const override; - - void write(QJsonObject &json) const; - void read(const QJsonObject &json); + int role = Qt::DisplayRole) const override; unsigned int getPoints() const; + QString getTitle() const; + protected: virtual bool isValidIndex(const QModelIndex &index) const; diff --git a/source/DataModel.cpp b/source/DataModel.cpp index ab61bed..0b7332b 100644 --- a/source/DataModel.cpp +++ b/source/DataModel.cpp @@ -100,27 +100,43 @@ void DataModel::read(const QString &filename) m_passiv.read(dataModel.lateskillspassiv()); } -std::string DataModel::toHtml() const +void DataModel::printTo(QPrinter &printer) const { - std::stringstream out; + QPainter painter; + painter.begin(&printer); - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "

ESGRAF 4-8 Auswertungsbogen

" << std::endl; - out << "

" << std::endl; - out << m_metaData.toHtml(); - out << "

" << std::endl; - out << "" << std::endl; - out << "" << std::endl; + painter.setFont(PrintableModel::h1Font()); + painter.drawText(0, painter.fontMetrics().lineSpacing(), "ESGRAF 4-8 Auswertungsbogen"); + painter.translate(0, 3 * painter.fontMetrics().lineSpacing()); - return out.str(); + m_metaData.printTo(painter); + + m_wfModel.printTo(painter); + m_otModel.printTo(painter); + m_tPrModel.printTo(painter); + m_tPeModel.printTo(painter); + V2SvkModel::printSummary(painter, + m_wfModel.getV2Points() + m_otModel.getV2Points() + + m_tPrModel.getV2Points() + m_tPeModel.getV2Points(), + m_wfModel.getSvkPoints() + m_otModel.getSvkPoints() + + m_tPrModel.getSvkPoints() + m_tPeModel.getSvkPoints()); + + m_verbEnd.printTo(painter); + m_genus.printTo(painter); + + printer.newPage(); + painter.resetTransform(); + + m_akkusativ.printTo(painter); + m_dativ.printTo(painter); + m_plural.printTo(painter); + + m_passiv.printTo(painter); + m_genitiv.printTo(painter); + + m_results.printTo(painter); + + painter.end(); } void DataModel::pluralModelChanged() diff --git a/source/DataModel.h b/source/DataModel.h index 307a93b..aa0fbf3 100644 --- a/source/DataModel.h +++ b/source/DataModel.h @@ -1,5 +1,7 @@ #pragma once +#include "PrintableModel.h" + #include "MetaData/MetaDataModel.h" #include "GenusModel.h" #include "VerbEndModel.h" @@ -17,7 +19,7 @@ #include "ResultModel.h" -#include +#include class DataModel : public QObject { @@ -44,35 +46,14 @@ public: public: DataModel(QObject *parent); - std::string toHtml() const; - void write(const QString &filename) const; void read(const QString &filename); + void printTo(QPrinter &printer) const; + signals: void modelChanged(); -private: - template - void write( - const ModelType &model, QJsonObject &target, const char *name) const - { - QJsonObject jsonObject; - model.write(jsonObject); - target[name] = jsonObject; - } - - template - void read( - ModelType &model, const QJsonObject &source, const char *name) const - { - const auto &jsonObject = source[name]; - if (jsonObject.isObject()) - { - model.read(jsonObject.toObject()); - } - } - private slots: void pluralModelChanged(); void metaDataChanged(); diff --git a/source/MetaData/CMakeLists.txt b/source/MetaData/CMakeLists.txt index e00d8de..ab2b0f0 100644 --- a/source/MetaData/CMakeLists.txt +++ b/source/MetaData/CMakeLists.txt @@ -42,6 +42,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE Age + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/MetaData/MetaDataModel.cpp b/source/MetaData/MetaDataModel.cpp index f2911e8..2342b17 100644 --- a/source/MetaData/MetaDataModel.cpp +++ b/source/MetaData/MetaDataModel.cpp @@ -5,7 +5,7 @@ #include MetaDataModel::MetaDataModel(QObject *parent) - : QAbstractTableModel(parent) + : PrintableModel(parent) { m_dateOfBirth = QDate::currentDate().addYears(-9); m_dateOfTest = QDate::currentDate(); @@ -130,41 +130,41 @@ void MetaDataModel::write(ESGRAF48::MetaDataModel &model) const model.set_remarks(m_remarks.toStdString()); } -std::string MetaDataModel::toHtml() const +void MetaDataModel::printTo(QPainter &painter) const { - std::ostringstream out; + painter.setFont(tableFont()); - out << "" - << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" - << std::endl; - out << "" << std::endl; - out << "" - << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" - << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" - << std::endl; - out << "" - << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "" << std::endl; - out << "
Name, Vorname" << m_participant.toHtmlEscaped().toStdString() << "Untersucher(in)" << m_instructor.toHtmlEscaped().toStdString() << "
Geburtsdatum" << m_dateOfBirth.toString("dd.MM.yyyy").toHtmlEscaped().toStdString() << "Bemerkungen
Untersuchungsdatum" << m_dateOfTest.toString("dd.MM.yyyy").toHtmlEscaped().toStdString() << "" - << m_remarks.trimmed().toHtmlEscaped().replace("\n", "
").toStdString() << "
Alter am Testtag" << getAge().toString() << "
" << std::endl; + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); - return out.str(); + auto hasRemarks = !m_remarks.trimmed().isEmpty(); + + painter.drawText(0, 0, "Name, Vorname"); + painter.drawText(0.25 * width, 0, m_participant); + painter.drawText(0.5 * width, 0, "Untersucher(in)"); + painter.drawText(0.75 * width, 0, m_instructor); + + painter.translate(0, height); + + painter.drawText(0, 0, "Geburtsdatum"); + painter.drawText(0.25 * width, 0, m_dateOfBirth.toString("dd.MM.yyyy")); + if (hasRemarks) + { + painter.drawText(0.5 * width, 0, "Bemerkungen:"); + painter.drawText(QRect(0.5 * width, 0.5 * height, width, 2 * height), m_remarks); + } + + painter.translate(0, height); + + painter.drawText(0, 0, "Untersuchungsdatum"); + painter.drawText(0.25 * width, 0, m_dateOfTest.toString("dd.MM.yyyy")); + + painter.translate(0, height); + + painter.drawText(0, 0, "Alter am Testtag"); + painter.drawText(0.25 * width, 0, getAge().toString().c_str()); + + painter.translate(0, 2 * height); } Age MetaDataModel::getAge() const diff --git a/source/MetaData/MetaDataModel.h b/source/MetaData/MetaDataModel.h index 72811e6..4ab5f4b 100644 --- a/source/MetaData/MetaDataModel.h +++ b/source/MetaData/MetaDataModel.h @@ -1,5 +1,7 @@ #pragma once +#include "PrintableModel.h" + #include "Age.h" #include "MetaDataModel.pb.h" @@ -7,9 +9,8 @@ #include #include #include -#include -class MetaDataModel : public QAbstractTableModel +class MetaDataModel : public PrintableModel { Q_OBJECT @@ -31,7 +32,7 @@ public: void read(const ESGRAF48::MetaDataModel &model); void write(ESGRAF48::MetaDataModel &model) const; - std::string toHtml() const; + void printTo(QPainter &painter) const override; Age getAge() const; }; diff --git a/source/PrintableModel/CMakeLists.txt b/source/PrintableModel/CMakeLists.txt new file mode 100644 index 0000000..842b0f2 --- /dev/null +++ b/source/PrintableModel/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.6) + +project(PrintableModel LANGUAGES CXX) + +find_package(Qt5Core REQUIRED) +find_package(Qt5Widgets REQUIRED) + +add_library(${PROJECT_NAME} + PrintableModel.cpp +) + +set_target_properties(${PROJECT_NAME} + PROPERTIES CXX_STANDARD 14 +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(${PROJECT_NAME} + PUBLIC + CheckableTestModel + PRIVATE + Qt5::Core + Qt5::Widgets +) diff --git a/source/PrintableModel/PrintableModel.cpp b/source/PrintableModel/PrintableModel.cpp new file mode 100644 index 0000000..2423ba0 --- /dev/null +++ b/source/PrintableModel/PrintableModel.cpp @@ -0,0 +1,184 @@ +#include "PrintableModel.h" + +#include + +PrintableModel::PrintableModel(QObject *parent) + : CheckableTestModel(parent) +{ +} + +void PrintableModel::printTo(QPainter &painter) const +{ + printHeader(painter); + printTests(painter); + printSummary(painter); +} + +QFont PrintableModel::h1Font() +{ + return QFont("Helvetica", 16); +} + +QFont PrintableModel::h2Font() +{ + return QFont("Helvetica", 10); +} + +QFont PrintableModel::tableFont() +{ + return QFont("Helvetica", 8); +} + +QPen PrintableModel::tablePen() +{ + return QPen(Qt::black, 1, Qt::SolidLine); +} + +QPen PrintableModel::resultPen() +{ + return QPen(Qt::black, 2, Qt::SolidLine); +} + +double PrintableModel::headerWidthFactor() +{ + return 0.17; +} + +double PrintableModel::cellWidthFactor() +{ + return headerWidthFactor() / 2; +} + +void PrintableModel::drawTextSquare(QPainter &painter, const QRectF &cell, const QString &text) +{ + auto prevPen = painter.pen(); + painter.setPen(tablePen()); + + painter.drawText(cell, Qt::AlignCenter, text); + + painter.drawLine(cell.topLeft(), cell.topRight()); + painter.drawLine(cell.topRight(), cell.bottomRight()); + painter.drawLine(cell.bottomRight(), cell.bottomLeft()); + painter.drawLine(cell.bottomLeft(), cell.topLeft()); + + painter.setPen(prevPen); +} + +void PrintableModel::drawNumberSquare(QPainter &painter, double x, double y, int number) +{ + QRectF cell = {x, y, 0.03 * painter.device()->width(), + 1.5 * painter.fontMetrics().lineSpacing()}; + + painter.drawText(cell, Qt::AlignCenter, QString::number(number)); + + painter.drawLine(cell.topLeft(), cell.topRight()); + painter.drawLine(cell.topRight(), cell.bottomRight()); + painter.drawLine(cell.bottomRight(), cell.bottomLeft()); + painter.drawLine(cell.bottomLeft(), cell.topLeft()); +} + +void PrintableModel::PrintableModel::drawCheckSquare(QPainter &painter, const QRectF &cell, + bool checked) +{ + drawTextSquare(painter, cell, checked ? "\u2612" : "\u2610"); +} + +void PrintableModel::drawResultSquare(QPainter &painter, double y, bool rightCell, + unsigned int value) +{ + double pageWidth = painter.device()->width(); + double cellWidth = 0.03 * pageWidth; + double cellHeight = 1.5 * painter.fontMetrics().lineSpacing(); + double x = pageWidth - cellWidth - (rightCell ? 0 : 0.04 * pageWidth); + + drawTextSquare(painter, {x, y, cellWidth, cellHeight}, QString::number(value)); +} + +void PrintableModel::drawGreySquare(QPainter &painter, const QRectF &cell) +{ + auto prevBrush = painter.brush(); + auto prevPen = painter.pen(); + + painter.setBrush(QBrush(QColor(224, 224, 224))); + painter.setPen(QPen(Qt::NoPen)); + QPointF points[4] = {cell.topLeft(), cell.topRight(), cell.bottomRight(), cell.bottomLeft()}; + painter.drawPolygon(points, 4); + + painter.setPen(tablePen()); + painter.drawLine(cell.topLeft(), cell.topRight()); + painter.drawLine(cell.topRight(), cell.bottomRight()); + painter.drawLine(cell.bottomRight(), cell.bottomLeft()); + painter.drawLine(cell.bottomLeft(), cell.topLeft()); + + painter.setBrush(prevBrush); + painter.setPen(prevPen); +} + +void PrintableModel::drawHeader2(QPainter &painter, const QString &text) +{ + painter.setFont(h2Font()); + painter.drawText(0, 0, text); + painter.translate(0, 0.5 * painter.fontMetrics().lineSpacing()); +} + +void PrintableModel::printHeader(QPainter &painter) const +{ + auto title = getTitle(); + if (!title.isEmpty()) + { + drawHeader2(painter, getTitle()); + } +} + +void PrintableModel::printTests(QPainter &painter) const +{ + painter.setFont(tableFont()); + painter.setPen(tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + double headerWidth = headerWidthFactor() * width; + double cellWidth = cellWidthFactor() * width; + double rowHeight = height; + + double x = 0; + double y = 0; + for (const auto &test : m_tests) + { + QString testName = QString::fromStdString( + std::regex_replace(test.name().toStdString(), std::regex("\\s"), "\n")); + + drawTextSquare(painter, {0, y, headerWidth, 2 * rowHeight}, testName); + x = headerWidth; + + for (const auto &item : test.items()) + { + drawTextSquare(painter, {x, y, cellWidth, rowHeight}, item.getText().c_str()); + drawCheckSquare(painter, {x, y + rowHeight, cellWidth, rowHeight}, item.isChecked()); + + x += cellWidth; + } + y += rowHeight; + + drawResultSquare(painter, y, true, test.getPoints()); + y += rowHeight; + } + + painter.translate(0, y + rowHeight); +} + +void PrintableModel::printSummary(QPainter &painter) const +{ + painter.setFont(tableFont()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + painter.drawText(0, 0, 0.95 * width, height, Qt::AlignRight | Qt::AlignVCenter, + "Rohwertpunkte Total:"); + painter.setPen(resultPen()); + drawNumberSquare(painter, 0.97 * width, 0, getPoints()); + + painter.translate(0, 3 * height); +} diff --git a/source/PrintableModel/PrintableModel.h b/source/PrintableModel/PrintableModel.h new file mode 100644 index 0000000..3cbced8 --- /dev/null +++ b/source/PrintableModel/PrintableModel.h @@ -0,0 +1,42 @@ +#pragma once + +#include "CheckableTestModel.h" + +#include +#include +#include +#include +#include + +class PrintableModel : public CheckableTestModel +{ + Q_OBJECT + +public: + PrintableModel(QObject *parent); + + virtual void printTo(QPainter &painter) const; + + static QFont h1Font(); + static QFont h2Font(); + static QFont tableFont(); + + static QPen tablePen(); + static QPen resultPen(); + + static double headerWidthFactor(); + static double cellWidthFactor(); + + static void drawTextSquare(QPainter &painter, const QRectF &cell, const QString &text); + static void drawNumberSquare(QPainter &painter, double x, double y, int number); + static void drawCheckSquare(QPainter &painter, const QRectF &cell, bool checked); + static void drawResultSquare(QPainter &painter, double y, bool rightCell, unsigned int value); + static void drawGreySquare(QPainter &painter, const QRectF &cell); + + static void drawHeader2(QPainter &painter, const QString &text); + +protected: + virtual void printHeader(QPainter &painter) const; + virtual void printTests(QPainter &painter) const; + virtual void printSummary(QPainter &painter) const; +}; diff --git a/source/ResultWidget/CMakeLists.txt b/source/ResultWidget/CMakeLists.txt index bfdd22c..437eeab 100644 --- a/source/ResultWidget/CMakeLists.txt +++ b/source/ResultWidget/CMakeLists.txt @@ -30,6 +30,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE + PrintableModel Age Qt5::Widgets ) diff --git a/source/ResultWidget/ResultModel.cpp b/source/ResultWidget/ResultModel.cpp index c905346..85cf097 100644 --- a/source/ResultWidget/ResultModel.cpp +++ b/source/ResultWidget/ResultModel.cpp @@ -10,13 +10,14 @@ #include "PassivPR.h" #include "GenitivPR.h" +#include "PrintableModel.h" + #include ResultModel::ResultModel(QObject *parent) - : QAbstractTableModel(parent) + : QAbstractTableModel(parent) { - m_results = { { "V2", "SVK", "VE", "Passiv", "Genus", "Akkusativ", "Dativ", - "Genitiv", "Plural" } }; + m_results = {{"V2", "SVK", "VE", "Passiv", "Genus", "Akkusativ", "Dativ", "Genitiv", "Plural"}}; } int ResultModel::rowCount(const QModelIndex &parent) const @@ -81,8 +82,7 @@ QVariant ResultModel::data(const QModelIndex &index, int role) const return {}; } -QVariant ResultModel::headerData( - int section, Qt::Orientation orientation, int role) const +QVariant ResultModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) { @@ -170,7 +170,7 @@ void ResultModel::setDativResult(unsigned int points) emit dataChanged(index(0, 6), index(4, 6)); } } - + void ResultModel::setV2Result(unsigned int points) { if (m_results[0].points() != points) @@ -193,20 +193,66 @@ void ResultModel::setSvkResult(unsigned int points) void ResultModel::setPassivResult(unsigned int points) { - if (m_results[3].points() != points) - { - m_results[3].setPoints(points); - m_results[3].setPR(PassivPR().lookup(m_age, points)); - emit dataChanged(index(0, 3), index(4, 3)); - } + if (m_results[3].points() != points) + { + m_results[3].setPoints(points); + m_results[3].setPR(PassivPR().lookup(m_age, points)); + emit dataChanged(index(0, 3), index(4, 3)); + } } void ResultModel::setGenitivResult(unsigned int points) { - if (m_results[7].points() != points) - { - m_results[7].setPoints(points); - m_results[7].setPR(GenitivPR().lookup(m_age, points)); - emit dataChanged(index(0, 7), index(4, 7)); - } + if (m_results[7].points() != points) + { + m_results[7].setPoints(points); + m_results[7].setPR(GenitivPR().lookup(m_age, points)); + emit dataChanged(index(0, 7), index(4, 7)); + } +} + +void ResultModel::printTo(QPainter &painter) const +{ + PrintableModel::drawHeader2(painter, "Prozentränge (PR)"); + + painter.setFont(PrintableModel::tableFont()); + painter.setPen(PrintableModel::tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + double cellWidth = width / (m_results.size() + 1); + double rowHeight = 2 * height; + + double x = 0; + double y = 0; + + PrintableModel::drawTextSquare(painter, {x, y + 0 * rowHeight, cellWidth, rowHeight}, ""); + PrintableModel::drawTextSquare(painter, {x, y + 1 * rowHeight, cellWidth, rowHeight}, + "\u2265 PR 84"); + PrintableModel::drawTextSquare(painter, {x, y + 2 * rowHeight, cellWidth, rowHeight}, + "< PR 84"); + + PrintableModel::drawGreySquare(painter, {x, y + 3 * rowHeight, cellWidth, rowHeight}); + PrintableModel::drawTextSquare(painter, {x, y + 3 * rowHeight, cellWidth, rowHeight}, + "\u2264 PR 16"); + + x += cellWidth; + for (const auto &result : m_results) + { + PrintableModel::drawTextSquare(painter, {x, y + 0 * rowHeight, cellWidth, rowHeight}, + result.name()); + const auto pr = result.pr(); + + PrintableModel::drawTextSquare(painter, {x, y + 1 * rowHeight, cellWidth, rowHeight}, + pr >= 84 ? QString::number(pr) : "-"); + PrintableModel::drawTextSquare(painter, {x, y + 2 * rowHeight, cellWidth, rowHeight}, + pr < 84 && pr > 16 ? QString::number(pr) : "-"); + + PrintableModel::drawGreySquare(painter, {x, y + 3 * rowHeight, cellWidth, rowHeight}); + PrintableModel::drawTextSquare(painter, {x, y + 3 * rowHeight, cellWidth, rowHeight}, + pr <= 16 ? QString::number(pr) : "-"); + + x += cellWidth; + } } diff --git a/source/ResultWidget/ResultModel.h b/source/ResultWidget/ResultModel.h index ae6dd78..2430f62 100644 --- a/source/ResultWidget/ResultModel.h +++ b/source/ResultWidget/ResultModel.h @@ -1,7 +1,9 @@ #pragma once #include "Age.h" + #include +#include class TestResult { @@ -72,4 +74,6 @@ public: void setSvkResult(unsigned int points); void setPassivResult(unsigned int points); void setGenitivResult(unsigned int points); + + void printTo(QPainter &painter) const; }; diff --git a/source/SubTests/AkkusativDativ/AkkusativModel.cpp b/source/SubTests/AkkusativDativ/AkkusativModel.cpp index 79d2c31..368d297 100644 --- a/source/SubTests/AkkusativDativ/AkkusativModel.cpp +++ b/source/SubTests/AkkusativDativ/AkkusativModel.cpp @@ -1,7 +1,7 @@ #include "AkkusativModel.h" AkkusativModel::AkkusativModel(QObject *parent) - : CheckableTestModel(parent) + : PrintableModel(parent) { m_tests = {{"Akkusativ Nominalphrase", {"Tiger", "Katze", "Affe", "Gans", "Bär", "Pferd", "Hund", "Elefant"}}, @@ -105,3 +105,8 @@ void AkkusativModel::write(ESGRAF48::AkkusativModel &model) const futterModel->set_zucker(testItems[7].isChecked()); } } + +void AkkusativModel::printHeader(QPainter &painter) const +{ + drawHeader2(painter, "Subtest 4: Akkusativ und Dativ"); +} diff --git a/source/SubTests/AkkusativDativ/AkkusativModel.h b/source/SubTests/AkkusativDativ/AkkusativModel.h index 43a4881..e790ad9 100644 --- a/source/SubTests/AkkusativDativ/AkkusativModel.h +++ b/source/SubTests/AkkusativDativ/AkkusativModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "PrintableModel.h" #include "AkkusativModel.pb.h" -class AkkusativModel : public CheckableTestModel +class AkkusativModel : public PrintableModel { Q_OBJECT @@ -12,4 +12,7 @@ public: void read(const ESGRAF48::AkkusativModel &model); void write(ESGRAF48::AkkusativModel &model) const; + +protected: + void printHeader(QPainter &painter) const override; }; diff --git a/source/SubTests/AkkusativDativ/CMakeLists.txt b/source/SubTests/AkkusativDativ/CMakeLists.txt index a543ee7..da3a956 100644 --- a/source/SubTests/AkkusativDativ/CMakeLists.txt +++ b/source/SubTests/AkkusativDativ/CMakeLists.txt @@ -43,9 +43,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - CheckableItem - CheckableTest - CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/AkkusativDativ/DativModel.cpp b/source/SubTests/AkkusativDativ/DativModel.cpp index 3741833..c0a7560 100644 --- a/source/SubTests/AkkusativDativ/DativModel.cpp +++ b/source/SubTests/AkkusativDativ/DativModel.cpp @@ -1,7 +1,7 @@ #include "DativModel.h" DativModel::DativModel(QObject *parent) - : CheckableTestModel(parent) + : PrintableModel(parent) { m_tests = {{"Dativ Nominalphrase", {"Affe", "Gans", "Tiger", "Hund", "Elefant", "Pferd", "Bär", "Katze"}}, @@ -105,3 +105,8 @@ void DativModel::write(ESGRAF48::DativModel &model) const nomTiereModel->set_katze(testItems[7].isChecked()); } } + +void DativModel::printHeader(QPainter &painter) const +{ + painter.translate(0, -1.5 * painter.fontMetrics().lineSpacing()); +} diff --git a/source/SubTests/AkkusativDativ/DativModel.h b/source/SubTests/AkkusativDativ/DativModel.h index 6a9a323..9b21add 100644 --- a/source/SubTests/AkkusativDativ/DativModel.h +++ b/source/SubTests/AkkusativDativ/DativModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "PrintableModel.h" #include "DativModel.pb.h" -class DativModel : public CheckableTestModel +class DativModel : public PrintableModel { Q_OBJECT @@ -12,4 +12,7 @@ public: void read(const ESGRAF48::DativModel &model); void write(ESGRAF48::DativModel &model) const; + +protected: + void printHeader(QPainter &painter) const override; }; diff --git a/source/SubTests/Genus/CMakeLists.txt b/source/SubTests/Genus/CMakeLists.txt index 5b29b68..b3f1ae3 100644 --- a/source/SubTests/Genus/CMakeLists.txt +++ b/source/SubTests/Genus/CMakeLists.txt @@ -39,9 +39,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - CheckableItem - CheckableTest - CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/Genus/GenusModel.cpp b/source/SubTests/Genus/GenusModel.cpp index 3f2278b..faa7460 100644 --- a/source/SubTests/Genus/GenusModel.cpp +++ b/source/SubTests/Genus/GenusModel.cpp @@ -1,8 +1,10 @@ #include "GenusModel.h" GenusModel::GenusModel(QObject *parent) - : CheckableTestModel(parent) + : PrintableModel(parent) { + m_title = "Subtest 3: Genus"; + m_tests = {{"Tiere", {"Tiger", "Bär", "Katze", "Pferd", "Gans", "Elefant", "Affe", "Hund"}}, {"Futter", {"Salat", "Fleisch", "Knochen", "Banane", "Apfel", "Karotte", "Honig", "Zucker"}}, diff --git a/source/SubTests/Genus/GenusModel.h b/source/SubTests/Genus/GenusModel.h index 8261779..fd3faba 100644 --- a/source/SubTests/Genus/GenusModel.h +++ b/source/SubTests/Genus/GenusModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "PrintableModel.h" #include "GenusModel.pb.h" -class GenusModel : public CheckableTestModel +class GenusModel : public PrintableModel { Q_OBJECT diff --git a/source/SubTests/LateSkills/CMakeLists.txt b/source/SubTests/LateSkills/CMakeLists.txt index 7fef071..a32a4d9 100644 --- a/source/SubTests/LateSkills/CMakeLists.txt +++ b/source/SubTests/LateSkills/CMakeLists.txt @@ -22,6 +22,7 @@ protobuf_generate_cpp(LateSkills_PROTO_SRCS LateSkills_PROTO_HDRS add_library(${PROJECT_NAME} LateSkillsWidget.cpp + LateSkillsModel.cpp PassivModel.cpp GenitivModel.cpp ${UI_HEADERS} @@ -43,9 +44,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - CheckableItem - CheckableTest - CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/LateSkills/GenitivModel.cpp b/source/SubTests/LateSkills/GenitivModel.cpp index 9ebf423..6fcf26c 100644 --- a/source/SubTests/LateSkills/GenitivModel.cpp +++ b/source/SubTests/LateSkills/GenitivModel.cpp @@ -1,7 +1,7 @@ #include "GenitivModel.h" GenitivModel::GenitivModel(QObject *parent) - : CheckableTestModel(parent) + : LateSkillsModel(parent) { m_tests = { {"Genitiv Präpositionen", @@ -107,3 +107,8 @@ void GenitivModel::write(ESGRAF48::LateSkillsGenitivModel &model) const attributierungModel->set_guertel2(testItems[9].isChecked()); } } + +void GenitivModel::printHeader(QPainter &painter) const +{ + painter.translate(0, -1.5 * painter.fontMetrics().lineSpacing()); +} diff --git a/source/SubTests/LateSkills/GenitivModel.h b/source/SubTests/LateSkills/GenitivModel.h index 2346e94..4923828 100644 --- a/source/SubTests/LateSkills/GenitivModel.h +++ b/source/SubTests/LateSkills/GenitivModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "LateSkillsModel.h" #include "LateSkillsGenitivModel.pb.h" -class GenitivModel : public CheckableTestModel +class GenitivModel : public LateSkillsModel { Q_OBJECT @@ -14,4 +14,7 @@ public: void read(const ESGRAF48::LateSkillsGenitivModel &model); void write(ESGRAF48::LateSkillsGenitivModel &model) const; + +protected: + void printHeader(QPainter &painter) const override; }; diff --git a/source/SubTests/LateSkills/LateSkillsModel.cpp b/source/SubTests/LateSkills/LateSkillsModel.cpp new file mode 100644 index 0000000..1f441ce --- /dev/null +++ b/source/SubTests/LateSkills/LateSkillsModel.cpp @@ -0,0 +1,64 @@ +#include "LateSkillsModel.h" + +#include + +LateSkillsModel::LateSkillsModel(QObject *parent) + : PrintableModel(parent) +{ +} + +void LateSkillsModel::printTests(QPainter &painter) const +{ + painter.setFont(tableFont()); + painter.setPen(tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + double headerWidth = headerWidthFactor() * width; + double cellHeaderWidth = cellWidthFactor() * width; + double cellWidth = 0.5 * cellHeaderWidth; + double rowHeight = height; + + double x = 0; + double y = 0; + for (const auto &test : m_tests) + { + QString testName = QString::fromStdString( + std::regex_replace(test.name().toStdString(), std::regex("\\s"), "\n")); + + drawTextSquare(painter, {0, y, headerWidth, 3 * rowHeight}, testName); + + const auto &items = test.items(); + + x = headerWidth; + for (unsigned int i = 0; i < items.size(); i += 2) + { + const auto &item = test.items().at(i); + QString itemText = QString::fromStdString(item.getText()).split(" ").at(0); + + drawTextSquare(painter, {x, y, cellHeaderWidth, rowHeight}, itemText); + + x += cellHeaderWidth; + } + y += rowHeight; + + x = headerWidth; + for (const auto &item : items) + { + drawTextSquare(painter, {x, y, cellWidth, rowHeight}, QString::number(item.value())); + drawCheckSquare(painter, {x, y + rowHeight, cellWidth, rowHeight}, item.isChecked()); + + x += cellWidth; + } + + if (m_tests.size() > 1) + { + drawResultSquare(painter, y + rowHeight, true, test.getPoints()); + } + + y += 2 * rowHeight; + } + + painter.translate(0, y + rowHeight); +} diff --git a/source/SubTests/LateSkills/LateSkillsModel.h b/source/SubTests/LateSkills/LateSkillsModel.h new file mode 100644 index 0000000..8049f51 --- /dev/null +++ b/source/SubTests/LateSkills/LateSkillsModel.h @@ -0,0 +1,15 @@ +#pragma once + +#include "PrintableModel.h" +#include "LateSkillsPassivModel.pb.h" + +class LateSkillsModel : public PrintableModel +{ + Q_OBJECT + +public: + LateSkillsModel(QObject *parent); + +protected: + void printTests(QPainter &painter) const override; +}; diff --git a/source/SubTests/LateSkills/PassivModel.cpp b/source/SubTests/LateSkills/PassivModel.cpp index 6f1d3a8..d54d1c3 100644 --- a/source/SubTests/LateSkills/PassivModel.cpp +++ b/source/SubTests/LateSkills/PassivModel.cpp @@ -1,7 +1,7 @@ #include "PassivModel.h" PassivModel::PassivModel(QObject *parent) - : CheckableTestModel(parent) + : LateSkillsModel(parent) { m_tests = {{"Passiv", {"Elefant (1)", "Elefant (2)", "Pferde (1)", "Pferde (2)", "Bälle (1)", "Bälle (2)", @@ -65,3 +65,8 @@ void PassivModel::write(ESGRAF48::LateSkillsPassivModel &model) const model.set_fleisch1(testItems[8].isChecked()); model.set_fleisch2(testItems[9].isChecked()); } + +void PassivModel::printHeader(QPainter &painter) const +{ + drawHeader2(painter, "Subtest 6: Späte Fähigkeiten (7;0-8;11)"); +} diff --git a/source/SubTests/LateSkills/PassivModel.h b/source/SubTests/LateSkills/PassivModel.h index e0671bb..d6aabfd 100644 --- a/source/SubTests/LateSkills/PassivModel.h +++ b/source/SubTests/LateSkills/PassivModel.h @@ -1,17 +1,19 @@ #pragma once -#include "CheckableTestModel.h" +#include "LateSkillsModel.h" #include "LateSkillsPassivModel.pb.h" -class PassivModel : public CheckableTestModel +class PassivModel : public LateSkillsModel { Q_OBJECT public: PassivModel(QObject *parent); - bool setData(const QModelIndex &index, const QVariant &value, - int role = Qt::EditRole) override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; void read(const ESGRAF48::LateSkillsPassivModel &model); void write(ESGRAF48::LateSkillsPassivModel &model) const; + +protected: + void printHeader(QPainter &painter) const override; }; diff --git a/source/SubTests/Plural/CMakeLists.txt b/source/SubTests/Plural/CMakeLists.txt index 7a6aa58..978e936 100644 --- a/source/SubTests/Plural/CMakeLists.txt +++ b/source/SubTests/Plural/CMakeLists.txt @@ -39,9 +39,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - CheckableItem - CheckableTest - CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/Plural/PluralModel.cpp b/source/SubTests/Plural/PluralModel.cpp index dcd0959..cc9568e 100644 --- a/source/SubTests/Plural/PluralModel.cpp +++ b/source/SubTests/Plural/PluralModel.cpp @@ -2,9 +2,13 @@ #include +#include + PluralModel::PluralModel(QObject *parent) - : CheckableTestModel(parent) + : PrintableModel(parent) { + m_title = "Subtest 5: Plural"; + m_tests = {{"Plural", {"Fisch /-e/", "Banane /-n/", "Bonbon /-s/", "Ei /-er/", "Eimer /-ø/", "Korn UML+/-er/", "Nuss UML+/-e/", "Bär /-en/", "Apfel UML"}}}; @@ -41,3 +45,39 @@ void PluralModel::write(ESGRAF48::PluralModel &model) const model.set_baer(testItems[7].isChecked()); model.set_apfel(testItems[8].isChecked()); } + +void PluralModel::printTests(QPainter &painter) const +{ + painter.setFont(tableFont()); + painter.setPen(tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + double headerWidth = headerWidthFactor() * width; + double cellWidth = cellWidthFactor() * width; + double rowHeight = height; + + double x = 0; + double y = 0; + for (const auto &test : m_tests) + { + drawTextSquare(painter, {0, y, headerWidth, 3 * rowHeight}, test.name()); + x = headerWidth; + + for (const auto &item : test.items()) + { + QString itemText = + QString::fromStdString(std::regex_replace(item.getText(), std::regex("\\s"), "\n")); + + drawTextSquare(painter, {x, y, cellWidth, 2 * rowHeight}, itemText); + drawCheckSquare(painter, {x, y + 2 * rowHeight, cellWidth, rowHeight}, + item.isChecked()); + + x += cellWidth; + } + y += 2 * rowHeight; + } + + painter.translate(0, y + 2 * rowHeight); +} diff --git a/source/SubTests/Plural/PluralModel.h b/source/SubTests/Plural/PluralModel.h index ef1381f..f7c3543 100644 --- a/source/SubTests/Plural/PluralModel.h +++ b/source/SubTests/Plural/PluralModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "PrintableModel.h" #include "PluralModel.pb.h" -class PluralModel : public CheckableTestModel +class PluralModel : public PrintableModel { Q_OBJECT @@ -12,4 +12,7 @@ public: void read(const ESGRAF48::PluralModel &model); void write(ESGRAF48::PluralModel &model) const; + +protected: + virtual void printTests(QPainter &painter) const; }; diff --git a/source/SubTests/V2Svk/CMakeLists.txt b/source/SubTests/V2Svk/CMakeLists.txt index 441c569..2690a7b 100644 --- a/source/SubTests/V2Svk/CMakeLists.txt +++ b/source/SubTests/V2Svk/CMakeLists.txt @@ -19,6 +19,7 @@ protobuf_generate_cpp(V2Svk_PROTO_SRCS V2Svk_PROTO_HDRS ${V2Svk_PROTO_FILES}) add_library(${PROJECT_NAME} V2SvkWidget.cpp + V2SvkModel.cpp WFModel.cpp OTModel.cpp TPrModel.cpp @@ -42,9 +43,7 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE - CheckableItem - CheckableTest - CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/V2Svk/OTModel.cpp b/source/SubTests/V2Svk/OTModel.cpp index 1c0f477..6760255 100644 --- a/source/SubTests/V2Svk/OTModel.cpp +++ b/source/SubTests/V2Svk/OTModel.cpp @@ -1,7 +1,7 @@ #include "OTModel.h" OTModel::OTModel(QObject *parent) - : CheckableTestModel(parent) + : V2SvkModel(parent) { m_tests = { {"Objekt-Topikalisierung", @@ -13,7 +13,7 @@ OTModel::OTModel(QObject *parent) }; } -unsigned int OTModel::getV2Points() +unsigned int OTModel::getV2Points() const { unsigned int points = 0; @@ -33,7 +33,7 @@ unsigned int OTModel::getV2Points() return points; } -unsigned int OTModel::getSvkPoints() +unsigned int OTModel::getSvkPoints() const { unsigned int points = 0; @@ -103,3 +103,13 @@ void OTModel::read(const ESGRAF48::V2SvkModel &model) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } + +std::set OTModel::v2Tests() const +{ + return {0}; +}; + +std::set OTModel::svkTests() const +{ + return {1}; +}; diff --git a/source/SubTests/V2Svk/OTModel.h b/source/SubTests/V2Svk/OTModel.h index d4b5a49..c9d9e2b 100644 --- a/source/SubTests/V2Svk/OTModel.h +++ b/source/SubTests/V2Svk/OTModel.h @@ -1,18 +1,24 @@ #pragma once -#include "CheckableTestModel.h" +#include "V2SvkModel.h" #include "V2SvkModel.pb.h" -class OTModel : public CheckableTestModel +class OTModel : public V2SvkModel { Q_OBJECT public: OTModel(QObject *parent); - unsigned int getV2Points(); - unsigned int getSvkPoints(); + unsigned int getV2Points() const override; + unsigned int getSvkPoints() const override; - void write(ESGRAF48::V2SvkModel &model) const; - void read(const ESGRAF48::V2SvkModel &model); + void write(ESGRAF48::V2SvkModel &model) const override; + void read(const ESGRAF48::V2SvkModel &model) override; + +protected: + void printHeader(QPainter &) const override {}; + + std::set v2Tests() const override; + std::set svkTests() const override; }; diff --git a/source/SubTests/V2Svk/TPeModel.cpp b/source/SubTests/V2Svk/TPeModel.cpp index 2c17da3..5f66aab 100644 --- a/source/SubTests/V2Svk/TPeModel.cpp +++ b/source/SubTests/V2Svk/TPeModel.cpp @@ -1,7 +1,7 @@ #include "TPeModel.h" TPeModel::TPeModel(QObject *parent) - : CheckableTestModel(parent) + : V2SvkModel(parent) { m_tests = { {"Temporaladverb Perfekt", {"Affe", "Affe", "Schwein", "Schwein", "Gans", "Gans"}}, @@ -11,7 +11,7 @@ TPeModel::TPeModel(QObject *parent) }; } -unsigned int TPeModel::getV2Points() +unsigned int TPeModel::getV2Points() const { unsigned int points = 0; @@ -31,7 +31,7 @@ unsigned int TPeModel::getV2Points() return points; } -unsigned int TPeModel::getSvkPoints() +unsigned int TPeModel::getSvkPoints() const { unsigned int points = 0; @@ -93,3 +93,13 @@ void TPeModel::read(const ESGRAF48::V2SvkModel &model) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } + +std::set TPeModel::v2Tests() const +{ + return {0, 1}; +}; + +std::set TPeModel::svkTests() const +{ + return {2, 3}; +}; diff --git a/source/SubTests/V2Svk/TPeModel.h b/source/SubTests/V2Svk/TPeModel.h index 19a1c12..60eb7ba 100644 --- a/source/SubTests/V2Svk/TPeModel.h +++ b/source/SubTests/V2Svk/TPeModel.h @@ -1,18 +1,24 @@ #pragma once -#include "CheckableTestModel.h" +#include "V2SvkModel.h" #include "V2SvkModel.pb.h" -class TPeModel : public CheckableTestModel +class TPeModel : public V2SvkModel { Q_OBJECT public: TPeModel(QObject *parent); - unsigned int getV2Points(); - unsigned int getSvkPoints(); + unsigned int getV2Points() const override; + unsigned int getSvkPoints() const override; - void write(ESGRAF48::V2SvkModel &model) const; - void read(const ESGRAF48::V2SvkModel &model); + void write(ESGRAF48::V2SvkModel &model) const override; + void read(const ESGRAF48::V2SvkModel &model) override; + +protected: + void printHeader(QPainter &) const override {}; + + std::set v2Tests() const override; + std::set svkTests() const override; }; diff --git a/source/SubTests/V2Svk/TPrModel.cpp b/source/SubTests/V2Svk/TPrModel.cpp index fcf9c01..995b584 100644 --- a/source/SubTests/V2Svk/TPrModel.cpp +++ b/source/SubTests/V2Svk/TPrModel.cpp @@ -1,7 +1,7 @@ #include "TPrModel.h" TPrModel::TPrModel(QObject *parent) - : CheckableTestModel(parent) + : V2SvkModel(parent) { m_tests = { {"Temporaladverb Präsens", {"Affe", "Affe", "Schwein", "Schwein", "Gans", "Gans"}}, @@ -9,7 +9,7 @@ TPrModel::TPrModel(QObject *parent) }; } -unsigned int TPrModel::getV2Points() +unsigned int TPrModel::getV2Points() const { unsigned int points = 0; @@ -29,7 +29,7 @@ unsigned int TPrModel::getV2Points() return points; } -unsigned int TPrModel::getSvkPoints() +unsigned int TPrModel::getSvkPoints() const { unsigned int points = 0; @@ -87,3 +87,13 @@ void TPrModel::read(const ESGRAF48::V2SvkModel &model) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } + +std::set TPrModel::v2Tests() const +{ + return {0}; +}; + +std::set TPrModel::svkTests() const +{ + return {1}; +}; diff --git a/source/SubTests/V2Svk/TPrModel.h b/source/SubTests/V2Svk/TPrModel.h index 257a576..9047cbf 100644 --- a/source/SubTests/V2Svk/TPrModel.h +++ b/source/SubTests/V2Svk/TPrModel.h @@ -1,18 +1,24 @@ #pragma once -#include "CheckableTestModel.h" +#include "V2SvkModel.h" #include "V2SvkModel.pb.h" -class TPrModel : public CheckableTestModel +class TPrModel : public V2SvkModel { Q_OBJECT public: TPrModel(QObject *parent); - unsigned int getV2Points(); - unsigned int getSvkPoints(); + unsigned int getV2Points() const override; + unsigned int getSvkPoints() const override; - void write(ESGRAF48::V2SvkModel &model) const; - void read(const ESGRAF48::V2SvkModel &model); + void write(ESGRAF48::V2SvkModel &model) const override; + void read(const ESGRAF48::V2SvkModel &model) override; + +protected: + void printHeader(QPainter &) const override{}; + + std::set v2Tests() const override; + std::set svkTests() const override; }; diff --git a/source/SubTests/V2Svk/V2SvkModel.cpp b/source/SubTests/V2Svk/V2SvkModel.cpp new file mode 100644 index 0000000..ff0ab00 --- /dev/null +++ b/source/SubTests/V2Svk/V2SvkModel.cpp @@ -0,0 +1,137 @@ +#include "V2SvkModel.h" + +#include + +V2SvkModel::V2SvkModel(QObject *parent) + : PrintableModel(parent) +{ +} + +void V2SvkModel::printTests(QPainter &painter) const +{ + painter.setFont(tableFont()); + painter.setPen(tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + auto v2TestIndices = v2Tests(); + auto svkTestIndices = svkTests(); + + double x = 0; + double y = 0; + auto testIndex = 0; + for (const auto &test : m_tests) + { + double rowHeaderWidth = headerWidthFactor() * width; + double resultCellWidth = (test.size() > 8 ? 0.5 : 1) * cellWidthFactor() * width; + double rowHeight = height; + + QString testName = test.name(); + if (testName.length() > 20) + { + testName = QString::fromStdString( + std::regex_replace(testName.toStdString(), std::regex("[\\s-]"), "\n")); + } + + if (testIndex == 0) + { + drawTextSquare(painter, {x, y, rowHeaderWidth, 2 * rowHeight}, testName); + x += rowHeaderWidth; + + std::vector> columnHeaders; + for (const auto &item : test.items()) + { + const auto &itemText = item.getText(); + if (!columnHeaders.empty() && columnHeaders.back().first == itemText) + { + columnHeaders.back().second++; + } + else + { + columnHeaders.emplace_back(itemText, 1); + } + } + + for (const auto &columnHeader : columnHeaders) + { + double cellWidth = columnHeader.second * resultCellWidth; + drawTextSquare(painter, {x, y, cellWidth, rowHeight}, columnHeader.first.c_str()); + x += cellWidth; + } + x = rowHeaderWidth; + y += rowHeight; + } + else + { + drawTextSquare(painter, {x, y, rowHeaderWidth, rowHeight}, testName); + x += rowHeaderWidth; + } + + unsigned int emptyItemsStack = 0; + for (const auto &item : test.items()) + { + if (item.getText().empty()) + { + emptyItemsStack++; + } + else + { + if (emptyItemsStack > 0) + { + drawGreySquare(painter, {x - emptyItemsStack * resultCellWidth, y, + emptyItemsStack * resultCellWidth, rowHeight}); + emptyItemsStack = 0; + } + + drawCheckSquare(painter, {x, y, resultCellWidth, rowHeight}, item.isChecked()); + } + x += resultCellWidth; + } + if (emptyItemsStack > 0) + { + drawGreySquare(painter, {x - emptyItemsStack * resultCellWidth, y, + emptyItemsStack * resultCellWidth, rowHeight}); + emptyItemsStack = 0; + } + + if (v2TestIndices.find(testIndex) != v2TestIndices.end()) + { + drawResultSquare(painter, y, false, test.getPoints()); + } + + if (svkTestIndices.find(testIndex) != svkTestIndices.end()) + { + drawResultSquare(painter, y, true, test.getPoints()); + } + + x = 0; + y += rowHeight; + + testIndex++; + } + + x = 0; + y += height; + + painter.translate(0, y); +} + +void V2SvkModel::printSummary(QPainter &painter, unsigned int v2Points, unsigned int svkPoints) +{ + painter.setFont(PrintableModel::tableFont()); + painter.setPen(PrintableModel::tablePen()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + painter.drawText(0, 0, 0.91 * width, height, Qt::AlignRight | Qt::AlignVCenter, + "Rohwertpunkte Total:"); + + painter.setPen(resultPen()); + drawNumberSquare(painter, 0.93 * width, 0, v2Points); + drawNumberSquare(painter, 0.97 * width, 0, svkPoints); + + painter.translate(0, 3 * height); +} + diff --git a/source/SubTests/V2Svk/V2SvkModel.h b/source/SubTests/V2Svk/V2SvkModel.h new file mode 100644 index 0000000..87af510 --- /dev/null +++ b/source/SubTests/V2Svk/V2SvkModel.h @@ -0,0 +1,27 @@ +#pragma once + +#include "PrintableModel.h" +#include "V2SvkModel.pb.h" + +class V2SvkModel : public PrintableModel +{ + Q_OBJECT + +public: + V2SvkModel(QObject *parent); + + virtual unsigned int getV2Points() const = 0; + virtual unsigned int getSvkPoints() const = 0; + + virtual void write(ESGRAF48::V2SvkModel &model) const = 0; + virtual void read(const ESGRAF48::V2SvkModel &model) = 0; + + static void printSummary(QPainter &painter, unsigned int v2Points, unsigned int svkPoints); + +protected: + void printTests(QPainter &painter) const override; + void printSummary(QPainter &painter) const override {}; + + virtual std::set v2Tests() const = 0; + virtual std::set svkTests() const = 0; +}; diff --git a/source/SubTests/V2Svk/WFModel.cpp b/source/SubTests/V2Svk/WFModel.cpp index fac9098..487a5dc 100644 --- a/source/SubTests/V2Svk/WFModel.cpp +++ b/source/SubTests/V2Svk/WFModel.cpp @@ -1,8 +1,10 @@ #include "WFModel.h" WFModel::WFModel(QObject *parent) - : CheckableTestModel(parent) + : V2SvkModel(parent) { + m_title = "Subtest 1: Verbzweitstellungsregel (V2) und Subjekt-Verb-Kontrollregel (SVK)"; + m_tests = { {"W-Frage", {"Affe", "Affe", "Affe", "Affe", "Schwein", "Schwein", "Schwein", "Schwein", "Gans", @@ -14,7 +16,7 @@ WFModel::WFModel(QObject *parent) }; } -unsigned int WFModel::getV2Points() +unsigned int WFModel::getV2Points() const { unsigned int points = 0; @@ -34,7 +36,7 @@ unsigned int WFModel::getV2Points() return points; } -unsigned int WFModel::getSvkPoints() +unsigned int WFModel::getSvkPoints() const { unsigned int points = 0; @@ -133,3 +135,13 @@ void WFModel::read(const ESGRAF48::V2SvkModel &model) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } + +std::set WFModel::v2Tests() const +{ + return {0, 1}; +}; + +std::set WFModel::svkTests() const +{ + return {2}; +}; diff --git a/source/SubTests/V2Svk/WFModel.h b/source/SubTests/V2Svk/WFModel.h index 647765a..a3d801d 100644 --- a/source/SubTests/V2Svk/WFModel.h +++ b/source/SubTests/V2Svk/WFModel.h @@ -1,20 +1,24 @@ #pragma once -#include "CheckableTestModel.h" +#include "V2SvkModel.h" #include "V2SvkModel.pb.h" -class WFModel : public CheckableTestModel +class WFModel : public V2SvkModel { Q_OBJECT public: WFModel(QObject *parent); - unsigned int getV2Points(); - unsigned int getSvkPoints(); + unsigned int getV2Points() const override; + unsigned int getSvkPoints() const override; - void write(ESGRAF48::V2SvkModel &model) const; - void read(const ESGRAF48::V2SvkModel &model); + void write(ESGRAF48::V2SvkModel &model) const override; + void read(const ESGRAF48::V2SvkModel &model) override; - bool isValidIndex(const QModelIndex &index) const; +protected: + std::set v2Tests() const override; + std::set svkTests() const override; + + bool isValidIndex(const QModelIndex &index) const override; }; diff --git a/source/SubTests/VerbEnd/CMakeLists.txt b/source/SubTests/VerbEnd/CMakeLists.txt index 1302223..135ab66 100644 --- a/source/SubTests/VerbEnd/CMakeLists.txt +++ b/source/SubTests/VerbEnd/CMakeLists.txt @@ -42,6 +42,7 @@ target_link_libraries(${PROJECT_NAME} CheckableItem CheckableTest CheckableTestModel + PrintableModel Qt5::Widgets ${Protobuf_LIBRARIES} ) diff --git a/source/SubTests/VerbEnd/VerbEndModel.cpp b/source/SubTests/VerbEnd/VerbEndModel.cpp index dea4d95..afc21cc 100644 --- a/source/SubTests/VerbEnd/VerbEndModel.cpp +++ b/source/SubTests/VerbEnd/VerbEndModel.cpp @@ -1,15 +1,14 @@ #include "VerbEndModel.h" VerbEndModel::VerbEndModel(QObject *parent) - : CheckableTestModel(parent) + : PrintableModel(parent) { - m_tests = { { "Telefonat", - { "Kausal", "Kausal", "Relativ", "Kausal", - "Final", "Temporal", "Temporal" } }, - { "Zaubertrick", { "Relativ", "Final", "Kausal", "Final", - "Temporal", "Kausal", "Temporal" } }, - { "Zauberregel", { "Temporal", "Kausal", "Final", "Relativ", - "Temporal", "Relativ" } } }; + m_title = "Subtest 2: Verbendstellungsregel (VE)"; + + m_tests = { + {"Telefonat", {"Kausal", "Kausal", "Relativ", "Kausal", "Final", "Temporal", "Temporal"}}, + {"Zaubertrick", {"Relativ", "Final", "Kausal", "Final", "Temporal", "Kausal", "Temporal"}}, + {"Zauberregel", {"Temporal", "Kausal", "Final", "Relativ", "Temporal", "Relativ"}}}; } void VerbEndModel::write(ESGRAF48::VerbEndModel &model) const @@ -98,3 +97,32 @@ void VerbEndModel::read(const ESGRAF48::VerbEndModel &model) emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1)); } + +unsigned int VerbEndModel::getKausalPoints() const +{ + auto points = [&](unsigned int testId, unsigned int itemId) { + return m_tests.at(testId).items().at(itemId).points(); + }; + + return points(0, 0) + points(0, 1) + points(0, 3) + points(1, 2) + points(1, 5) + points(2, 1); +} + +void VerbEndModel::printSummary(QPainter &painter) const +{ + painter.setFont(tableFont()); + + auto width = painter.device()->width(); + auto height = 1.5 * painter.fontMetrics().lineSpacing(); + + painter.drawText(0, 0, 0.71 * width, height, Qt::AlignRight | Qt::AlignVCenter, + "Rohwertpunkte Kausalsätze:"); + painter.drawText(0, 0, 0.95 * width, height, Qt::AlignRight | Qt::AlignVCenter, + "Rohwertpunkte Total:"); + + drawNumberSquare(painter, 0.73 * width, 0, getKausalPoints()); + + painter.setPen(resultPen()); + drawNumberSquare(painter, 0.97 * width, 0, getKausalPoints()); + + painter.translate(0, 3 * height); +} diff --git a/source/SubTests/VerbEnd/VerbEndModel.h b/source/SubTests/VerbEnd/VerbEndModel.h index cf6342a..0211e4f 100644 --- a/source/SubTests/VerbEnd/VerbEndModel.h +++ b/source/SubTests/VerbEnd/VerbEndModel.h @@ -1,9 +1,9 @@ #pragma once -#include "CheckableTestModel.h" +#include "PrintableModel.h" #include "VerbEndModel.pb.h" -class VerbEndModel : public CheckableTestModel +class VerbEndModel : public PrintableModel { Q_OBJECT @@ -12,4 +12,9 @@ public: void write(ESGRAF48::VerbEndModel &model) const; void read(const ESGRAF48::VerbEndModel &model); + + unsigned int getKausalPoints() const; + +protected: + void printSummary(QPainter &painter) const override; }; diff --git a/source/mainwindow.cpp b/source/mainwindow.cpp index 9d90d06..3a29063 100644 --- a/source/mainwindow.cpp +++ b/source/mainwindow.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -167,10 +168,9 @@ void MainWindow::closeFile() void MainWindow::print() const { - //std::ofstream htmlfile("print.html"); - //htmlfile << m_dataModel.toHtml(); - QPrinter printer; + printer.setPaperSize(QPrinter::A4); + printer.setPageMargins(20, 20, 20, 20, QPrinter::Millimeter); QPrintDialog dialog(&printer); if (dialog.exec() != QDialog::Accepted) @@ -178,10 +178,7 @@ void MainWindow::print() const return; } - QTextDocument printDoc; - printDoc.setHtml(QString::fromStdString(m_dataModel.toHtml())); - - printDoc.print(&printer); + m_dataModel.printTo(printer); } void MainWindow::dataModelChanged() @@ -237,12 +234,10 @@ void MainWindow::savePdf(const QString &filename) QPrinter printer; printer.setOutputFormat(QPrinter::PdfFormat); printer.setPaperSize(QPrinter::A4); + printer.setPageMargins(20, 20, 20, 20, QPrinter::Millimeter); printer.setOutputFileName(filename); - QTextDocument printDoc; - printDoc.setHtml(QString::fromStdString(m_dataModel.toHtml())); - - printDoc.print(&printer); + m_dataModel.printTo(printer); } void MainWindow::aboutDialog() diff --git a/source/mainwindow.h b/source/mainwindow.h index e250555..f49c5bf 100644 --- a/source/mainwindow.h +++ b/source/mainwindow.h @@ -4,6 +4,7 @@ #include #include +#include class DataModel;