00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "keducaview.h"
00019 #include "keducaview.moc"
00020 #include "settings.h"
00021 #include "../libkeduca/fileread.h"
00022 #include "kquestion.h"
00023 #include "kgroupeduca.h"
00024
00025 #include <stdlib.h>
00026
00027 #include <klocale.h>
00028 #include <kstandarddirs.h>
00029 #include <kmessagebox.h>
00030 #include <kfiledialog.h>
00031 #include <kpushbutton.h>
00032 #include <kdebug.h>
00033 #include <kio/netaccess.h>
00034
00035 #include <qtimer.h>
00036 #include <qlayout.h>
00037 #include <qlabel.h>
00038 #include <qtextedit.h>
00039
00040 KEducaView::KEducaView( QWidget *parent, const char *name )
00041 : QWidgetStack( parent, name ), _keducaFile( 0 ), _timeoutTimer( 0 )
00042 {
00043 init();
00044 }
00045
00046 KEducaView::~KEducaView()
00047 {
00048 delete _questionText;
00049 delete _buttonGroup;
00050 delete _split;
00051 delete _buttonNext;
00052 delete _buttonSave;
00053 delete _viewResults;
00054 delete _keducaFile;
00055 }
00056
00058 void KEducaView::init()
00059 {
00060
00061 _introWidget = new QLabel( this, "introScreen" );
00062 _introWidget->setBackgroundColor( Qt::white );
00063 _introWidget->setAlignment( AlignCenter );
00064 _introWidget->setPixmap( QPixmap( locate("data","keduca/pics/keduca_init.png") ) );
00065 addWidget( _introWidget, 0 );
00066
00067
00068 _infoWidget = new QVBox( this, "infoWidget" );
00069 _viewInfo = new QTextEdit( _infoWidget );
00070 _viewInfo->setReadOnly( true );
00071 _buttonStartTest = new KPushButton( i18n( "&Start Test" ), _infoWidget );
00072 connect( _buttonStartTest, SIGNAL( clicked() ), SLOT( slotButtonNext() ) );
00073 addWidget( _infoWidget, 1 );
00074
00075
00076 _questionWidget = new QVBox( this, "questionWidget" );
00077 _split = new QSplitter( QSplitter::Vertical, _questionWidget );
00078 _questionText = new KQuestion( _split, "kquestion" );
00079 _buttonGroup = new KGroupEduca( _split, "ButtonGroup" );
00080 _buttonGroup->setRadioButtonExclusive( true );
00081 _buttonNext = new KPushButton( i18n( "&Next >>" ), _questionWidget, "ButtonNext" );
00082 connect( _buttonNext, SIGNAL( clicked() ), SLOT( slotButtonNext() ) );
00083 addWidget( _questionWidget, 2 );
00084
00085
00086 _resultsWidget = new QVBox( this, "resultsWidget" );
00087 _viewResults = new QTextEdit( _resultsWidget );
00088 _viewResults->setReadOnly( true );
00089 _buttonSave = new KPushButton( i18n( "&Save Results..." ), _resultsWidget );
00090 connect( _buttonSave, SIGNAL( clicked() ), SLOT( slotButtonSave() ) );
00091
00092
00093
00094
00095
00096 _buttonResultsNext = new KPushButton( i18n( "&Next >>" ), _resultsWidget );
00097 connect( _buttonResultsNext, SIGNAL( clicked() ), SLOT( slotButtonNext() ) );
00098 _buttonResultsNext->hide();
00099 addWidget( _resultsWidget, 3 );
00100
00101 raiseWidget( _introWidget );
00102
00103
00104 _split->setSizes( Settings::splitter_size() );
00105 }
00106
00107 void KEducaView::slotButtonStartTest()
00108 {
00109 raiseWidget( _questionWidget );
00110 showRecord();
00111 }
00112
00114 void KEducaView::slotButtonNext()
00115 {
00116
00117 if (_timeoutTimer)
00118 {
00119 _currentTime += _questionText->getCurrentTime();
00120 _timeoutTimer->stop();
00121 _questionText->countdown(0);
00122 }
00123
00124 if( ( visibleWidget() == _questionWidget ) && !_isInitStatus )
00125 setResults();
00126
00127 _buttonGroup->clearAnswers();
00128
00129 if( ( Settings::resultFinish()== Settings::EnumResultFinish::afterEachQuestion )
00130 && _questionText->isVisible() )
00131 {
00132 showResults( _currentResults + "<HR>" + currentStatusPoints() );
00133 }
00134 else
00135 {
00136 if( questionNext() )
00137 showRecord();
00138 else
00139 {
00140 configWrite();
00141 showResults( setFinalResult() + currentStatusPoints() + "<HR><P>" + _results + "</HTML>"
00142 );
00143 }
00144 }
00145 }
00146
00148 void KEducaView::slotButtonSave()
00149 {
00150 KFileDialog *dialog=new KFileDialog(QString::null, QString::null, this, "file dialog", true);
00151 dialog->setCaption( i18n("Save Results As") );
00152 dialog->setKeepLocation( true );
00153 dialog->setOperationMode( KFileDialog::Saving );
00154 QStringList mimeFilter( "text/html");
00155 dialog->setMimeFilter( mimeFilter );
00156 KURL newURL;
00157 QString outputFormat ("text/html");
00158
00159 bool bOk;
00160 do {
00161 bOk=true;
00162 if(dialog->exec()==QDialog::Accepted) {
00163 newURL=dialog->selectedURL();
00164 outputFormat=dialog->currentMimeFilter();
00165 }
00166 else
00167 {
00168 bOk = false;
00169 break;
00170 }
00171 kdDebug()<<"Requested saving to file "<<newURL.prettyURL() <<endl;
00172
00173 if ( QFileInfo( newURL.path() ).extension().isEmpty() ) {
00174
00175 QString extension = ".html";
00176 newURL.setPath( newURL.path() + extension );
00177 }
00178
00179 if ( KIO::NetAccess::exists( newURL, false, this ) ) {
00180 bOk = KMessageBox::warningContinueCancel( this,
00181 i18n("A document with this name already exists.\n"\
00182 "Do you want to overwrite it?"),
00183 i18n("Warning"), i18n("Overwrite") ) == KMessageBox::Continue;
00184 }
00185 } while ( !bOk );
00186
00187 delete dialog;
00188 if( bOk ) {
00189 if (!_keducaFile->saveResults( newURL, _viewResults->text() ))
00190 {
00191 kdDebug()<< "saving of file failed" <<endl;
00192 KMessageBox::sorry( this, i18n("Save failed.") );
00193 }
00194 }else {
00195 kdDebug()<< "KControlDoc: no valid filename selected" <<endl;
00196 }
00197 }
00198
00200 void KEducaView::showRecord()
00201 {
00202 QString questionTextTemp = "";
00203
00204 raiseWidget( _questionWidget );
00205
00206 _keducaFileIndex++;
00207 bool MultiAnswer = _keducaFile->isMultiAnswer();
00208
00209
00210 _questionText->setPixmap( _keducaFile->getPicturePixmap() );
00211 questionTextTemp = "<table width=100%><tr><td><b>"
00212 + i18n("Question %1").arg(_keducaFileIndex) + "</b>";
00213
00214 if( _keducaFile->getTotalPoints() > 0 )
00215 questionTextTemp += "</td><td align=center bgColor=#336699><font color=#ffffff><b>"
00216 + _keducaFile->getQuestion( FileRead::QF_POINTS )
00217 + " " + i18n("Points")
00218 + "</b></font>";
00219
00220 questionTextTemp += "</tr></td></table><hr/><table><tr><td>"
00221 + _keducaFile->getQuestion( FileRead::QF_TEXT )
00222 + "</td></tr></table>";
00223
00224 _questionText->setText( questionTextTemp );
00225
00226
00227 if( MultiAnswer )
00228 _buttonGroup->setType( KGroupEduca::Check );
00229 else
00230 _buttonGroup->setType( KGroupEduca::Radio );
00231
00232
00233 if( Settings::randomAnswers() )
00234 {
00235 _randomAnswers.clear();
00236 QValueList<unsigned int> tmpRandom;
00237 unsigned int index;
00238 for( index = 0 ; index < _keducaFile->recordAnswerCount() ; index ++ )
00239 { tmpRandom.append( index ); }
00240 for( index = 0 ; index < _keducaFile->recordAnswerCount() ; index ++ )
00241 {
00242 unsigned int random = rand() % tmpRandom.count();
00243 QValueList<unsigned int>::iterator itTmpRandom = tmpRandom.begin();
00244 for( unsigned int i = 0; i < random; i++) { ++itTmpRandom; }
00245 _keducaFile->recordAnswerAt( (*itTmpRandom) );
00246 _randomAnswers.append( (*itTmpRandom) );
00247 _buttonGroup->insertAnswer( _keducaFile->getAnswer(FileRead::AF_TEXT) );
00248 tmpRandom.remove( itTmpRandom );
00249 }
00250 }
00251 else
00252 {
00253 _keducaFile->recordAnswerFirst();
00254 while( !_keducaFile->recordAnswerEOF() )
00255 {
00256 if( !_keducaFile->getAnswer(FileRead::AF_TEXT).isEmpty() )
00257 _buttonGroup->insertAnswer( _keducaFile->getAnswer(FileRead::AF_TEXT) );
00258 _keducaFile->recordAnswerNext();
00259 };
00260 }
00261
00262
00263
00264 if( _keducaFile->getQuestionInt(FileRead::QF_TIME) > 0 )
00265 {
00266 KMessageBox::information( this,
00267 i18n( "You have %1 seconds to complete this question.\n\n"
00268 "Press OK when you are ready." )
00269 .arg( _keducaFile->getQuestion(FileRead::QF_TIME) ) );
00270 }
00271
00272 int timeout = _keducaFile->getQuestionInt(FileRead::QF_TIME);
00273 if (timeout > 0)
00274 {
00275 if (!_timeoutTimer)
00276 {
00277 _timeoutTimer = new QTimer(this);
00278 connect(_timeoutTimer, SIGNAL(timeout()),
00279 this, SLOT(questionTimedOut()));
00280 }
00281 _timeoutTimer->start(1000*timeout);
00282 _questionText->countdown(timeout);
00283 _questionText->countdownVisible(true);
00284 }
00285 else
00286 {
00287 _questionText->countdownVisible(false);
00288 }
00289 }
00290
00291 void KEducaView::questionTimedOut()
00292 {
00293 _currentTime += _keducaFile->getQuestionInt(FileRead::QF_TIME);
00294 slotButtonNext();
00295 }
00296
00298 void KEducaView::showResults( const QString &text )
00299 {
00300 _viewResults->setText( text );
00301
00302 if ( _keducaFile->recordEOF() )
00303 {
00304 _buttonSave->show();
00305 _buttonResultsNext->hide();
00306 }
00307 else
00308 {
00309 _buttonSave->hide();
00310 _buttonResultsNext->show();
00311 }
00312
00313 raiseWidget( _resultsWidget );
00314 }
00315
00317 void KEducaView::setResults()
00318 {
00319 bool isCorrect = true;
00320 QString yourAnswer = "";
00321 QString correctAnswer = "";
00322 QValueList<uint>::iterator itRandom = _randomAnswers.begin();
00323
00324 Settings::randomAnswers() ? _keducaFile->recordAnswerAt(*itRandom) : _keducaFile->recordAnswerFirst();
00325
00326 for( unsigned index = 0 ; index < _keducaFile->recordAnswerCount() ; index++ )
00327 {
00328 QString answertext = _keducaFile->getAnswer( FileRead::AF_TEXT );
00329 if( !answertext.isEmpty() )
00330 {
00331 if(_buttonGroup->isChecked(index) != _keducaFile->getAnswerValue())
00332 {
00333 isCorrect=false;
00334 if(_buttonGroup->isChecked(index)) yourAnswer += "<BR><FONT COLOR=#b84747><B>" + answertext + "</B></FONT>";
00335 if(_keducaFile->getAnswerValue()) correctAnswer += "<BR><FONT COLOR=#006b6b><B>" + answertext + "</B></FONT>";
00336 }
00337 else
00338 {
00339 if(_buttonGroup->isChecked(index)) yourAnswer += "<BR><B>" + answertext + "</B>";
00340 if(_keducaFile->getAnswerValue()) correctAnswer += "<BR><FONT COLOR=#006b6b><B>" + answertext + "</B></FONT>";
00341 }
00342 }
00343 if( Settings::randomAnswers() )
00344 {
00345 ++itRandom;
00346 _keducaFile->recordAnswerAt(*itRandom);
00347 }
00348 else
00349 _keducaFile->recordAnswerNext();
00350 }
00351
00352 if( isCorrect)
00353 {
00354 _correctAnswer++;
00355 if( _keducaFile->getTotalPoints() > 0 )
00356 _correctPoints += _keducaFile->getQuestionInt(FileRead::QF_POINTS);
00357 }
00358 else
00359 {
00360 _incorrectAnswer++;
00361 if( _keducaFile->getTotalPoints() > 0 )
00362 _incorrectPoints += _keducaFile->getQuestionInt(FileRead::QF_POINTS);
00363 }
00364
00365 _results += getTableQuestion( isCorrect, correctAnswer, yourAnswer );
00366 }
00367
00369 QString KEducaView::setFinalResult()
00370 {
00371 QString finalResult = "";
00372
00373 if( !_keducaFile->isResult() ) return "";
00374
00375 finalResult = "<TABLE WIDTH=100% BORDER=0 BGCOLOR=#EEEEDD CELLSPACING=0><TR><TD BGCOLOR=#DDDDCC COLSPAN=2 ALIGN=CENTER><FONT COLOR=#222211><B>"
00376 + i18n("Result")
00377 + "</B></FONT></TD></TR>";
00378
00379 _keducaFile->recordResultFirst();
00380 while( !_keducaFile->recordResultEOF() )
00381 {
00382 if( _correctPoints >= _keducaFile->getResultInt(FileRead::RS_MIN) &&
00383 _correctPoints <= _keducaFile->getResultInt(FileRead::RS_MAX) )
00384 {
00385 if( _keducaFile->getResult(FileRead::RS_PICTURE).isEmpty() )
00386 finalResult += "<TR><TD COLSPAN=2 ALIGN=CENTER>";
00387 else
00388 finalResult += "<TR><TD><IMG SRC=" + _keducaFile->getResult(FileRead::RS_PICTURE) + " : </TD><TD>";
00389
00390 finalResult += _keducaFile->getResult(FileRead::RS_TEXT) + "</TD><TR>";
00391 }
00392 _keducaFile->recordResultNext();
00393 }
00394
00395 finalResult += "</TABLE>";
00396
00397 return finalResult;
00398 }
00399
00401 bool KEducaView::openURL( const KURL &url)
00402 {
00403 _keducaFile = new FileRead();
00404 if ( !_keducaFile->openFile( url ) )
00405 return false;
00406
00407 _isInitStatus = true;
00408 _results = "<HTML>";
00409 _correctAnswer = 0;
00410 _correctPoints = 0;
00411 _currentTime = 0;
00412 _incorrectAnswer = 0;
00413 _incorrectPoints = 0;
00414 _keducaFileIndex = 0;
00415
00416 if( Settings::randomQuestions() )
00417 {
00418 unsigned int index;
00419 for( index = 0 ; index < _keducaFile->getTotalQuestions() ; index ++ )
00420 { _randomQuestions.append( index ); }
00421 }
00422
00423 _keducaFile->recordFirst();
00424 _keducaFile->recordAnswerFirst();
00425
00426 _viewInfo->setText( getInformation() );
00427 raiseWidget( _infoWidget );
00428
00429 return true;
00430 }
00431
00433 void KEducaView::configWrite()
00434 {
00435 Settings::setSplitter_size( _split->sizes() );
00436 Settings::writeConfig();
00437 }
00438
00440 QString KEducaView::currentStatusPoints()
00441 {
00442 QString tempStatus;
00443
00444 tempStatus = insertTable()
00445 + insertRow( i18n("Statistics"), true, 4)
00446 + insertRow( i18n("Correct questions"),
00447 QString().setNum( _correctAnswer ),
00448 i18n("Incorrect questions"),
00449 QString().setNum( _incorrectAnswer ), true);
00450
00451 if( _keducaFile->getTotalPoints() > 0 )
00452 tempStatus += insertRow( i18n("Total points"), true, 4 )
00453 + insertRow( i18n("Correct points"),
00454 QString().setNum( _correctPoints ),
00455 i18n("Incorrect points"),
00456 QString().setNum( _incorrectPoints ), true );
00457
00458 if( _keducaFile->getTotalTime() > 0 )
00459 tempStatus += insertRow( i18n("Time"), true, 4 )
00460 + insertRow( i18n("Total time"),
00461 QString().setNum( _keducaFile->getTotalTime() ),
00462 i18n("Time in tests"),
00463 QString().setNum( _currentTime ), true );
00464 tempStatus += insertTableClose();
00465 return tempStatus;
00466 }
00467
00469 QString KEducaView::getTableQuestion( bool isCorrect, const QString &correct, const QString &incorrect)
00470 {
00471 _currentResults = "<TABLE WIDTH=100% BORDER=0><TR><TD VALIGN=TOP WIDTH=70><IMG WIDTH=64 HEIGHT=64 SRC=";
00472 if( isCorrect )
00473 _currentResults += locate("data","keduca/pics/keduca_correct_64.png");
00474 else
00475 _currentResults += locate("data","keduca/pics/keduca_incorrect_64.png");
00476
00477 _currentResults += "></TD><TD VALIGN=TOP>";
00478
00479 _currentResults += "<B><FONT COLOR=#336699>" + _keducaFile->getQuestion( FileRead::QF_TEXT ) + "</FONT></B>";
00480
00481 if( _keducaFile->getQuestionInt(FileRead::QF_POINTS) > 0 )
00482 _currentResults += "<SMALL> ( " + _keducaFile->getQuestion(FileRead::QF_POINTS) + " " + i18n("Points") + " )</SMALL>";
00483
00484 _currentResults += "<HR><SMALL>";
00485
00486 if( isCorrect )
00487 _currentResults += i18n( "The answer is: ");
00488 else
00489 _currentResults += i18n( "The correct answer is: ");
00490
00491 _currentResults += correct + "<BR>";
00492
00493 if( !isCorrect )
00494 {
00495 _currentResults += i18n( "Your answer was: ");
00496 _currentResults += incorrect;
00497 }
00498
00499 _currentResults += "</SMALL></TD></TR></TABLE><P>";
00500 return _currentResults;
00501 }
00502
00504 bool KEducaView::questionNext()
00505 {
00506 if( !Settings::randomQuestions() && !_isInitStatus )
00507 {
00508 _keducaFile->recordNext();
00509 return _keducaFile->recordEOF() ? false : true;
00510 }
00511
00512 if( _isInitStatus )
00513 {
00514 _isInitStatus = false;
00515 if( !Settings::randomQuestions() ) return true;
00516 }
00517
00518 if( _randomQuestions.count() > 0 )
00519 {
00520 unsigned int randomQuestion = rand() % _randomQuestions.count();
00521 QValueList<uint>::iterator itRandom = _randomQuestions.begin();
00522 for( unsigned int i = 0; i < randomQuestion; ++i)
00523 { ++itRandom; }
00524 _keducaFile->recordAt( (*itRandom) );
00525 _randomQuestions.remove( itRandom );
00526 return true;
00527 }
00528 else
00529 return false;
00530 }
00531
00533 QString KEducaView::getInformation()
00534 {
00535
00536 QString tmp = "";
00537
00538 if ( _keducaFile )
00539 {
00540 if( !(_keducaFile->getHeader("startupinfo")).isEmpty() )
00541 {
00542 tmp += insertTable( "<img src=" + locate("data","keduca/pics/alert.png") + ">", 2 )
00543
00544 + insertRow( _keducaFile->getHeader("startupinfo") + "<br>", false )
00545 + insertTableClose();
00546 }
00547
00548 tmp += insertTable( "<img src=" + locate("data","keduca/pics/info.png") + ">", 2 );
00549 tmp += insertRow( i18n("Information")+"<br>", true, 2);
00550 tmp += insertRow( i18n("Title"), _keducaFile->getHeader("title"), true );
00551 tmp += insertRow( i18n("Category"), _keducaFile->getHeader("category"), true );
00552 tmp += insertRow( i18n("Type"), _keducaFile->getHeader("type"), true );
00553 tmp += insertRow( i18n("Language"), _keducaFile->getHeader("language"), true );
00554 tmp += insertTableClose();
00555 }
00556 else
00557 {
00558 tmp += "<html><body>";
00559 tmp += "<img src=" + locate("data","keduca/pics/keduca_init.png") + "/>";
00560 tmp += "</body></html>";
00561 }
00562
00563 return tmp;
00564 }
00565
00567 QString KEducaView::insertTable( const QString &title, unsigned int col){
00568 QString tmp;
00569
00570 tmp = "<TABLE WIDTH=100% BORDER=0 CELLSPACING=0 BGCOLOR=#EEEEDD>";
00571
00572 if( !title.isEmpty() ) {
00573 tmp += "<TR><TD ";
00574
00575 if( col > 0 ) tmp += "COLSPAN=" + QString().setNum( col ) + " ";
00576
00577 tmp += "ALIGN=CENTER><FONT COLOR=#222211><B>"
00578 + title
00579 + "</B></FONT></TD></TR>";
00580 }
00581 return tmp;
00582 }
00583
00585 QString KEducaView::insertRow( const QString &text, bool title, unsigned colSpan ){
00586 QString tmp;
00587 tmp = "<TR><TD";
00588 if( colSpan>0 ) tmp+= " COLSPAN=" + QString().setNum(colSpan);
00589 if( title ) tmp += " ALIGN=CENTER";
00590 tmp += ">";
00591 if( title ) tmp += "<B>";
00592 tmp += text;
00593 if( title ) tmp += "</B>";
00594 tmp += "</TD></TR>";
00595 return tmp;
00596 }
00597
00599 QString KEducaView::insertRow( const QString &label, const QString &field, bool formBased ){
00600 QString tmp;
00601 tmp = "<TR><TD";
00602 if( formBased ) tmp += " ALIGN=RIGHT";
00603 tmp += ">" + label;
00604 if( formBased ) tmp += ": ";
00605 tmp += "</TD><TD>" + field + "</TD></TR>";
00606 return tmp;
00607 }
00608
00609 QString KEducaView::insertRow( const QString &label1, const QString &field1, const QString &label2, const QString &field2, bool formBased ){
00610 QString tmp;
00611 tmp = "<TR><TD";
00612 if( formBased ) tmp += " ALIGN=RIGHT";
00613 tmp += ">" + label1;
00614 if( formBased ) tmp += ": ";
00615 tmp += "</TD><TD>" + field1 + "</TD>";
00616 tmp += "<TD";
00617 if( formBased ) tmp += " ALIGN=RIGHT";
00618 tmp += ">" + label2;
00619 if( formBased ) tmp += ": ";
00620 tmp += "</TD><TD>" + field2 + "</TD></TR>";
00621 return tmp;
00622 }
00623
00624
00626 QString KEducaView::insertTableClose(){
00627 return "</TABLE>";
00628 }
00629