/************************************************************************* * Bulgarian-English Dictionary * Copyright (C) 2000, 2001 Radostin Radnev * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "encodechar.h" #include "registry.h" #include "translator.h" #include "test.h" //=== Class Test ========================================================= // Written by Radostin Radnev - radnev@yahoo.com // $Id: test.cpp,v 1.7 2001/03/11 05:21:32 radnev Exp $ // // This is main test/exam window //======================================================================== // Some constants static const int MAX_ANSWER_LEN = 100; static const int MIN_LEFT_WIDTH = 100; static const int ADDITIONAL_WIDTH = 25; static const int ADDITIONAL_HEIGHT = 10; // Default options static const char DEFAULT_GEOMETRY[] = "50, 50, 350, 250"; static const int DEFAULT_TRANSLATE = 1; static const int DEFAULT_SHOW_ANSWER = 1; static const int DEFAULT_SESSION = 0; static const int DEFAULT_QUESTIONS = 100; static const int DEFAULT_LEVEL = 3; // Min and max allowed numbers static const int MIN_TRANSLATE = 1; static const int MAX_TRANSLATE = 2; static const int MIN_SHOW_ANSWER = 1; static const int MAX_SHOW_ANSWER = 5; static const int MIN_SESSION = 0; static const int MAX_SESSION = 1000000; static const int MIN_QUESTIONS = 10; static const int MAX_QUESTIONS = 10000; static const int MIN_LEVEL = 1; static const int MAX_LEVEL = 5; // Registry keys static const char OPTION_GEOMETRY[] = "Test.Geometry"; static const char OPTION_TRANSLATE[] = "Test.Translate"; static const char OPTION_SHOW_ANSWER[] = "Test.ShowAnswer"; static const char OPTION_SESSION[] = "Test.Session"; static const char OPTION_QUESTIONS[] = "Test.Questions"; static const char OPTION_LEVEL[] = "Test.Level"; // Welcome, help and other messages static const char CAPTION[] = QT_TR_NOOP("kbe Test"); static const char FOUND[] = QT_TR_NOOP(":)"); static const char NOT_FOUND[] = QT_TR_NOOP(":("); static const char END_OF_TEST[] = QT_TR_NOOP("End of session. Start again or exit."); static const char WELCOME_TEXT[] = QT_TR_NOOP("To begin test press button 'New Test'."); static const char HELP_TEXT[] = QT_TR_NOOP( "Enter answer that you think is correct.
" "Use comma (,) to separate two or more answers that you may have.
"); // Status Info and word format message static const char STATUS_INFO[] = QT_TR_NOOP(" Correct %1% ( %2 / %3 ) Asked %4% ( %5 / %6 )"); static const char ASKED[] = QT_TR_NOOP("%1. %2"); // Color objects static const QColor COLOR_FOUND(0, 255, 0); static const QColor COLOR_NOT_FOUND(255, 0, 0); static const int LEVEL_CHARS[] = {300, 200, 100, 50, 0}; //=== Constructor ======================================================== // Create GUI // Init objects and set default variables //======================================================================== Test::Test(QWidget *parent, const char *name, Translator *pDictionary, Registry *pReg, const QFont *pFont, const int pBorderWidth):QDialog(parent, name, true) { setCaption(tr(CAPTION)); dictionary = pDictionary; borderWidth = pBorderWidth; reg = pReg; font = QFont(*pFont); int X = 0, Y = 0, W = 0, H = 0; sscanf(DEFAULT_GEOMETRY, "%d, %d, %d, %d", &X, &Y, &W, &H); sscanf(reg->getString(OPTION_GEOMETRY, DEFAULT_GEOMETRY), "%d, %d, %d, %d", &X, &Y, &W, &H); resize(QSize(W, H)); move(QPoint(X, Y)); translate = reg->getInt(OPTION_TRANSLATE, DEFAULT_TRANSLATE, MIN_TRANSLATE, MAX_TRANSLATE); showAnswer = reg->getInt(OPTION_SHOW_ANSWER, DEFAULT_SHOW_ANSWER, MIN_SHOW_ANSWER, MAX_SHOW_ANSWER); session = reg->getInt(OPTION_SESSION, DEFAULT_SESSION, MIN_SESSION, MAX_SESSION); questions = reg->getInt(OPTION_QUESTIONS, DEFAULT_QUESTIONS, MIN_QUESTIONS, MAX_QUESTIONS); level = reg->getInt(OPTION_LEVEL, DEFAULT_LEVEL, MIN_LEVEL, MAX_LEVEL); current = questions + 1; correct = 0; // Create and set label question question = new QLabel(this); CHECK_PTR(question); question->setAlignment(QLabel::AlignLeft | QLabel::AlignVCenter); // Create and set Answer (text field) answer = new QLineEdit(W2U(""), this); CHECK_PTR(answer); answer->setMaxLength(MAX_ANSWER_LEN); connect(answer, SIGNAL(returnPressed()), this, SLOT(answer_EnterPressed())); // Create and set label word found = new QLabel(this); CHECK_PTR(found); found->setAlignment(QLabel::AlignCenter | QLabel::AlignVCenter); found->setFrameStyle(QFrame::Panel | QFrame::Sunken); // Create and set label word word = new QLabel(this); CHECK_PTR(word); word->setAlignment(QLabel::AlignLeft | QLabel::AlignVCenter); // Create and set button new test bnew = new QPushButton(tr("&New Test"), this); CHECK_PTR(bnew); connect(bnew, SIGNAL(clicked()), this, SLOT(button_New())); bnew->setFocusPolicy(QPushButton::NoFocus); bnew->setAutoDefault(false); // Create and set button close bclose = new QPushButton(tr("&Close"), this); CHECK_PTR(bclose); connect(bclose, SIGNAL(clicked()), this, SLOT(reject())); bclose->setFocusPolicy(QPushButton::NoFocus); bclose->setAutoDefault(false); // Create and set button help bhelp = new QPushButton(tr("&Help"), this); CHECK_PTR(bhelp); connect(bhelp, SIGNAL(clicked()), this, SLOT(button_Help())); bhelp->setFocusPolicy(QPushButton::NoFocus); bhelp->setAutoDefault(false); // Create and set result to show result = new QTextEdit(this); result->setReadOnly(true); CHECK_PTR(result); // Create and set label info info = new QLabel(this); CHECK_PTR(info); info->setAlignment(QLabel::AlignLeft | QLabel::AlignVCenter); info->setFrameStyle(QFrame::Panel | QFrame::Sunken); // Set size font and positions setView(); // Set focus answer->setFocus(); question->setText(tr(WELCOME_TEXT)); } // End of Constructor //=== Destructor ========================================================= // Save settings and geometry in registry file and free objects //======================================================================== Test::~Test() { reg->setInt(OPTION_TRANSLATE, translate); reg->setInt(OPTION_SHOW_ANSWER, showAnswer); reg->setInt(OPTION_SESSION, session); reg->setInt(OPTION_QUESTIONS, questions); reg->setInt(OPTION_LEVEL, level); if (!isMinimized()) { char val[32]; sprintf(val, "%d, %d, %d, %d", pos().x(), pos().y(), size().width(), size().height()); reg->setString(OPTION_GEOMETRY, val); } delete answer; delete bnew; delete bclose; delete bhelp; delete question; delete found; delete word; delete info; delete result; } // End of Destructor //=== Answer EnterPressed ================================================ // Perform enter pressed operation on answerd lineedit control //======================================================================== void Test::answer_EnterPressed() { if (current > questions) { // Do nothing answer->clear(); return; } // Clear fields result->clear(); // Check for new sessoin if (current == 0) { // Start new session if (session == 0) { srand(time(NULL)); } else { srand(session); } dictionary->setTestParameters(translate, LEVEL_CHARS[level - 1]); answer->clear(); word->clear(); found->clear(); found->setBackgroundColor(word->backgroundColor()); } else { // Check result if (dictionary->testWord(U2W(answer->text()))) { correct++; found->setBackgroundColor(COLOR_FOUND); found->setText(tr(FOUND)); } else { found->setBackgroundColor(COLOR_NOT_FOUND); found->setText(tr(NOT_FOUND)); if (((showAnswer == 2) && ((answer->text()).length() > 0)) || ((showAnswer == 3) && ((answer->text()).length() == 0)) || (showAnswer == 4)) { result->setText(W2U(dictionary->getResult())); result->sync(); result->setCursorPosition(0, 0); } } word->setText(answer->text()); answer->clear(); if (showAnswer == 1) { result->setText(W2U(dictionary->getResult())); result->sync(); result->setCursorPosition(0, 0); } } // Show status info->setText(tr(STATUS_INFO) .arg((current == 0 ? 0 : (correct*100)/current)) .arg(correct) .arg(current) .arg((questions == 0 ? 0 : (current*100)/questions)) .arg(current) .arg(questions)); // Increase current ponter current++; // Generata next random word or end of test if (current > questions) { question->setText(tr(END_OF_TEST)); } else { question->setText(tr(ASKED) .arg(current) .arg(W2U(dictionary->getNextRandomWord()))); } } // End of answer_EnterPressed //=== Button New ========================================================= // Start new test session //======================================================================== void Test::button_New() { QDialog options(this, "new", true); options.setCaption(tr("New Test")); QFontMetrics fm = options.fontMetrics(); int h = fm.height(); // Height of element int y = (h*2)/3; // Space between elements int x = h; // Space between left border and elements int w = h/3; // Space between two elements at one line int s = h; // Additional space between groups int m = 0; // Max width of element (Used for alignment) QLabel ltf(tr("Translate:"), &options); ltf.setAlignment(QLabel::AlignRight | QLabel::AlignVCenter); ltf.adjustSize(); ltf.move(x, y); QComboBox tf(false, &options); tf.insertItem(tr("From English To Bulgarian")); tf.insertItem(tr("From Bulgarian To English")); tf.setCurrentItem(translate - 1); tf.adjustSize(); tf.move(x + ltf.width() + w, y); QLabel lsa(tr("Show answer:"), &options); lsa.setAlignment(QLabel::AlignRight | QLabel::AlignVCenter); lsa.adjustSize(); lsa.move(x, tf.y() + tf.height() + y); QComboBox sa(false, &options); sa.insertItem(tr("Every time")); sa.insertItem(tr("In wrong answer")); sa.insertItem(tr("In empty answer")); sa.insertItem(tr("In wrong or empty answer")); sa.insertItem(tr("Never")); sa.setCurrentItem(showAnswer - 1); sa.adjustSize(); sa.move(x + lsa.width() + w, lsa.y()); // Make the two elements with the same size m = (tf.width() > sa.width() ? tf.width() : sa.width()); tf.resize(m, tf.height()); sa.resize(m, sa.height()); QLabel lsn(tr("Session (0 - random):"), &options); lsn.setAlignment(QLabel::AlignRight | QLabel::AlignVCenter); lsn.adjustSize(); lsn.move(x, sa.y() + sa.height() + y + s); QSpinBox sn(MIN_SESSION, MAX_SESSION, 1, &options); sn.setValue(session); sn.adjustSize(); sn.move(x + lsn.width() + w, lsn.y()); QLabel lqn(tr("Number of questions:"), &options); lqn.setAlignment(QLabel::AlignRight | QLabel::AlignVCenter); lqn.adjustSize(); lqn.move(x, sn.y() + sn.height() + y); QSpinBox qn(MIN_QUESTIONS, MAX_QUESTIONS, 10, &options); qn.setValue(questions); qn.adjustSize(); qn.move(x + lqn.width() + w, lqn.y()); // Make the two elements with the same size m = (sn.width() > qn.width() ? sn.width() : qn.width()); sn.resize(m, sn.height()); qn.resize(m, qn.height()); QLabel llv(tr("Test difficult level:"), &options); llv.setAlignment(QLabel::AlignRight | QLabel::AlignVCenter); llv.adjustSize(); llv.move(x, qn.y() + qn.height() + y + s); QComboBox lv(false, &options); lv.insertItem(tr("Novice")); lv.insertItem(tr("Beginner")); lv.insertItem(tr("Intermediate")); lv.insertItem(tr("Specialist")); lv.insertItem(tr("Expert")); lv.setCurrentItem(level - 1); lv.adjustSize(); lv.move(x + llv.width() + w, llv.y()); // Determine max size of labels m = 0; m = (ltf.width() > m ? ltf.width() : m); m = (lsa.width() > m ? lsa.width() : m); m = (lsn.width() > m ? lsn.width() : m); m = (lqn.width() > m ? lqn.width() : m); m = (llv.width() > m ? llv.width() : m); // Set labels with max size ltf.resize(m, tf.height()); lsa.resize(m, sa.height()); lsn.resize(m, sn.height()); lqn.resize(m, qn.height()); llv.resize(m, lv.height()); // Move other elements relative to labels tf.move(x + m + w, tf.y()); sa.move(x + m + w, sa.y()); sn.move(x + m + w, sn.y()); qn.move(x + m + w, qn.y()); lv.move(x + m + w, lv.y()); // Create buttons QPushButton ok(tr("&OK"), &options); ok.setDefault(true); connect(&ok, SIGNAL(clicked()), &options, SLOT(accept())); QPushButton cancel(tr("&Cancel"), &options); connect(&cancel, SIGNAL(clicked()), &options, SLOT(reject())); cancel.adjustSize(); cancel.move(tf.x() + tf.width() - cancel.width(), lv.y() + lv.height() + (s + y)*2); ok.setGeometry(cancel.x() - cancel.width() - x, cancel.y(), cancel.width(), cancel.height()); options.setFixedSize(cancel.x() + cancel.width() + x, cancel.y() + cancel.height() + y); // Execute dialog and check for OK button if (options.exec() == QDialog::Accepted) { translate = tf.currentItem() + 1; showAnswer = sa.currentItem() + 1; level = lv.currentItem() + 1; session = sn.value(); questions = qn.value(); current = 0; correct = 0; answer->setFocus(); answer_EnterPressed(); } } // End of button_New //=== Button Help ======================================================== // Shows help message in result text view //======================================================================== void Test::button_Help() { result->setText(tr(HELP_TEXT)); result->sync(); result->setCursorPosition(0, 0); } // End of button_Help //=== Set View =========================================================== // Sets positions, fonts and size of widgets // Called from constructor and resize //======================================================================== void Test::setView() { // Create FontMetrics Object for height of Word field and for other objects width QFontMetrics fm = QFontMetrics(font); // Set button new test bnew->setFont(font); bnew->resize(fm.width(bnew->text()) + ADDITIONAL_WIDTH, fm.height() + ADDITIONAL_HEIGHT); bnew->move((width() - borderWidth*4 - 2 - bnew->width() < MIN_LEFT_WIDTH ? MIN_LEFT_WIDTH + borderWidth*3 + 2 : width() - borderWidth - bnew->width()), borderWidth); // Set button close bclose->setFont(font); bclose->setGeometry(bnew->x(), bnew->y() + bnew->height() + borderWidth + 1, bnew->width(), bnew->height()); // Set button close bhelp->setFont(font); bhelp->setGeometry(bnew->x(), bclose->y() + bclose->height() + borderWidth + 1, bnew->width(), bnew->height()); // Set Question label question->setFont(font); question->setGeometry(borderWidth, borderWidth, bnew->x() - borderWidth*3 - 2, bnew->height()); // Set Answer text field answer->setFont(font); answer->setGeometry(borderWidth, question->y() + question->height() + borderWidth + 1, question->width(), question->height()); // Set Word label found->setFont(font); found->setGeometry(borderWidth, answer->y() + answer->height() + borderWidth + 1, question->height(), question->height()); // Set Word label word->setFont(font); word->setGeometry(found->width() + borderWidth*2 + 1, found->y(), question->width() - found->width() - borderWidth - 1, question->height()); // Set Info label info->setFont(font); info->setGeometry(borderWidth, height() - borderWidth - bnew->height(), width() - borderWidth*2, bnew->height()); // Create new font for result (down pane) with Normal Style only QFont f2 = QFont(font); f2.setWeight(QFont::Normal); // Set result text view result->setFont(f2); result->setGeometry(borderWidth, word->y() + word->height() + borderWidth + 1, width() - borderWidth*2, height() - info->height() - word->y() - word->height() - borderWidth*3 - 2); } // End of setView //=== Resize Event ======================================================= // Invoked from resize ivent // Set new size and positions for a components //======================================================================== void Test::resizeEvent(QResizeEvent *resizeEvent) { static bool firstTime = true; if (firstTime) { setView(); firstTime = false; } else { bnew->move((width() - borderWidth*4 - 2 - bnew->width() < MIN_LEFT_WIDTH ? MIN_LEFT_WIDTH + borderWidth*3 + 2 : width() - borderWidth - bnew->width()), borderWidth); bclose->move(bnew->x(), bclose->y()); bhelp->move(bnew->x(), bhelp->y()); question->resize(bnew->x() - borderWidth*3 - 2, question->height()); answer->resize(question->width(), question->height()); word->resize(question->width() - found->width() - borderWidth - 1, question->height()); result->resize(width() - borderWidth*2, height() - info->height() - word->y() - word->height() - borderWidth*3 - 2); info->setGeometry(borderWidth, height() - borderWidth - info->height(), width() - borderWidth*2, info->height()); } } // End of resizeEvent