File indexing completed on 2024-04-21 03:51:06

0001 /*
0002     SPDX-FileCopyrightText: 2007-2009 Frederik Gladhorn <gladhorn@kde.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "practicesummarycomponent.h"
0007 #include "prefs.h"
0008 
0009 #include "parleyactions.h"
0010 
0011 #include <KActionCollection>
0012 #include <KColorScheme>
0013 #include <KConfigGroup>
0014 #include <KEduVocExpression>
0015 #include <KLocalizedString>
0016 #include <KMessageBox>
0017 #include <KToolBar>
0018 #include <QFileDialog>
0019 #include <QTableWidgetItem>
0020 #include <QTextCursor>
0021 #include <QTextDocument>
0022 #include <QTextDocumentWriter>
0023 #include <QTextTable>
0024 
0025 using namespace Practice;
0026 
0027 class PracticeSummaryComponent::SortedAttemptTableWidgetItem : public QTableWidgetItem
0028 {
0029     bool operator<(const QTableWidgetItem &other) const override
0030     {
0031         if (data(Qt::DisplayRole).toInt() == other.data(Qt::DisplayRole).toInt()) {
0032             return data(Qt::UserRole).toInt() < other.data(Qt::UserRole).toInt();
0033         }
0034         return data(Qt::DisplayRole).toInt() < other.data(Qt::DisplayRole).toInt();
0035     }
0036 };
0037 
0038 PracticeSummaryComponent::PracticeSummaryComponent(SessionManagerBase *sessionManager, QWidget *parent)
0039     : KXmlGuiWindow(parent)
0040     , m_sessionManager(sessionManager)
0041 {
0042     // KXmlGui
0043     setXMLFile(QStringLiteral("practicesummaryui.rc"));
0044     setObjectName(QStringLiteral("Statistics"));
0045 
0046     QWidget *mainWidget = new QWidget(this);
0047     setupUi(mainWidget);
0048     setCentralWidget(mainWidget);
0049 
0050     initActions(parent);
0051 
0052     setupDetailsTable();
0053     summaryBar->setStatistics(m_sessionManager->statisticTotalCorrectFirstAttempt(),
0054                               m_sessionManager->statisticTotalWrong(),
0055                               m_sessionManager->statisticTotalUnanswered());
0056 
0057     int total = m_sessionManager->statisticTotalCorrectFirstAttempt() + m_sessionManager->statisticTotalWrong();
0058     int minutes = m_sessionManager->totalTime() / 60;
0059     int seconds = m_sessionManager->totalTime() % 60;
0060 
0061     testSummaryLabel->setText(i18nc("number of words, minutes, seconds",
0062                                     "You practiced %1 in %2 and %3.",
0063                                     i18np("one word", "%1 words", total),
0064                                     i18np("one minute", "%1 minutes", minutes),
0065                                     i18np("one second", "%1 seconds", seconds)));
0066 
0067     KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName());
0068     applyMainWindowSettings(cfg);
0069 }
0070 
0071 PracticeSummaryComponent::~PracticeSummaryComponent()
0072 {
0073     KConfigGroup cfg(KSharedConfig::openConfig(QStringLiteral("parleyrc")), objectName());
0074     saveMainWindowSettings(cfg);
0075 }
0076 
0077 void PracticeSummaryComponent::initActions(QWidget *parleyMainWindow)
0078 {
0079     ParleyActions::create(ParleyActions::EnterEditMode, parleyMainWindow, SLOT(showEditor()), actionCollection());
0080     ParleyActions::create(ParleyActions::StartPractice, parleyMainWindow, SLOT(showPracticeConfiguration()), actionCollection());
0081     ParleyActions::create(ParleyActions::ExportPracticeResults, this, SLOT(exportResults()), actionCollection());
0082     actionCollection()->action(QStringLiteral("practice_start"))->setText(i18n("Practice Overview"));
0083     actionCollection()->action(QStringLiteral("practice_start"))->setToolTip(i18n("Switch to the Practice Overview page"));
0084 }
0085 
0086 void PracticeSummaryComponent::setupDetailsTable()
0087 {
0088     tableWidget->setRowCount(m_sessionManager->allEntryCount());
0089     tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
0090 
0091     Qt::ItemFlags flags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
0092 
0093     KColorScheme scheme(QPalette::Active);
0094     QPalette correctPalette = QApplication::palette();
0095     correctPalette.setColor(QPalette::WindowText, scheme.foreground(KColorScheme::PositiveText).color());
0096     correctPalette.setColor(QPalette::Text, scheme.foreground(KColorScheme::PositiveText).color());
0097 
0098     QPalette wrongPalette = QApplication::palette();
0099     wrongPalette.setColor(QPalette::WindowText, scheme.foreground(KColorScheme::NegativeText).color());
0100     wrongPalette.setColor(QPalette::Text, scheme.foreground(KColorScheme::NegativeText).color());
0101 
0102     int i = 0;
0103     // TODO headers with languages
0104     // TODO some colors, maybe an indicator icon whether the word was right/wrong
0105     const QList<TestEntry *> allTestEntries = m_sessionManager->allTestEntries();
0106     for (TestEntry *entry : allTestEntries) {
0107         QTableWidgetItem *itemFrom = new QTableWidgetItem(entry->entry()->translation(entry->TestEntry::languageFrom())->text());
0108         QTableWidgetItem *itemTo = new QTableWidgetItem(entry->entry()->translation(entry->languageTo())->text());
0109         if (entry->statisticGoodCount() > 0) {
0110             itemTo->setForeground(correctPalette.windowText());
0111         }
0112 
0113         QTableWidgetItem *itemUserAnswer = new QTableWidgetItem(entry->userAnswers().join(QStringLiteral("; ")));
0114         itemUserAnswer->setForeground(wrongPalette.windowText());
0115 
0116         SortedAttemptTableWidgetItem *itemAttempts = new SortedAttemptTableWidgetItem();
0117         itemAttempts->setData(Qt::DisplayRole, entry->statisticCount());
0118         itemAttempts->setData(Qt::UserRole, entry->statisticBadCount());
0119         itemAttempts->setTextAlignment(Qt::AlignRight);
0120 
0121         itemFrom->setFlags(flags);
0122         itemTo->setFlags(flags);
0123         itemUserAnswer->setFlags(flags);
0124         itemAttempts->setFlags(flags);
0125 
0126         if (entry->correctAtFirstAttempt()) {
0127             itemUserAnswer->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-apply")));
0128         } else if (entry->statisticGoodCount() > 0) {
0129             itemUserAnswer->setIcon(QIcon::fromTheme(QStringLiteral("task-attempt")));
0130         } else if (entry->statisticCount() > 0) {
0131             itemUserAnswer->setIcon(QIcon::fromTheme(QStringLiteral("dialog-error")));
0132         } else {
0133             itemUserAnswer->setIcon(QIcon::fromTheme(QStringLiteral("task-attempt")));
0134         }
0135 
0136         tableWidget->setItem(i, 0, itemAttempts);
0137         tableWidget->setItem(i, 1, itemFrom);
0138         tableWidget->setItem(i, 2, itemTo);
0139         tableWidget->setItem(i, 3, itemUserAnswer);
0140         ++i;
0141     }
0142 
0143     tableWidget->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);
0144     tableWidget->setSortingEnabled(true);
0145     tableWidget->sortItems(0, Qt::DescendingOrder);
0146 }
0147 
0148 void PracticeSummaryComponent::exportResults()
0149 {
0150     QString filter = i18n("HTML Files") + " (*.html);;" + i18n("OpenDocument text files") + " (*.odt)";
0151     QString caption;
0152     QString startingdir(QStringLiteral("kfiledialog:///practice_export"));
0153     QString fileName = QFileDialog::getSaveFileName(nullptr, caption, startingdir, filter);
0154 
0155     if (fileName.isEmpty()) {
0156         return;
0157     }
0158 
0159     QTextDocument doc;
0160     doc.setHtml("<html><head><title>" + i18n("Practice results") + "</title></body></html>");
0161     QTextCursor cursor(&doc);
0162 
0163     cursor.insertHtml("<h1>" + m_sessionManager->title() + "</h1><br />");
0164 
0165     cursor.insertText(i18n("Answered questions: %1\n", m_sessionManager->allEntryCount()));
0166     cursor.insertText(i18n("Correct answers: %1\n", m_sessionManager->statisticTotalCorrectFirstAttempt()));
0167     cursor.insertText(i18n("Wrong answers: %1\n", m_sessionManager->statisticTotalWrong()));
0168 
0169     QTextTableFormat tableFormat;
0170     tableFormat.setBorderStyle(QTextFrameFormat::BorderStyle_Solid);
0171     tableFormat.setCellPadding(1);
0172     tableFormat.setAlignment(Qt::AlignLeft);
0173     QTextTable *table = cursor.insertTable(1, 4, tableFormat);
0174     table->cellAt(0, 0).firstCursorPosition().insertHtml(i18n("<b>Attempts</b>"));
0175     table->cellAt(0, 1).firstCursorPosition().insertHtml(i18n("<b>Question</b>"));
0176     table->cellAt(0, 2).firstCursorPosition().insertHtml(i18n("<b>Correct answer</b>"));
0177     table->cellAt(0, 3).firstCursorPosition().insertHtml(i18n("<b>Your errors</b>"));
0178 
0179     const QList<TestEntry *> allTestEntries = m_sessionManager->allTestEntries();
0180     for (TestEntry *entry : allTestEntries) {
0181         table->appendRows(1);
0182         int newRow = table->rows() - 1;
0183         table->cellAt(newRow, 0).firstCursorPosition().insertText(QString::number(entry->statisticCount()));
0184         table->cellAt(newRow, 1).firstCursorPosition().insertText(entry->entry()->translation(entry->languageFrom())->text());
0185         table->cellAt(newRow, 2).firstCursorPosition().insertText(entry->entry()->translation(entry->languageTo())->text());
0186         table->cellAt(newRow, 3).firstCursorPosition().insertText(entry->userAnswers().join(QStringLiteral("; ")));
0187     }
0188 
0189     QTextDocumentWriter writer(fileName);
0190 
0191     if (!writer.write(&doc)) {
0192         KMessageBox::error(this, i18n("Could not write to %1", fileName), i18n("Could not write file"));
0193         return;
0194     }
0195 }
0196 
0197 #include "moc_practicesummarycomponent.cpp"