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/keduca/keduca/keducaview.cpp

630 lines
20 KiB

/***************************************************************************
keducaview.cpp - description
-------------------
begin : Thu May 24 2001
copyright : (C) 2001 by Javier Campos
email : javi@asyris.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 "keducaview.h"
#include "keducaview.moc"
#include "settings.h"
#include "../libkeduca/fileread.h"
#include "kquestion.h"
#include "kgroupeduca.h"
#include <stdlib.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kpushbutton.h>
#include <kdebug.h>
#include <kio/netaccess.h>
#include <tqtimer.h>
#include <tqlayout.h>
#include <tqlabel.h>
#include <tqtextedit.h>
KEducaView::KEducaView( TQWidget *parent, const char *name )
: TQWidgetStack( parent, name ), _keducaFile( 0 ), _timeoutTimer( 0 )
{
init();
}
KEducaView::~KEducaView()
{
delete _questionText;
delete _buttonGroup;
delete _split;
delete _buttonNext;
delete _buttonSave;
delete _viewResults;
delete _keducaFile;
}
/** Init graphical interface */
void KEducaView::init()
{
// Intro Screen
_introWidget = new TQLabel( this, "introScreen" );
_introWidget->setBackgroundColor( TQt::white );
_introWidget->setAlignment( AlignCenter );
_introWidget->setPixmap( TQPixmap( locate("data","keduca/pics/keduca_init.png") ) );
addWidget( _introWidget, 0 );
// Info Widget
_infoWidget = new TQVBox( this, "infoWidget" );
_viewInfo = new TQTextEdit( _infoWidget );
_viewInfo->setReadOnly( true );
_buttonStartTest = new KPushButton( i18n( "&Start Test" ), _infoWidget );
connect( _buttonStartTest, TQT_SIGNAL( clicked() ), TQT_SLOT( slotButtonNext() ) );
addWidget( _infoWidget, 1 );
// Question Widget
_questionWidget = new TQVBox( this, "questionWidget" );
_split = new TQSplitter( Qt::Vertical, _questionWidget );
_questionText = new KQuestion( _split, "kquestion" );
_buttonGroup = new KGroupEduca( _split, "ButtonGroup" );
_buttonGroup->setRadioButtonExclusive( true );
_buttonNext = new KPushButton( i18n( "&Next >>" ), _questionWidget, "ButtonNext" );
connect( _buttonNext, TQT_SIGNAL( clicked() ), TQT_SLOT( slotButtonNext() ) );
addWidget( _questionWidget, 2 );
// Results Widget
_resultsWidget = new TQVBox( this, "resultsWidget" );
_viewResults = new TQTextEdit( _resultsWidget );
_viewResults->setReadOnly( true );
_buttonSave = new KPushButton( i18n( "&Save Results..." ), _resultsWidget );
connect( _buttonSave, TQT_SIGNAL( clicked() ), TQT_SLOT( slotButtonSave() ) );
/* FIXME: This is a hack
* The results widget can be shown only in the end of the test (when you should be shown the
* option to save the results) or at the middle of the test, after each question (when there should
* be a "Next" button).
*/
_buttonResultsNext = new KPushButton( i18n( "&Next >>" ), _resultsWidget );
connect( _buttonResultsNext, TQT_SIGNAL( clicked() ), TQT_SLOT( slotButtonNext() ) );
_buttonResultsNext->hide();
addWidget( _resultsWidget, 3 );
raiseWidget( _introWidget );
// Restore splitter size
_split->setSizes( Settings::splitter_size() );
}
void KEducaView::slotButtonStartTest()
{
raiseWidget( _questionWidget );
showRecord();
}
/** Button Next action */
void KEducaView::slotButtonNext()
{
// stop the timer
if (_timeoutTimer)
{
_currentTime += _questionText->getCurrentTime();
_timeoutTimer->stop();
_questionText->countdown(0);
}
if( ( visibleWidget() == _questionWidget ) && !_isInitStatus )
setResults();
_buttonGroup->clearAnswers();
if( ( Settings::resultFinish()== Settings::EnumResultFinish::afterEachQuestion )
&& _questionText->isVisible() )
{
showResults( _currentResults + "<HR>" + currentStatusPoints() );
}
else
{
if( questionNext() )
showRecord();
else
{
configWrite();
showResults( setFinalResult() + currentStatusPoints() + "<HR><P>" + _results + "</HTML>"
);
}
}
}
/** Button Save action */
void KEducaView::slotButtonSave()
{
KFileDialog *dialog=new KFileDialog(TQString(), TQString(), this, "file dialog", true);
dialog->setCaption( i18n("Save Results As") );
dialog->setKeepLocation( true );
dialog->setOperationMode( KFileDialog::Saving );
TQStringList mimeFilter( "text/html");
dialog->setMimeFilter( mimeFilter );
KURL newURL;
TQString outputFormat ("text/html");
bool bOk;
do {
bOk=true;
if(dialog->exec()==TQDialog::Accepted) {
newURL=dialog->selectedURL();
outputFormat=dialog->currentMimeFilter();
}
else
{
bOk = false;
break;
}
kdDebug()<<"Requested saving to file "<<newURL.prettyURL() <<endl;
if ( TQFileInfo( newURL.path() ).extension().isEmpty() ) {
// No more extensions in filters. We need to get it from the mimetype.
TQString extension = ".html";
newURL.setPath( newURL.path() + extension );
}
if ( KIO::NetAccess::exists( newURL, false, this ) ) { // this file exists => ask for confirmation
bOk = KMessageBox::warningContinueCancel( this,
i18n("A document with this name already exists.\n"\
"Do you want to overwrite it?"),
i18n("Warning"), i18n("Overwrite") ) == KMessageBox::Continue;
}
} while ( !bOk );
delete dialog;
if( bOk ) {
if (!_keducaFile->saveResults( newURL, _viewResults->text() ))
{
kdDebug()<< "saving of file failed" <<endl;
KMessageBox::sorry( this, i18n("Save failed.") );
}
}else {
kdDebug()<< "KControlDoc: no valid filename selected" <<endl;
}
}
/** Show record, returns false if there is no record to show. */
void KEducaView::showRecord()
{
TQString questionTextTemp = "";
raiseWidget( _questionWidget );
_keducaFileIndex++;
bool MultiAnswer = _keducaFile->isMultiAnswer();
// SHOW QUESTION *******************************************************************
_questionText->setPixmap( _keducaFile->getPicturePixmap() );
questionTextTemp = "<table width=100%><tr><td><b>"
+ i18n("Question %1").arg(_keducaFileIndex) + "</b>";
if( _keducaFile->getTotalPoints() > 0 )
questionTextTemp += "</td><td align=center bgColor=#336699><font color=#ffffff><b>"
+ _keducaFile->getQuestion( FileRead::TQF_POINTS )
+ " " + i18n("Points")
+ "</b></font>";
questionTextTemp += "</tr></td></table><hr/><table><tr><td>"
+ _keducaFile->getQuestion( FileRead::TQF_TEXT )
+ "</td></tr></table>";
_questionText->setText( questionTextTemp );
// SHOW ANSWERS ********************************************************************
if( MultiAnswer )
_buttonGroup->setType( KGroupEduca::Check );
else
_buttonGroup->setType( KGroupEduca::Radio );
if( Settings::randomAnswers() )
{
_randomAnswers.clear();
TQValueList<unsigned int> tmpRandom;
unsigned int index;
for( index = 0 ; index < _keducaFile->recordAnswerCount() ; index ++ )
{ tmpRandom.append( index ); }
for( index = 0 ; index < _keducaFile->recordAnswerCount() ; index ++ )
{
unsigned int random = rand() % tmpRandom.count();
TQValueList<unsigned int>::iterator itTmpRandom = tmpRandom.begin();
for( unsigned int i = 0; i < random; i++) { ++itTmpRandom; }
_keducaFile->recordAnswerAt( (*itTmpRandom) );
_randomAnswers.append( (*itTmpRandom) );
_buttonGroup->insertAnswer( _keducaFile->getAnswer(FileRead::AF_TEXT) );
tmpRandom.remove( itTmpRandom );
}
}
else
{
_keducaFile->recordAnswerFirst();
while( !_keducaFile->recordAnswerEOF() )
{
if( !_keducaFile->getAnswer(FileRead::AF_TEXT).isEmpty() )
_buttonGroup->insertAnswer( _keducaFile->getAnswer(FileRead::AF_TEXT) );
_keducaFile->recordAnswerNext();
};
}
// START THE TIMER *****************************************************************
if( _keducaFile->getQuestionInt(FileRead::TQF_TIME) > 0 )
{
KMessageBox::information( this,
i18n( "You have %1 seconds to complete this question.\n\n"
"Press OK when you are ready." )
.arg( _keducaFile->getQuestion(FileRead::TQF_TIME) ) );
}
int timeout = _keducaFile->getQuestionInt(FileRead::TQF_TIME);
if (timeout > 0)
{
if (!_timeoutTimer)
{
_timeoutTimer = new TQTimer(this);
connect(_timeoutTimer, TQT_SIGNAL(timeout()),
this, TQT_SLOT(questionTimedOut()));
}
_timeoutTimer->start(1000*timeout);
_questionText->countdown(timeout);
_questionText->countdownVisible(true);
}
else
{
_questionText->countdownVisible(false);
}
}
void KEducaView::questionTimedOut()
{
_currentTime += _keducaFile->getQuestionInt(FileRead::TQF_TIME);
slotButtonNext();
}
/** Show results */
void KEducaView::showResults( const TQString &text )
{
_viewResults->setText( text );
if ( _keducaFile->recordEOF() )
{
_buttonSave->show();
_buttonResultsNext->hide();
}
else
{
_buttonSave->hide();
_buttonResultsNext->show();
}
raiseWidget( _resultsWidget );
}
/** Set results */
void KEducaView::setResults()
{
bool isCorrect = true;
TQString yourAnswer = "";
TQString correctAnswer = "";
TQValueList<uint>::iterator itRandom = _randomAnswers.begin();
Settings::randomAnswers() ? _keducaFile->recordAnswerAt(*itRandom) : _keducaFile->recordAnswerFirst();
for( unsigned index = 0 ; index < _keducaFile->recordAnswerCount() ; index++ )
{
TQString answertext = _keducaFile->getAnswer( FileRead::AF_TEXT );
if( !answertext.isEmpty() )
{
if(_buttonGroup->isChecked(index) != _keducaFile->getAnswerValue())
{
isCorrect=false;
if(_buttonGroup->isChecked(index)) yourAnswer += "<BR><FONT COLOR=#b84747><B>" + answertext + "</B></FONT>";
if(_keducaFile->getAnswerValue()) correctAnswer += "<BR><FONT COLOR=#006b6b><B>" + answertext + "</B></FONT>";
}
else
{
if(_buttonGroup->isChecked(index)) yourAnswer += "<BR><B>" + answertext + "</B>";
if(_keducaFile->getAnswerValue()) correctAnswer += "<BR><FONT COLOR=#006b6b><B>" + answertext + "</B></FONT>";
}
}
if( Settings::randomAnswers() )
{
++itRandom;
_keducaFile->recordAnswerAt(*itRandom);
}
else
_keducaFile->recordAnswerNext();
}
if( isCorrect)
{
_correctAnswer++;
if( _keducaFile->getTotalPoints() > 0 )
_correctPoints += _keducaFile->getQuestionInt(FileRead::TQF_POINTS);
}
else
{
_incorrectAnswer++;
if( _keducaFile->getTotalPoints() > 0 )
_incorrectPoints += _keducaFile->getQuestionInt(FileRead::TQF_POINTS);
}
_results += getTableQuestion( isCorrect, correctAnswer, yourAnswer );
}
/** Set results */
TQString KEducaView::setFinalResult()
{
TQString finalResult = "";
if( !_keducaFile->isResult() ) return "";
finalResult = "<TABLE WIDTH=100% BORDER=0 BGCOLOR=#EEEEDD CELLSPACING=0><TR><TD BGCOLOR=#DDDDCC COLSPAN=2 ALIGN=CENTER><FONT COLOR=#222211><B>"
+ i18n("Result")
+ "</B></FONT></TD></TR>";
_keducaFile->recordResultFirst();
while( !_keducaFile->recordResultEOF() )
{
if( _correctPoints >= _keducaFile->getResultInt(FileRead::RS_MIN) &&
_correctPoints <= _keducaFile->getResultInt(FileRead::RS_MAX) )
{
if( _keducaFile->getResult(FileRead::RS_PICTURE).isEmpty() )
finalResult += "<TR><TD COLSPAN=2 ALIGN=CENTER>";
else
finalResult += "<TR><TD><IMG SRC=" + _keducaFile->getResult(FileRead::RS_PICTURE) + " : </TD><TD>";
finalResult += _keducaFile->getResult(FileRead::RS_TEXT) + "</TD><TR>";
}
_keducaFile->recordResultNext();
}
finalResult += "</TABLE>";
return finalResult;
}
/** Open url */
bool KEducaView::openURL( const KURL &url)
{
_keducaFile = new FileRead();
if ( !_keducaFile->openFile( url ) )
return false;
_isInitStatus = true;
_results = "<HTML>";
_correctAnswer = 0;
_correctPoints = 0;
_currentTime = 0;
_incorrectAnswer = 0;
_incorrectPoints = 0;
_keducaFileIndex = 0;
if( Settings::randomQuestions() )
{
unsigned int index;
for( index = 0 ; index < _keducaFile->getTotalQuestions() ; index ++ )
{ _randomQuestions.append( index ); }
}
_keducaFile->recordFirst();
_keducaFile->recordAnswerFirst();
_viewInfo->setText( getInformation() );
raiseWidget( _infoWidget );
return true;
}
/** Write settings */
void KEducaView::configWrite()
{
Settings::setSplitter_size( _split->sizes() );
Settings::writeConfig();
}
/** current Status Points */
TQString KEducaView::currentStatusPoints()
{
TQString tempStatus;
tempStatus = insertTable()
+ insertRow( i18n("Statistics"), true, 4)
+ insertRow( i18n("Correct questions"),
TQString().setNum( _correctAnswer ),
i18n("Incorrect questions"),
TQString().setNum( _incorrectAnswer ), true);
if( _keducaFile->getTotalPoints() > 0 )
tempStatus += insertRow( i18n("Total points"), true, 4 )
+ insertRow( i18n("Correct points"),
TQString().setNum( _correctPoints ),
i18n("Incorrect points"),
TQString().setNum( _incorrectPoints ), true );
if( _keducaFile->getTotalTime() > 0 )
tempStatus += insertRow( i18n("Time"), true, 4 )
+ insertRow( i18n("Total time"),
TQString().setNum( _keducaFile->getTotalTime() ),
i18n("Time in tests"),
TQString().setNum( _currentTime ), true );
tempStatus += insertTableClose();
return tempStatus;
}
/** Set HTML table view with correct and incorrect answers */
TQString KEducaView::getTableQuestion( bool isCorrect, const TQString &correct, const TQString &incorrect)
{
_currentResults = "<TABLE WIDTH=100% BORDER=0><TR><TD VALIGN=TOP WIDTH=70><IMG WIDTH=64 HEIGHT=64 SRC=";
if( isCorrect )
_currentResults += locate("data","keduca/pics/keduca_correct_64.png");
else
_currentResults += locate("data","keduca/pics/keduca_incorrect_64.png");
_currentResults += "></TD><TD VALIGN=TOP>";
_currentResults += "<B><FONT COLOR=#336699>" + _keducaFile->getQuestion( FileRead::TQF_TEXT ) + "</FONT></B>";
if( _keducaFile->getQuestionInt(FileRead::TQF_POINTS) > 0 )
_currentResults += "<SMALL> ( " + _keducaFile->getQuestion(FileRead::TQF_POINTS) + " " + i18n("Points") + " )</SMALL>";
_currentResults += "<HR><SMALL>";
if( isCorrect )
_currentResults += i18n( "The answer is: ");
else
_currentResults += i18n( "The correct answer is: ");
_currentResults += correct + "<BR>";
if( !isCorrect )
{
_currentResults += i18n( "Your answer was: ");
_currentResults += incorrect;
}
_currentResults += "</SMALL></TD></TR></TABLE><P>";
return _currentResults;
}
/** Define the next questions (random, secuencial) */
bool KEducaView::questionNext()
{
if( !Settings::randomQuestions() && !_isInitStatus )
{
_keducaFile->recordNext();
return _keducaFile->recordEOF() ? false : true;
}
if( _isInitStatus )
{
_isInitStatus = false;
if( !Settings::randomQuestions() ) return true;
}
if( _randomQuestions.count() > 0 )
{
unsigned int randomQuestion = rand() % _randomQuestions.count();
TQValueList<uint>::iterator itRandom = _randomQuestions.begin();
for( unsigned int i = 0; i < randomQuestion; ++i)
{ ++itRandom; }
_keducaFile->recordAt( (*itRandom) );
_randomQuestions.remove( itRandom );
return true;
}
else
return false;
}
/** Get document information */
TQString KEducaView::getInformation()
{
TQString tmp = "";
if ( _keducaFile )
{
if( !(_keducaFile->getHeader("startupinfo")).isEmpty() )
{
tmp += insertTable( "<img src=" + locate("data","keduca/pics/alert.png") + ">", 2 )
// + insertRow( i18n("Additional Information")+"<br>", true, 2 )
+ insertRow( _keducaFile->getHeader("startupinfo") + "<br>", false )
+ insertTableClose();
}
tmp += insertTable( "<img src=" + locate("data","keduca/pics/info.png") + ">", 2 );
tmp += insertRow( i18n("Information")+"<br>", true, 2);
tmp += insertRow( i18n("Title"), _keducaFile->getHeader("title"), true );
tmp += insertRow( i18n("Category"), _keducaFile->getHeader("category"), true );
tmp += insertRow( i18n("Type"), _keducaFile->getHeader("type"), true );
tmp += insertRow( i18n("Language"), _keducaFile->getHeader("language"), true );
tmp += insertTableClose();
}
else
{
tmp += "<html><body>";
tmp += "<img src=" + locate("data","keduca/pics/keduca_init.png") + "/>";
tmp += "</body></html>";
}
return tmp;
}
/** Init table with title and colspan */
TQString KEducaView::insertTable( const TQString &title, unsigned int col){
TQString tmp;
tmp = "<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 BGCOLOR=#EEEEDD>";
if( !title.isEmpty() ) {
tmp += "<TR><TD ";
if( col > 0 ) tmp += "COLSPAN=" + TQString().setNum( col ) + " ";
tmp += "ALIGN=CENTER><FONT COLOR=#222211><B>"
+ title
+ "</B></FONT></TD></TR>";
}
return tmp;
}
/** Insert row */
TQString KEducaView::insertRow( const TQString &text, bool title, unsigned colSpan ){
TQString tmp;
tmp = "<TR><TD";
if( colSpan>0 ) tmp+= " COLSPAN=" + TQString().setNum(colSpan);
if( title ) tmp += " ALIGN=CENTER";
tmp += ">";
if( title ) tmp += "<B>";
tmp += text;
if( title ) tmp += "</B>";
tmp += "</TD></TR>";
return tmp;
}
/** Insert row */
TQString KEducaView::insertRow( const TQString &label, const TQString &field, bool formBased ){
TQString tmp;
tmp = "<TR><TD";
if( formBased ) tmp += " ALIGN=RIGHT";
tmp += ">" + label;
if( formBased ) tmp += ": ";
tmp += "</TD><TD>" + field + "</TD></TR>";
return tmp;
}
TQString KEducaView::insertRow( const TQString &label1, const TQString &field1, const TQString &label2, const TQString &field2, bool formBased ){
TQString tmp;
tmp = "<TR><TD";
if( formBased ) tmp += " ALIGN=RIGHT";
tmp += ">" + label1;
if( formBased ) tmp += ": ";
tmp += "</TD><TD>" + field1 + "</TD>";
tmp += "<TD";
if( formBased ) tmp += " ALIGN=RIGHT";
tmp += ">" + label2;
if( formBased ) tmp += ": ";
tmp += "</TD><TD>" + field2 + "</TD></TR>";
return tmp;
}
/** Close current table */
TQString KEducaView::insertTableClose(){
return "</TABLE>";
}