|
|
|
|
/***************************************************************************
|
|
|
|
|
* ktouchtrainer.cpp *
|
|
|
|
|
* ----------------- *
|
|
|
|
|
* Copyright (C) 2000 by Håvard Frøiland, 2006 by Andreas Nicolai *
|
|
|
|
|
* ghorwin@users.sourceforge.net *
|
|
|
|
|
* *
|
|
|
|
|
* 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 "ktouchtrainer.h"
|
|
|
|
|
#include "ktouchtrainer.moc"
|
|
|
|
|
|
|
|
|
|
#include <tqlcdnumber.h>
|
|
|
|
|
#include <tqfile.h>
|
|
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
#include <kpushbutton.h>
|
|
|
|
|
#include <klocale.h>
|
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
|
#include <kaudioplayer.h>
|
|
|
|
|
#include <tqmessagebox.h>
|
|
|
|
|
|
|
|
|
|
#include "ktouch.h"
|
|
|
|
|
#include "ktouchstatus.h"
|
|
|
|
|
#include "ktouchslideline.h"
|
|
|
|
|
#include "ktouchkeyboardwidget.h"
|
|
|
|
|
#include "ktouchlecture.h"
|
|
|
|
|
#include "ktouchdefaults.h"
|
|
|
|
|
#include "prefs.h"
|
|
|
|
|
|
|
|
|
|
KTouchTrainer::KTouchTrainer(KTouchStatus *status, KTouchSlideLine *slideLine, KTouchKeyboardWidget *keyboard, KTouchLecture *lecture)
|
|
|
|
|
: TQObject(),
|
|
|
|
|
m_trainingTimer(new TQTimer),
|
|
|
|
|
m_statusWidget(status),
|
|
|
|
|
m_slideLineWidget(slideLine),
|
|
|
|
|
m_keyboardWidget(keyboard),
|
|
|
|
|
m_lecture(lecture)
|
|
|
|
|
{
|
|
|
|
|
m_level = 0; // level 1, but we're storing it zero based
|
|
|
|
|
m_line = 0;
|
|
|
|
|
m_wordsInCurrentLine = 0;
|
|
|
|
|
m_trainingPaused=true; // we start in pause mode
|
|
|
|
|
m_teacherText=m_lecture->level(0).line(0);
|
|
|
|
|
m_studentText="";
|
|
|
|
|
|
|
|
|
|
// reset statistics
|
|
|
|
|
m_levelStats.clear();
|
|
|
|
|
m_sessionStats.clear();
|
|
|
|
|
|
|
|
|
|
/// \todo preload sounds and improve sound playback system
|
|
|
|
|
m_levelUpSound = KGlobal::dirs()->findResource("appdata","up.wav");
|
|
|
|
|
m_levelDownSound = KGlobal::dirs()->findResource("appdata","down.wav");
|
|
|
|
|
m_typeWriterSound = KGlobal::dirs()->findResource("appdata","typewriter.wav");
|
|
|
|
|
|
|
|
|
|
connect(m_statusWidget->levelUpBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(levelUp()) );
|
|
|
|
|
connect(m_statusWidget->levelDownBtn, TQT_SIGNAL(clicked()), this, TQT_SLOT(levelDown()) );
|
|
|
|
|
connect(m_trainingTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(timerTick()) );
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
KTouchTrainer::~KTouchTrainer() {
|
|
|
|
|
delete m_trainingTimer;
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::gotoFirstLine() {
|
|
|
|
|
m_statusWidget->setNewChars( m_lecture->level(m_level).newChars() );
|
|
|
|
|
m_line=0;
|
|
|
|
|
newLine();
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::keyPressed(TQChar key) {
|
|
|
|
|
// NOTE : In this function we need to distinguish between left and right
|
|
|
|
|
// typing. Use the config setting Prefs::right2LeftTyping() for that.
|
|
|
|
|
|
|
|
|
|
if (m_trainingPaused) continueTraining();
|
|
|
|
|
if (m_teacherText==m_studentText) {
|
|
|
|
|
// if already at end of line, don't add more chars
|
|
|
|
|
/// \todo Flash the line when line complete
|
|
|
|
|
if (Prefs::beepOnError()) TQApplication::beep();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// remember length of student text without added character
|
|
|
|
|
unsigned int old_student_text_len = m_studentText.length();
|
|
|
|
|
// compose new student text depending in typing direction
|
|
|
|
|
TQString new_student_text = m_studentText;
|
|
|
|
|
if (Prefs::right2LeftTyping())
|
|
|
|
|
new_student_text = key + new_student_text;
|
|
|
|
|
else
|
|
|
|
|
new_student_text += key;
|
|
|
|
|
|
|
|
|
|
// don´t allow excessive amounts of characters per line
|
|
|
|
|
if (!m_slideLineWidget->canAddCharacter(new_student_text)) {
|
|
|
|
|
if (Prefs::beepOnError()) TQApplication::beep();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// store the new student text
|
|
|
|
|
m_studentText = new_student_text;
|
|
|
|
|
// we need to find out, if the key was correct or not
|
|
|
|
|
if (studentLineCorrect())
|
|
|
|
|
statsAddCorrectChar(key); // ok, all student text is correct
|
|
|
|
|
else {
|
|
|
|
|
// nope, the key was wrong : beep !!!
|
|
|
|
|
if (Prefs::beepOnError()) TQApplication::beep();
|
|
|
|
|
// check if the key is the first wrong key that was mistyped. Only then add it
|
|
|
|
|
// to the wrong char statistics.
|
|
|
|
|
if (Prefs::right2LeftTyping()) {
|
|
|
|
|
if (m_teacherText.right(old_student_text_len)==m_studentText.right(old_student_text_len) &&
|
|
|
|
|
m_teacherText.length() > old_student_text_len)
|
|
|
|
|
{
|
|
|
|
|
// add the key the student ought to press to the wrong character stats
|
|
|
|
|
int next_key_index = m_teacherText.length() - old_student_text_len;
|
|
|
|
|
// kdDebug() << "Wrong key = " << m_teacherText[next_key_index] << endl;
|
|
|
|
|
statsAddWrongChar( m_teacherText[next_key_index] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (m_teacherText.left(old_student_text_len)==m_studentText.left(old_student_text_len) &&
|
|
|
|
|
m_teacherText.length() > old_student_text_len)
|
|
|
|
|
{
|
|
|
|
|
// add the key the student ought to press to the wrong character stats
|
|
|
|
|
int next_key_index = old_student_text_len;
|
|
|
|
|
statsAddWrongChar( m_teacherText[next_key_index] );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// \todo Implement option whether subsequent mistyped keys should be remembered as missed
|
|
|
|
|
/// keys as well.
|
|
|
|
|
}
|
|
|
|
|
updateWidgets(); // update all the other widgets (keyboard widget, status widget and statusbar)
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::backspacePressed() {
|
|
|
|
|
if (m_trainingPaused) continueTraining();
|
|
|
|
|
/// \todo Implement the "remove space character = remove word count" feature
|
|
|
|
|
|
|
|
|
|
unsigned int len = m_studentText.length();
|
|
|
|
|
if (len) {
|
|
|
|
|
if (m_teacherText.left(len)==m_studentText && m_teacherText.length()>=len) {
|
|
|
|
|
// we are removing a correctly typed char
|
|
|
|
|
statsRemoveCorrectChar(m_studentText[len-1]);
|
|
|
|
|
}
|
|
|
|
|
m_studentText = m_studentText.left(--len);
|
|
|
|
|
updateWidgets(); // update all the widgets and the word count
|
|
|
|
|
if (m_teacherText.left(len)==m_studentText)
|
|
|
|
|
m_keyboardWidget->newKey(m_teacherText[len]);
|
|
|
|
|
else
|
|
|
|
|
m_keyboardWidget->newKey(TQChar(8));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/// \todo Flash line when Backspace on empty line
|
|
|
|
|
TQApplication::beep();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::enterPressed() {
|
|
|
|
|
if (m_trainingPaused) continueTraining();
|
|
|
|
|
if (m_studentText!=m_teacherText) {
|
|
|
|
|
TQApplication::beep();
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
// NOTE : auto level change inside level was removed due to popular request
|
|
|
|
|
|
|
|
|
|
if (Prefs::autoLevelChange()) {
|
|
|
|
|
// if level increase criterion was fulfilled, increase line counter
|
|
|
|
|
if (Prefs::upCorrectLimit() <= m_session.correctness()*100 &&
|
|
|
|
|
Prefs::upSpeedLimit() <= m_session.charSpeed())
|
|
|
|
|
{
|
|
|
|
|
m_decLinesCount=0;
|
|
|
|
|
++m_incLinesCount;
|
|
|
|
|
}
|
|
|
|
|
else if (Prefs::downCorrectLimit() > m_session.correctness()*100 ||
|
|
|
|
|
Prefs::downSpeedLimit() > m_session.charSpeed())
|
|
|
|
|
{
|
|
|
|
|
m_incLinesCount=0;
|
|
|
|
|
++m_decLinesCount;
|
|
|
|
|
};
|
|
|
|
|
// Automatic level change after a number of lines can happen, if you fulfilled the
|
|
|
|
|
// requirements in the last 5 lines.
|
|
|
|
|
if (m_incLinesCount>=2) {
|
|
|
|
|
levelUp();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (m_decLinesCount>=2 && m_level!=0) {
|
|
|
|
|
levelDown();
|
|
|
|
|
return;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if we are in the last line
|
|
|
|
|
if (m_line+1 >= m_lecture->level(m_level).count()) {
|
|
|
|
|
if (Prefs::autoLevelChange()) {
|
|
|
|
|
// adjust level if limits exceeded
|
|
|
|
|
if (Prefs::upCorrectLimit() <= m_levelStats.correctness()*100 &&
|
|
|
|
|
Prefs::upSpeedLimit() <= m_levelStats.charSpeed())
|
|
|
|
|
{
|
|
|
|
|
/// \todo Test if last level is done and show message, stop training, show statistics etc.
|
|
|
|
|
levelUp(); // level change takes care of updating word count
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (Prefs::downCorrectLimit() > m_levelStats.correctness()*100 ||
|
|
|
|
|
Prefs::downSpeedLimit() > m_levelStats.charSpeed())
|
|
|
|
|
{
|
|
|
|
|
levelDown(); // level change takes care of updating word count
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// we have to store the word count before continuing in the first line
|
|
|
|
|
updateWordCount();
|
|
|
|
|
m_levelStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
m_sessionStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
gotoFirstLine(); // restart in the new/current level
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// store the word count
|
|
|
|
|
updateWordCount();
|
|
|
|
|
m_levelStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
m_sessionStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
++m_line;
|
|
|
|
|
newLine(); // otherwise show next line
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::updateWidgets() {
|
|
|
|
|
// update status widget
|
|
|
|
|
m_statusWidget->updateStatus(m_level, m_levelStats.correctness());
|
|
|
|
|
// update slide line widget
|
|
|
|
|
m_slideLineWidget->setStudentText(m_studentText);
|
|
|
|
|
// update keyboard widget -> show next to be pressed char.
|
|
|
|
|
// we have to find out first whether the student text is correct or not.
|
|
|
|
|
if (studentLineCorrect()) {
|
|
|
|
|
// ok, all student text is correct
|
|
|
|
|
if (m_teacherText.length()==m_studentText.length())
|
|
|
|
|
m_keyboardWidget->newKey(TQChar(13)); // we have reached the end of the line
|
|
|
|
|
else
|
|
|
|
|
m_keyboardWidget->newKey(m_teacherText[m_studentText.length()]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
m_keyboardWidget->newKey(TQChar(8)); // wrong key, user must now press backspace
|
|
|
|
|
}
|
|
|
|
|
updateWordCount(); // here we first update the word count
|
|
|
|
|
updateStatusBar(); // and then the status bar
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::startTraining(bool keepLevel) {
|
|
|
|
|
// Here we start a new training session.
|
|
|
|
|
|
|
|
|
|
// keep the current level if flag is set
|
|
|
|
|
if (!keepLevel)
|
|
|
|
|
m_level=0;
|
|
|
|
|
// reset the level and session statistics
|
|
|
|
|
m_levelStats.clear();
|
|
|
|
|
m_sessionStats.clear();
|
|
|
|
|
// transfer level to level statistics
|
|
|
|
|
m_levelStats.m_levelNum = m_level;
|
|
|
|
|
// remember level in session stats
|
|
|
|
|
m_sessionStats.m_levelNums.insert(m_level);
|
|
|
|
|
// go to first line in level (also resets word count)
|
|
|
|
|
gotoFirstLine();
|
|
|
|
|
updateStatusBarMessage(i18n("Starting training session: Waiting for first keypress...") );
|
|
|
|
|
updateStatusBar();
|
|
|
|
|
m_statusWidget->updateStatus(m_level, 1);
|
|
|
|
|
m_statusWidget->speedLCD->display( 0 );
|
|
|
|
|
m_trainingPaused=true; // Go into "Pause" mode
|
|
|
|
|
m_trainingTimer->stop(); // Training timer will be started on first keypress.
|
|
|
|
|
m_slideLineWidget->setCursorTimerEnabled(true); // Curser will blink
|
|
|
|
|
updateLevelChangeButtons();
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Pauses the current training session.
|
|
|
|
|
// This function is called from class KTouch (when the Pause action is executed).
|
|
|
|
|
void KTouchTrainer::pauseTraining() {
|
|
|
|
|
m_trainingPaused=true;
|
|
|
|
|
m_trainingTimer->stop();
|
|
|
|
|
m_slideLineWidget->setCursorTimerEnabled(false);
|
|
|
|
|
m_statusWidget->updateStatus(m_level, m_levelStats.correctness());
|
|
|
|
|
m_statusWidget->speedLCD->display( m_levelStats.charSpeed() );
|
|
|
|
|
updateStatusBarMessage(i18n("Training session paused. Training continues on next keypress...") );
|
|
|
|
|
updateStatusBar();
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
// Continues the current training session.
|
|
|
|
|
// This function is called from class KTouch when a user presses a normal key
|
|
|
|
|
// while the training is in pause mode.
|
|
|
|
|
void KTouchTrainer::continueTraining() {
|
|
|
|
|
m_trainingPaused=false;
|
|
|
|
|
m_slideLineWidget->setCursorTimerEnabled(true);
|
|
|
|
|
m_statusWidget->updateStatus(m_level, m_levelStats.correctness() );
|
|
|
|
|
m_statusWidget->speedLCD->display( m_levelStats.charSpeed() );
|
|
|
|
|
updateStatusBarMessage(i18n("Training session! The time is running...") );
|
|
|
|
|
updateStatusBar();
|
|
|
|
|
m_trainingTimer->start(LCD_UPDATE_INTERVAL); // start the timer
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::storeTrainingStatistics() {
|
|
|
|
|
// at first get a reference to the statistics data of the current lecture
|
|
|
|
|
KTouchLectureStats& data = KTouchPtr->getCurrentLectureStats();
|
|
|
|
|
// update word count
|
|
|
|
|
updateWordCount();
|
|
|
|
|
// add word count to level and session statistics
|
|
|
|
|
m_levelStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
m_sessionStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
// are there level stats to be stored?
|
|
|
|
|
if (m_levelStats.m_elapsedTime != 0) {
|
|
|
|
|
//kdDebug() << "[KTouchTrainer::storeTrainingStatistics] Storing level statistics!" << endl;
|
|
|
|
|
m_levelStats.m_timeRecorded = TQDateTime::currentDateTime();
|
|
|
|
|
data.m_levelStats.push_back( m_levelStats );
|
|
|
|
|
}
|
|
|
|
|
if (m_sessionStats.m_elapsedTime != 0) {
|
|
|
|
|
//kdDebug() << "[KTouchTrainer::storeTrainingStatistics] Storing session statistics!" << endl;
|
|
|
|
|
m_sessionStats.m_timeRecorded = TQDateTime::currentDateTime();
|
|
|
|
|
data.m_sessionStats.push_back( m_sessionStats );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
bool KTouchTrainer::studentLineCorrect() const {
|
|
|
|
|
if (m_teacherText.isEmpty())
|
|
|
|
|
return m_studentText.isEmpty();
|
|
|
|
|
unsigned int len = m_studentText.length();
|
|
|
|
|
// different check for left and right writing
|
|
|
|
|
if (Prefs::right2LeftTyping())
|
|
|
|
|
return m_teacherText.right(len)==m_studentText && m_teacherText.length()>=len;
|
|
|
|
|
else
|
|
|
|
|
return (m_teacherText.left(len)==m_studentText && m_teacherText.length()>=len);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *** Public slots ***
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::levelUp() {
|
|
|
|
|
KAudioPlayer::play(m_levelUpSound.url());
|
|
|
|
|
++m_level; // increase the level
|
|
|
|
|
if (m_level>=m_lecture->levelCount()) {
|
|
|
|
|
// already at max level? Let's stay there
|
|
|
|
|
m_level=m_lecture->levelCount()-1;
|
|
|
|
|
levelAllComplete();
|
|
|
|
|
/// \todo Do something when last level is completed
|
|
|
|
|
}
|
|
|
|
|
// Store level statistics if level is increased
|
|
|
|
|
statsChangeLevel();
|
|
|
|
|
gotoFirstLine();
|
|
|
|
|
updateLevelChangeButtons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::levelDown() {
|
|
|
|
|
if (m_level>0) {
|
|
|
|
|
--m_level;
|
|
|
|
|
KAudioPlayer::play(m_levelDownSound.url());
|
|
|
|
|
}
|
|
|
|
|
// Store level statistics if level is increased
|
|
|
|
|
statsChangeLevel();
|
|
|
|
|
gotoFirstLine();
|
|
|
|
|
updateLevelChangeButtons();
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::timerTick() {
|
|
|
|
|
if (m_trainingPaused) return;
|
|
|
|
|
// Add the timer interval. I think we can neglect the error we make when the session is
|
|
|
|
|
// paused and continued... it's not a scientific calculation, isn't it?
|
|
|
|
|
statsAddTime(LCD_UPDATE_INTERVAL*0.001);
|
|
|
|
|
// update only the widgets that are affected by progressing time
|
|
|
|
|
m_statusWidget->speedLCD->display( m_levelStats.charSpeed() );
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// *** Private functions ***
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::levelAllComplete() {
|
|
|
|
|
TQMessageBox::information(0, i18n("You rock!"),
|
|
|
|
|
i18n("You have finished this training exercise.\n"
|
|
|
|
|
"This training session will start from the beginning."));
|
|
|
|
|
statsChangeLevel();
|
|
|
|
|
startTraining(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::updateLevelChangeButtons() {
|
|
|
|
|
if (!Prefs::disableManualLevelChange()) {
|
|
|
|
|
m_statusWidget->levelUpBtn->setEnabled(m_level < m_lecture->levelCount() - 1);
|
|
|
|
|
m_statusWidget->levelDownBtn->setEnabled(m_level > 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void KTouchTrainer::newLine() {
|
|
|
|
|
m_teacherText = m_lecture->level(m_level).line(m_line);
|
|
|
|
|
m_studentText="";
|
|
|
|
|
m_wordsInCurrentLine = 0;
|
|
|
|
|
m_keyboardWidget->newKey(m_teacherText[0]);
|
|
|
|
|
m_slideLineWidget->setNewText(m_teacherText, m_studentText);
|
|
|
|
|
updateStatusBar(); // update status bar
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::updateStatusBar() const {
|
|
|
|
|
KTouchPtr->changeStatusbarStats(m_levelStats.m_correctChars, m_levelStats.m_totalChars,
|
|
|
|
|
m_levelStats.m_words + m_wordsInCurrentLine,
|
|
|
|
|
m_sessionStats.m_correctChars, m_sessionStats.m_totalChars,
|
|
|
|
|
m_sessionStats.m_words + m_wordsInCurrentLine);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::updateStatusBarMessage(const TQString& message) const {
|
|
|
|
|
KTouchPtr->changeStatusbarMessage(message);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::updateWordCount() {
|
|
|
|
|
// now update the m_wordsInCurrentLine variable
|
|
|
|
|
if (!studentLineCorrect()) return; // if error, don't update
|
|
|
|
|
int words = 0;
|
|
|
|
|
bool space = true;
|
|
|
|
|
for (unsigned int i=0; i<m_studentText.length(); ++i) {
|
|
|
|
|
bool is_space = (m_studentText[i] == TQChar(' '));
|
|
|
|
|
if (is_space) {
|
|
|
|
|
if (space) continue; // two spaces after each other... ignore
|
|
|
|
|
else {
|
|
|
|
|
++words;
|
|
|
|
|
space = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!space) continue; // two chars after each other... ignore
|
|
|
|
|
else {
|
|
|
|
|
space = false; // no need to add a word here.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// check if line is completely typed and add a word then
|
|
|
|
|
if (m_studentText == m_teacherText) ++words;
|
|
|
|
|
m_wordsInCurrentLine = words;
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::statsAddCorrectChar(TQChar key) {
|
|
|
|
|
m_levelStats.addCorrectChar(key);
|
|
|
|
|
m_sessionStats.addCorrectChar(key);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::statsAddWrongChar(TQChar key) {
|
|
|
|
|
m_levelStats.addWrongChar(key);
|
|
|
|
|
m_sessionStats.addWrongChar(key);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::statsRemoveCorrectChar(TQChar) {
|
|
|
|
|
m_levelStats.removeCorrectChar();
|
|
|
|
|
m_sessionStats.removeCorrectChar();
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::statsAddTime(double dt) {
|
|
|
|
|
m_levelStats.m_elapsedTime += dt;
|
|
|
|
|
m_sessionStats.m_elapsedTime += dt;
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
void KTouchTrainer::statsChangeLevel() {
|
|
|
|
|
//kdDebug() << "[KTouchTrainer::statsChangeLevel] First!" << endl;
|
|
|
|
|
// first update word count and store data in
|
|
|
|
|
updateWordCount();
|
|
|
|
|
//kdDebug() << "[KTouchTrainer::statsChangeLevel] Adding word count of " << m_wordsInCurrentLine << endl;
|
|
|
|
|
m_levelStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
m_sessionStats.m_words += m_wordsInCurrentLine;
|
|
|
|
|
// get a reference to the statistics data of the current lecture
|
|
|
|
|
KTouchLectureStats& data = KTouchPtr->getCurrentLectureStats();
|
|
|
|
|
// are there level stats to be stored?
|
|
|
|
|
if (m_levelStats.m_elapsedTime != 0) {
|
|
|
|
|
//kdDebug() << "[KTouchTrainer::storeTrainingStatistics] Storing level statistics!" << endl;
|
|
|
|
|
m_levelStats.m_timeRecorded = TQDateTime::currentDateTime();
|
|
|
|
|
data.m_levelStats.push_back( m_levelStats );
|
|
|
|
|
}
|
|
|
|
|
// clear level stats
|
|
|
|
|
m_levelStats.clear();
|
|
|
|
|
// transfer current level to level statistics
|
|
|
|
|
m_levelStats.m_levelNum = m_level;
|
|
|
|
|
// remember level in session stats
|
|
|
|
|
m_sessionStats.m_levelNums.insert(m_level);
|
|
|
|
|
// show new level (in status widet) and 100% correctness
|
|
|
|
|
m_statusWidget->updateStatus(m_level, 1);
|
|
|
|
|
}
|
|
|
|
|
// ----------------------------------------------------------------------------
|