diff --git a/src/practice/sessionmanagerbase.cpp b/src/practice/sessionmanagerbase.cpp index 1f81fd17..5c1de4c0 100644 --- a/src/practice/sessionmanagerbase.cpp +++ b/src/practice/sessionmanagerbase.cpp @@ -1,332 +1,332 @@ /*************************************************************************** copyright : (C) 1999-2001 Ewald Arnold (C) 2005-2007 Peter Hedlund (C) 2007-2009 Frederik Gladhorn (C) 2014 Inge Wallin ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "sessionmanagerbase.h" // Qt #include // kdelibs #include #include #include #include #include // kdeedulibs #include #include #include // parley #include "entryfilter.h" #include using namespace Practice; SessionManagerBase::SessionManagerBase(QWidget* parent) : m_parent(parent) , m_learningLanguageIndex(0) , m_knownLanguageIndex(1) , m_currentEntry(-1) , m_totalTime(0) { } SessionManagerBase::~SessionManagerBase() { qDeleteAll(m_allTestEntries); } void SessionManagerBase::setDocument(KEduVocDocument* doc) { qDeleteAll(m_allTestEntries); m_allTestEntries.clear(); m_notAskedTestEntries.clear(); m_currentEntries.clear(); m_doc = doc; // Make sure that there are at least 2 languages in the file before // starting the practice. If we don't do this, it will crash later. if (m_doc->identifierCount() < 2) { KMessageBox::error(0, i18n("The vocabulary collection contains fewer than two languages."), i18n("Could not start practice")); return; } if (Prefs::learningLanguage() >= m_doc->identifierCount() || Prefs::knownLanguage() >= m_doc->identifierCount()) { Prefs::setLearningLanguage(0); Prefs::setKnownLanguage(1); } m_learningLanguageIndex = Prefs::learningLanguage(); m_knownLanguageIndex = Prefs::knownLanguage(); // qDebug() << "Practice: learning language:" << m_doc->identifier(m_learningLanguageIndex).name() // << " known language:" << m_doc->identifier(m_knownLanguageIndex).name(); // Create the list of available entries for this training session. EntryFilter filter(m_doc, m_parent); m_allTestEntries = filter.entries(); // qDebug() << "Entries: ----------------"; // qDebug() << "Found " << m_allTestEntries.count() << " entries after filtering."; // foreach (TestEntry *entry, m_allTestEntries) { // qDebug() << "Entry: " << entry->languageFrom() << entry->entry()->translation(entry->languageFrom())->text() // << "to" << entry->languageTo() << entry->entry()->translation(entry->languageTo())->text(); // } // Create the list actual entries in this training session. This // is a pure virtual function and must be implemented by the // concrete session managers. initializeTraining(); } QString SessionManagerBase::title() const { return m_doc->title(); } void SessionManagerBase::practiceStarted() { qDebug() << "start practice timer"; m_time.start(); } void SessionManagerBase::practiceFinished() { m_totalTime = m_time.elapsed(); - qDebug() << "stop practice timer" << m_totalTime << m_time.toString(); + qDebug() << "stop practice timer" << m_totalTime; } int SessionManagerBase::totalTime() { // seconds instead of ms return m_totalTime / (1000); } TestEntry* SessionManagerBase::nextTrainingEntry() { // In some session types an entry will move out of the "current // entries" when they are correctly answered and then we need to // refill. while (m_currentEntries.count() < Prefs::testNumberOfEntries() && m_notAskedTestEntries.count() > 0) { m_currentEntries.append(m_notAskedTestEntries.takeAt(0)); } // Return one of the current entries, but not the same as last // time if possible. int lastEntry = m_currentEntry; if (m_currentEntries.count() > 0) { // Choose one of the current entries randomly. m_currentEntry = KRandom::random() % m_currentEntries.count(); // Do not allow to ask the same entry twice in a row. if (m_currentEntries.count() > 1) { while (m_currentEntry == lastEntry) { m_currentEntry = KRandom::random() % m_currentEntries.count(); } } qDebug() << "nextTrainingEntry:" << m_currentEntry << " = " << m_currentEntries.value(m_currentEntry)->entry()->translation(0)->text() << " (" << m_currentEntries.count() + m_notAskedTestEntries.count() << "entries remaining)"; return m_currentEntries.value(m_currentEntry); } else { return 0; } } void SessionManagerBase::removeCurrentEntryFromPractice() { if (m_currentEntry >= 0) { m_currentEntries.takeAt(m_currentEntry); } } QList SessionManagerBase::allTestEntries() const { return m_allTestEntries; } int SessionManagerBase::allEntryCount() const { return m_allTestEntries.count(); } int SessionManagerBase::activeEntryCount() { return m_notAskedTestEntries.count() + m_currentEntries.count(); } QList SessionManagerBase::allUnansweredTestEntries() { QList result; result.append(m_notAskedTestEntries); result.append(m_currentEntries); return result; } // ---------------------------------------------------------------- // Statistics int SessionManagerBase::statisticTotalCorrectFirstAttempt() { int count = 0; foreach(TestEntry * entry, m_allTestEntries) { if (entry->correctAtFirstAttempt()) { count++; } } return count; } int SessionManagerBase::statisticTotalWrong() { int count = 0; foreach(TestEntry * entry, m_allTestEntries) { if (entry->statisticBadCount()) { count++; } } return count; } int SessionManagerBase::statisticTotalUnanswered() { int count = 0; foreach(TestEntry * entry, m_allTestEntries) { if (entry->statisticCount() == 0) { count++; } } return count; } void SessionManagerBase::printStatistics() { qDebug() << "Test statistics: "; foreach(TestEntry * entry, m_allTestEntries) { qDebug() << " asked: " << entry->statisticCount() << " +" << entry->statisticGoodCount() << " -" << entry->statisticBadCount() << "Entry: " << entry->entry()->translation(0)->text(); } } // ---------------------------------------------------------------- // Multiple choice questions QStringList SessionManagerBase::multipleChoiceAnswers(int numberChoices) { QStringList choices; QList allEntries = m_doc->lesson()->entries(KEduVocLesson::Recursive); int numValidEntries = 0; int count = numberChoices; // if the current entry has predefined multiple choice entries defined, use them first TestEntry *currentEntry = m_currentEntries.at(m_currentEntry); QStringList predefinedChoices = currentEntry->entry()->translation(currentEntry->languageTo())->getMultipleChoice(); while (!predefinedChoices.isEmpty() && count > 0) { choices.append(predefinedChoices.takeAt(KRandom::random() % predefinedChoices.count())); count--; } // find out if we got enough valid entries to fill all the options for (int i = 0; i < allEntries.count(); ++i) { if (isValidMultipleChoiceAnswer(allEntries.value(i))) numValidEntries++; if (numValidEntries >= numberChoices) break; } // if we don't have enough valid entries, just try everything and use what we can get if (numValidEntries < numberChoices) { for (int i = choices.count(); i < allEntries.count(); ++i) { KEduVocExpression *exp = allEntries.value(i); // FIXME: Use trainingmode2 also here! if (isValidMultipleChoiceAnswer(exp)) { choices.append(exp->translation(currentEntry->languageTo())->text()); } } } else { QList exprlist; while (count > 0) { int nr; // if there are enough non-empty fields, fill the options only with those do { nr = KRandom::random() % allEntries.count(); } while (!isValidMultipleChoiceAnswer(allEntries.value(nr))); // append if new entry found bool newex = true; for (int i = 0; newex && i < exprlist.count(); i++) { if (exprlist[i] == allEntries.value(nr)) newex = false; } if (newex) { count--; exprlist.append(allEntries.value(nr)); } } // FIXME: Use trainingmode2 too here for (int i = 0; i < exprlist.count(); i++) { choices.append(exprlist[i]->translation(currentEntry->languageTo())->text()); } } qDebug() << "choices:" << choices << " answerLang = " << currentEntry->languageTo() ; return choices; } // ---------------------------------------------------------------- // Protected methods bool SessionManagerBase::isValidMultipleChoiceAnswer(KEduVocExpression *e) { // entry is empty if (e->translation(m_learningLanguageIndex)->text().trimmed().isEmpty()) return false; // FIXME: Must test individual solution & question languages per // entry in mixed mode training. // // entry is a synonym of the solution if (e->translation(m_learningLanguageIndex)->synonyms().contains(m_currentEntries.at(m_currentEntry)->entry()->translation(m_learningLanguageIndex))) return false; // Entry has the same text as the solution. if (e->translation(m_learningLanguageIndex)->text().simplified() == m_currentEntries.at(m_currentEntry)->entry()->translation(m_learningLanguageIndex)->text().simplified()) return false; return true; } diff --git a/src/practice/sessionmanagerbase.h b/src/practice/sessionmanagerbase.h index 3eedf901..a7481c6b 100644 --- a/src/practice/sessionmanagerbase.h +++ b/src/practice/sessionmanagerbase.h @@ -1,173 +1,173 @@ /*************************************************************************** copyright : (C) 1999-2001 Ewald Arnold (C) 2005-2007 Peter Hedlund (C) 2007-2010 Frederik Gladhorn (C) 2014 Inge Wallin ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #ifndef PRACTICESESSIONMANAGERBASE_H #define PRACTICESESSIONMANAGERBASE_H // Qt #include - +#include // kdeedulibs #include // Parley #include "testentry.h" #include "prefs.h" class KEduVocDocument; namespace Practice { class SessionManagerBase { public: /** * Create a collection of entries to be practiced. */ explicit SessionManagerBase(QWidget *parent); /** * destructor */ virtual ~SessionManagerBase(); /** * Prepare for practice using the entries in this document. * * The default implementation selects all available entries in the * document into the list allTestEntries and then calls * initializeTraining(). */ virtual void setDocument(KEduVocDocument *doc); /** * Initialize the lists of entries that will be used in the * training from the full set of available entries. Reimplement * this to create other types of training sessions. */ virtual void initializeTraining() = 0; /** * Return the title of the document. */ QString title() const; // Should be called when starting and ending the practice session respectively. // The default implementations only start and stop the practice timer. virtual void practiceStarted(); virtual void practiceFinished(); /** the time in seconds */ int totalTime(); /** * Get the next entry to show to the user. The default * implementation refills the active entries up to the max number * and selects a random entry from them. * * @return TestEntry* the next entry to be practiced */ virtual TestEntry* nextTrainingEntry(); /** Finish the currently active entry */ virtual void removeCurrentEntryFromPractice(); /** * Get a list of all entries in the test - used by the summary dialog */ QList allTestEntries() const; /** * The number of entries available for the practice session. * This is used for statistics at the end of the session. * @return */ int allEntryCount() const; /** * The number of entries that are still to be practiced * @return */ int activeEntryCount(); /** * Get a list of all unanswered entries in the test */ QList allUnansweredTestEntries(); // ---------------------------------------------------------------- // Statistics int statisticTotalCorrectFirstAttempt(); int statisticTotalWrong(); int statisticTotalUnanswered(); /** * Puts some grades on the shell */ void printStatistics(); QStringList multipleChoiceAnswers(int numberChoices); //QString currentConjugationTense(); protected: // methods /** * Find out if the given expression can be used as a multiple choice answer for the current entry * (i.e. if it's not the answer itself, not a synonym and has a different text) */ bool isValidMultipleChoiceAnswer(KEduVocExpression *e); protected: // data KEduVocDocument *m_doc; QWidget *m_parent; int m_learningLanguageIndex; int m_knownLanguageIndex; int m_testType; // ---------------------------------------------------------------- // The following entries define the training /// All entries available in the document that fulfill the /// requirements set in the configuration and the grades in the /// entries themselves. QList m_allTestEntries; /// All entries that have not been entered into the active set. QList m_notAskedTestEntries; /// The list of entries that are being asked. If one of these is /// done, it can be deleted and an new one from /// m_notAskedTestEntries taken. QList m_currentEntries; // The index of the current entry in m_currentEntries. int m_currentEntry; - QTime m_time; + QElapsedTimer m_time; int m_totalTime; }; } #endif // kvtquery_included