You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/klatin/klatin/klatinvocab.cpp

399 lines
9.9 KiB

/***************************************************************************
begin : Thu Jul 17
copyright : (C) 2001-2004 by George Wright
email : gwright@kde.org
***************************************************************************/
/***************************************************************************
* *
* 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 <tqdir.h>
#include <tqlabel.h>
#include <tqlistview.h>
#include <tdeapplication.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>
#include <kstandarddirs.h>
#include <kstdguiitem.h>
#include <stdlib.h>
#include <time.h>
#include "klatinvocab.h"
#include "settings.h"
KLatinVocab::KLatinVocab(TQWidget* parent, const char *name)
: KLatinVocabWidget(parent, name)
{
BackButton->setIconSet(TDEGlobal::iconLoader()->loadIconSet("back", TDEIcon::Small));
m_vocabFile = TQString();
// Goes back to the last dialog
connect(BackButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(goBack()));
// Set default settings
m_numberOfQuestions = Settings::numOfQuestions();
m_total = 0;
m_totalCorrect = 0;
m_questionNumber = 0;
m_dialogShown = true;
// Parse the kvtml vocab file
parseVocab();
// Connect the multiple choice buttons to the various slots
connect(Answer1, TQT_SIGNAL(clicked()), this, TQT_SLOT(checkAnswerOne()));
connect(Answer2, TQT_SIGNAL(clicked()), this, TQT_SLOT(checkAnswerTwo()));
connect(Answer3, TQT_SIGNAL(clicked()), this, TQT_SLOT(checkAnswerThree()));
connect(Answer4, TQT_SIGNAL(clicked()), this, TQT_SLOT(checkAnswerFour()));
}
KLatinVocab::~KLatinVocab()
{
}
void KLatinVocab::parseVocab(TQString customFile)
{
m_vocabFile = customFile;
m_texts.clear();
TQString fileName;
// Load all the config variables
if (Settings::numOfQuestions() != 0) {
m_numberOfQuestions = Settings::numOfQuestions();
}
// Load default file as defined in settings
fileName = Settings::defaultFile();
kdDebug() << fileName << endl;
if (!customFile.isNull())
fileName = customFile;
// Check whether file exists or not
// If not then regenerate working default
if (TQFile::exists(fileName) == FALSE) {
TDEConfigBase *globalConf = TDEGlobal::config();
globalConf->setGroup("Locale");
TQString language = globalConf->readEntry("Language", "en");
language = language.left(2);
TQString fileNameLang = locate("data", "klatin/data/vocabs/");
fileNameLang += language;
TQDir checkLang(fileNameLang);
if (checkLang.exists() == FALSE) {
language = "en";
}
TQDir vocabDirectory(fileNameLang, "*.kvtml");
TQString defaultFile = (fileNameLang + "/" + vocabDirectory[0]);
if (TQFile::exists(defaultFile) == FALSE) {
KMessageBox::error(this, i18n("Could not load vocabulary file; there is a problem with your KLatin installation."), i18n("Error with KLatin"));
kapp->quit();
} else {
fileName = defaultFile;
Settings::setDefaultFile(defaultFile);
}
}
// Load XML file into memory
KEduVocDataItemList vocabulary = KEduVocData::parse(fileName);
int it = 0;
// Start parsing file and allocating words to the TQValueList<TQStringPair>
for(KEduVocDataItemList::Iterator dataIt = vocabulary.begin(); dataIt != vocabulary.end(); ++dataIt) {
if (Settings::langToLatin()) {
m_texts.append(tqMakePair(vocabulary[it].originalText(), vocabulary[it].translatedText()));
} else {
m_texts.append(tqMakePair(vocabulary[it].translatedText(), vocabulary[it].originalText()));
}
it++;
}
// Number of words in the list
m_numberOfWords = it - 1;
// Create a random sequence to follow in the test
createRandomSequence();
// Ask a question
newQuestion();
}
void KLatinVocab::createRandomSequence()
{
// Seed the random number generator
srandom(time(NULL));
// This works by assigning an array with 1, 2, 3, 4, 5 etc
// and then shuffling them into m_sequence.
// This sequence is then followed for testing purposes
// TODO Change implementation to use KRandomSequence
int i;
int randomSequence[256];
m_numberOfQuestions++;
for (i = 0; i < m_numberOfWords; i++) {
randomSequence[i] = i;
}
// Courtesy of Neil Stevens
for (i = 0; i < m_numberOfQuestions * 2; i++) {
const int x = i % m_numberOfWords;
const int y = x + (rand() % (m_numberOfWords - x));
const int swap = randomSequence[x];
randomSequence[x] = randomSequence[y];
randomSequence[y] = swap;
}
if (m_numberOfQuestions <= m_numberOfWords) {
for (i = 0; i < m_numberOfQuestions; i++) {
m_sequence[i] = randomSequence[i];
}
}
if (m_numberOfQuestions > m_numberOfWords) {
int j = 0;
for (i = 0; i < m_numberOfQuestions; i++) {
if (j < m_numberOfWords) {
m_sequence[i] = randomSequence[j];
j++;
}
if (j >= m_numberOfWords) {
j = 0;
}
}
}
}
void KLatinVocab::newQuestion()
{
int randNum = 0;
// If we have already asked the number of questions required
// then show the results dialogue
if (m_questionNumber == (m_numberOfQuestions - 1)) {
resultsDialog();
return;
}
// Seed the random number generator
srandom(time(NULL));
// Grab number from random sequence
randNum = m_sequence[m_questionNumber];
QuestionLabel->setText(m_texts[randNum].first);
m_previousQuestion += QuestionLabel->text();
// Initialise a couple of temporary variables
int i = 0, j = 0, tempRand[4];
bool override = FALSE;
// Assign m_choiceWords with the 4 words
// to go into the multiple choice. Make sure
// none of them are the same.
while (i < 4) {
tempRand[i] = (random() % (m_numberOfWords - 1)) + 1;
if (i > 0) {
j = 0;
while (j < i) {
if (tempRand[j] == tempRand[i]) {
tempRand[i] = (random() % (m_numberOfWords - 1)) + 1;
} else
j++;
}
}
i++;
}
// Assign the four words to m_choiceWords.
if (m_choiceWords.count() == 0) {
for (i = 0; i < 4; i++)
m_choiceWords += m_texts[tempRand[i]].second;
m_choiceWords += m_texts[randNum].second;
} else {
for (i = 0; i < 4; i++)
m_choiceWords[i] = m_texts[tempRand[i]].second;
m_choiceWords[4] = m_texts[randNum].second;
}
// Make sure the actual answer isn't already in m_choiceWords
// If it is, set override to be TRUE
for (i = 0; i < 4; i++) {
if (m_choiceWords[4] == m_choiceWords[i]) {
m_lastAnswerNumber = i;
override = TRUE;
}
}
bool exitLoop = FALSE;
// Override a random variable with the correct
// answer
if (!override) {
int answerNumber = (random() % 3);
while (!exitLoop) {
if (answerNumber != m_lastAnswerNumber) {
m_choiceWords[answerNumber] = m_texts[randNum].second;
m_lastAnswerNumber = answerNumber;
exitLoop = TRUE;
} else {
answerNumber = (random() % 3);
}
}
}
// Add the correct answer to the list (for use
// when the results dialogue is called)
m_correctAnswer += m_choiceWords[4];
// The four values that will go into the four
// Option boxes.
Answer1->setText(m_choiceWords[0]);
Answer2->setText(m_choiceWords[1]);
Answer3->setText(m_choiceWords[2]);
Answer4->setText(m_choiceWords[3]);
// We have now asked another question so iterate this int.
m_questionNumber++;
}
// Slots
void KLatinVocab::goBack()
{
// If the dialogue isn't already shown then show it
if (!m_dialogShown)
resultsDialog();
emit exited();
close();
}
// Slots for each of the multiple choice buttons
void KLatinVocab::checkAnswer(int button)
{
m_dialogShown = false;
if (m_choiceWords[button] == m_choiceWords[4]) {
// Update the total answered correctly
m_totalCorrect++;
}
// Update the total questions faced
m_total++;
m_previousAnswer += m_choiceWords[button];
updateScores();
// Setup a new question
newQuestion();
}
// TODO Use one slot and check the sender() instead
void KLatinVocab::checkAnswerOne()
{
checkAnswer(0);
}
void KLatinVocab::checkAnswerTwo()
{
checkAnswer(1);
}
void KLatinVocab::checkAnswerThree()
{
checkAnswer(2);
}
void KLatinVocab::checkAnswerFour()
{
checkAnswer(3);
}
void KLatinVocab::updateScores()
{
// Update the score labels
Score1Label->setNum(m_totalCorrect);
Score2Label->setNum(m_total);
// Set percentage
PercentageLabel->setText(TQString::number(int(double(m_totalCorrect) / m_total * 100))+TQString("%"));
}
void KLatinVocab::resultsDialog()
{
// Show the results dialog
results = new KLatinResultsDialog(this, 0, TRUE);
results->CloseButton->setGuiItem(KStdGuiItem::close());
int temp = Score2Label->text().toInt();
// Set the lists
for (int i = 0 ; i < temp; i++) {
if (m_previousAnswer[i] != 0)
new TQListViewItem(results->ResultsView, m_previousQuestion[i], m_previousAnswer[i], m_correctAnswer[i]);
}
// Set the scores
results->PercentageValue->setText(PercentageLabel->text());
results->AttemptedValue->setText(Score2Label->text());
results->show();
results->resize(TQSize(420, 280));
// Set some variables.
m_dialogShown = true;
changeVocab(Settings::defaultFile());
}
void KLatinVocab::changeVocab(const TQString &filename)
{
// Reset to defaults
m_total = 0;
m_totalCorrect = 0;
m_questionNumber = 0;
m_numberOfQuestions = Settings::numOfQuestions();
// Reset the StringLists as we are now on a new testing session
m_correctAnswer.clear();
m_previousAnswer.clear();
m_previousQuestion.clear();
// Reset score labels
Score1Label->setNum(m_totalCorrect);
Score2Label->setNum(m_total);
PercentageLabel->setText(0);
// Load the vocabulary file again (and thus create a new random sequence)
parseVocab(filename);
}
#include "klatinvocab.moc"