#include "main_window.h"
void MainWindow::setupServer()
{
tcpServer = new QTcpServer(this);
QObject::connect(mainStackedWidget, SIGNAL(currentChanged(int)), this, SLOT(enableSMTools()));
QObject::connect(tcpServer, SIGNAL(newConnection()), this, SLOT(addClient()));
QObject::connect(btnStartServer, SIGNAL(released()), this, SLOT(startServer()));
QObject::connect(actionStart_server, SIGNAL(triggered()), this, SLOT(startServer()));
QObject::connect(actionStop_server, SIGNAL(triggered()), this, SLOT(stopServer()));
QObject::connect(actionExport_log, SIGNAL(triggered()), this, SLOT(exportLog()));
QObject::connect(SMLCListWidget, SIGNAL(currentTextChanged(QString)), this, SLOT(setCurrentClient()));
QObject::connect(actionQuickPrint, SIGNAL(triggered()), this, SLOT(quickPrint()));
QObject::connect(actionPrint, SIGNAL(triggered()), this, SLOT(print()));
QObject::connect(actionExport_test, SIGNAL(triggered()), this, SLOT(exportTest()));
QObject::connect(actionAdd_offline_client, SIGNAL(triggered()), this, SLOT(addOfflineClient()));
QObject::connect(actionAdd_offline_clients, SIGNAL(triggered()), this, SLOT(addOfflineClients()));
enableSMTools(); togglePrintEnabled();
rbtngrpAdvSelect = new QButtonGroup (this);
rbtngrpAdvSelect->addButton(rbtnSelectFlags);
rbtngrpAdvSelect->addButton(rbtnSelectQuestions);
QObject::connect(rbtngrpAdvSelect, SIGNAL(buttonReleased(QAbstractButton *)), this, SLOT(reloadAvailableItems()));
QObject::connect(TSAdvancedSetupGroupBox, SIGNAL(toggled(bool)), this, SLOT(reloadAvailableItems()));
QObject::connect(TSSearchAvailableLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(searchAvailableItems(const QString &)));
QObject::connect(TSSearchUsedLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(searchUsedItems(const QString &)));
QObject::connect(TSExcludeListWidget, SIGNAL(currentTextChanged(QString)), this, SLOT(toggleAddRemoveEnabled()));
QObject::connect(TSIncludeListWidget, SIGNAL(currentTextChanged(QString)), this, SLOT(toggleAddRemoveEnabled()));
QObject::connect(btnAddToList, SIGNAL(released()), this, SLOT(addToList()));
QObject::connect(btnRemoveFromList, SIGNAL(released()), this, SLOT(removeFromList()));
TSExcludeListWidget->setDragDropMode(QAbstractItemView::InternalMove);
TSIncludeListWidget->setDragDropMode(QAbstractItemView::InternalMove);
QObject::connect(TSMaxQnumCheckBox, SIGNAL(toggled(bool)), this, SLOT(setMaximumQuestions()));
QObject::connect(TSQnumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(updateTestTime()));
QObject::connect(TSQnumSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setMaximumPassMark(int)));
QObject::connect(rbtnTestTime, SIGNAL(toggled(bool)), this, SLOT(updateTestTime()));
QObject::connect(rbtnQuestionTime, SIGNAL(toggled(bool)), this, SLOT(updateTestTime()));
QObject::connect(TSTestTimeEdit, SIGNAL(timeChanged(QTime)), this, SLOT(updateTestTime()));
QObject::connect(TSQuestionTimeEdit, SIGNAL(timeChanged(QTime)), this, SLOT(updateTestTime()));
QGridLayout * glayout = (QGridLayout *)TSCommonSettingsGridLayout->layout();
if (glayout != NULL) { glayout->addWidget(TSTestNameLineEdit, 0, 2, 1, 3); }
}
void MainWindow::setMaximumPassMark(int value)
{
TSPassMarkSpinBox->setMaximum(value);
}
void MainWindow::toggleAddRemoveEnabled()
{
if (TSExcludeListWidget->currentIndex().isValid()) {
btnAddToList->setEnabled(true);
} else { btnAddToList->setEnabled(false); }
if (TSIncludeListWidget->currentIndex().isValid()) {
btnRemoveFromList->setEnabled(true);
} else { btnRemoveFromList->setEnabled(false); }
}
void MainWindow::reloadAvailableItems()
{
if (!TSAdvancedSetupGroupBox->isChecked()) {
TSExcludeListWidget->clear(); TSIncludeListWidget->clear();
TSSearchAvailableLineEdit->clear(); TSSearchUsedLineEdit->clear();
updateTestQnum();
} else {
if (rbtnSelectFlags->isChecked()) {
TSExcludeListWidget->clear(); TSIncludeListWidget->clear();
TSSearchAvailableLineEdit->clear(); TSSearchUsedLineEdit->clear();
QListWidgetItem * item;
for (int i = 0; i < 20; ++i) {
if (current_db_fe[i]) {
item = new QListWidgetItem (QString("%1 - %2").arg(i+1).arg(current_db_f[i]), TSExcludeListWidget);
item->setData(Qt::UserRole, i);
setQuestionItemColour(item, i);
}
}
toggleAddRemoveEnabled(); updateTestQnum();
} else if (rbtnSelectQuestions->isChecked()) {
TSExcludeListWidget->clear(); TSIncludeListWidget->clear();
TSSearchAvailableLineEdit->clear(); TSSearchUsedLineEdit->clear();
QListWidgetItem * item;
for (int i = 0; i < LQListWidget->count(); ++i) {
item = new QListWidgetItem (*LQListWidget->item(i));
item->setData(Qt::UserRole, i);
TSExcludeListWidget->addItem(item);
}
toggleAddRemoveEnabled(); updateTestQnum();
}
}
}
void MainWindow::updateTestQnum()
{
int db_qnum = 0;
if (!TSAdvancedSetupGroupBox->isChecked()) {
db_qnum = LQListWidget->count();
} else if (rbtnSelectFlags->isChecked()) {
QuestionItem * item; QList<int> used_items;
for (int i = 0; i < TSIncludeListWidget->count(); ++i) {
used_items << TSIncludeListWidget->item(i)->data(Qt::UserRole).toInt();
}
for (int i = 0; i < LQListWidget->count(); ++i) {
item = current_db_questions.value(LQListWidget->item(i));
if (used_items.contains(item->flag())) { db_qnum++; }
}
} else if (rbtnSelectQuestions->isChecked()) {
db_qnum = TSIncludeListWidget->count();
}
if (db_qnum < 1) {
TSQnumSpinBox->setMaximum(0);
TSMaxQnumCheckBox->setText(tr("maximum (%1)").arg(db_qnum));
btnStartServer->setEnabled(false);
actionStart_server->setEnabled(false);
} else {
TSQnumSpinBox->setMaximum(db_qnum);
TSMaxQnumCheckBox->setText(tr("maximum (%1)").arg(db_qnum));
if (TSMaxQnumCheckBox->isChecked()) {
TSQnumSpinBox->setValue(db_qnum);
}
btnStartServer->setEnabled(true);
actionStart_server->setEnabled(true);
}
}
void MainWindow::updateTestTime()
{
if (rbtnTestTime->isChecked()) {
if (TSQnumSpinBox->value() == 0) {
TSQuestionTimeEdit->setTime(QTime::QTime(0, 0));
} else {
QTime time = TSTestTimeEdit->time(); QTime nulltime (0, 0);
QTime qtime = nulltime.addSecs(((time.hour() * 60 * 60) + (time.minute() * 60)) / TSQnumSpinBox->value());
TSQuestionTimeEdit->setTime(qtime);
}
} else if (rbtnQuestionTime->isChecked()) {
QTime time = TSQuestionTimeEdit->time(); QTime nulltime (0, 0);
while ((((time.hour() * 60 * 60) + (time.minute() * 60)) * TSQnumSpinBox->value()) > 86340) {
time = time.addSecs(-60); qApp->processEvents();
}
TSQuestionTimeEdit->setTime(time);
QTime qtime = nulltime.addSecs(((time.hour() * 60 * 60) + (time.minute() * 60)) * TSQnumSpinBox->value());
TSTestTimeEdit->setTime(qtime);
}
}
void MainWindow::setMaximumQuestions()
{
TSQnumSpinBox->setValue(TSQnumSpinBox->maximum());
}
void MainWindow::searchAvailableItems(const QString & keyword)
{
searchListWidgetItems(keyword, TSExcludeListWidget, TSSearchAvailableLineEdit);
}
void MainWindow::searchUsedItems(const QString & keyword)
{
searchListWidgetItems(keyword, TSIncludeListWidget, TSSearchUsedLineEdit);
}
void MainWindow::addToList()
{
if (TSExcludeListWidget->currentIndex().isValid()) {
TSIncludeListWidget->addItem(TSExcludeListWidget->takeItem(TSExcludeListWidget->currentRow()));
updateTestQnum();
}
}
void MainWindow::removeFromList()
{
if (TSIncludeListWidget->currentIndex().isValid()) {
TSExcludeListWidget->addItem(TSIncludeListWidget->takeItem(TSIncludeListWidget->currentRow()));
updateTestQnum();
}
}
void MainWindow::startServer()
{
if (this->isWindowModified()) {
switch (QMessageBox::information(this, tr("iTest"), tr("It is necessary to save any changes you have made to the database before proceeding."), tr("&Save"), tr("Cancel"), 0, 1)) {
case 0: save(); break;
case 1: return; break;
}
}
if (TSCustomTestNameCheckBox->isChecked() && TSTestNameLineEdit->text().isEmpty())
{ QMessageBox::critical(this, tr("iTest"), tr("Invalid test name.")); return; }
QTime time = TSTestTimeEdit->time(); if (!time.isValid())
{ QMessageBox::critical(this, tr("iTest"), tr("Invalid exam time.")); return; }
if ((time.hour() == 0) && (time.minute() == 0) && (time.second() == 0))
{ QMessageBox::critical(this, tr("iTest"), tr("Students will need at least one minute for the exam,\nalthough it is recommended to give them an hour.")); return; }
if (!tcpServer->listen() && !tcpServer->isListening()) {
QMessageBox::critical(this, tr("iTest"), tr("Unable to start the server: %1.")
.arg(tcpServer->errorString()));
tcpServer->close();
return;
}
setProgress(2);
if (!loadPrinterSettings()) {
switch (QMessageBox::information(this, tr("iTest"), tr("You have not configured the printer yet. Would you like to configure it now?"), tr("Con&figure"), tr("Cancel"), 0, 0)) {
case 0: if (!configurePrinter(false)) { setProgress(-1); return; } break;
case 1: setProgress(-1); return; break;
}
} else {
QString printer_config;
if (printerConfiguration(printer_config)) {
switch (QMessageBox::information(this, tr("iTest"), tr("%1Current printer configuration:%2Would you like to review the configuration?%3").arg("<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">p, li { white-space: pre-wrap; }</style></head><body><p>").arg(printer_config).arg("</p></body></html>"), tr("&Review configuration"), tr("&Continue"), 0, 0)) {
case 0: if (!configurePrinter(true)) { setProgress(-1); return; } break;
case 1: if (!loadPrinterConfiguration()) { setProgress(-1); return; } break;
}
} else {
QMessageBox::critical(this, tr("iTest"), tr("Unable to start the server: Invalid printer configuration.")); setProgress(-1); return;
}
}
setProgress(4);
QString use_last_save_date;
if (actionUse_last_save_date->isChecked()) { use_last_save_date = "true"; }
else { use_last_save_date = "false"; }
int test_qnum = TSQnumSpinBox->value();
if (TSCustomTestNameCheckBox->isChecked()) {
current_db_testname = TSTestNameLineEdit->text();
} else { current_db_testname = current_db_name; }
current_db_testdate = QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm");
QList<int> used_items; int db_qnum = 0;
for (int i = 0; i < TSIncludeListWidget->count(); ++i) {
used_items << TSIncludeListWidget->item(i)->data(Qt::UserRole).toInt();
}
if (!TSAdvancedSetupGroupBox->isChecked()) {
db_qnum = current_db_questions.size();
} else if (rbtnSelectFlags->isChecked()) {
QuestionItem * item;
for (int i = 0; i < LQListWidget->count(); ++i) {
item = current_db_questions.value(LQListWidget->item(i));
if (used_items.contains(item->flag())) { db_qnum++; }
}
} else if (rbtnSelectQuestions->isChecked()) {
db_qnum = TSIncludeListWidget->count();
} else {
QMessageBox::critical(this, tr("iTest"), tr("Unable to start the server: Invalid server settings.")); setProgress(-1); return;
}
current_db_test.clear(); QByteArray ba;
QDataStream out(&ba, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_2);
out << (quint64)0;
setProgress(5); out << QString("[ITEST_VERSION]\n") << ver << QString("\n");
out << QString("[ITEST_DB_VERSION]\n") << db_ver << QString("\n");
out << QString("[DB_NAME]\n") << current_db_testname << QString("\n");
out << QString("[DB_DATE]\n") << current_db_date << QString("\n");
out << QString("[DB_DATE_ULSD]\n") << use_last_save_date << QString("\n");
out << QString("[TEST_DATE]\n") << current_db_testdate << QString("\n");
out << QString("[TEST_TIME]\n") << time.toString("HH:mm") << QString("\n");
out << QString("[TEST_QNUM]\n") << QString("%1").arg(test_qnum) << QString("\n");
out << QString("[DB_COMMENTS]\n") << current_db_comments << QString("\n");
out << QString("[DB_QNUM]\n") << QString("%1").arg(db_qnum) << QString("\n");
out << QString("[DB_FLAGS]") << QString("\n");
for (int i = 0; i < 20; ++i)
{if (current_db_fe[i]) {out << QString("+");} else {out << QString("-");}}
out << QString("\n");
for (int i = 0; i < 20; ++i)
{out << QString("[DB_F") << QString("%1").arg(i) << QString("]\n"); out << current_db_f[i] << QString("\n");}
out << QString("[DB_FLAGS_END]\n");
setProgress(10); out.device()->seek(0);
out << (quint64)(ba.size() - sizeof(quint64));
current_db_test << ba;
for (int i = 0; i < LQListWidget->count(); ++i) {
ba.clear(); out << (quint64)0;
if (!TSAdvancedSetupGroupBox->isChecked()) {
out << current_db_questions.value(LQListWidget->item(i))->allPublicProperties() << QString("\n");
} else if (rbtnSelectFlags->isChecked()) {
if (used_items.contains(current_db_questions.value(LQListWidget->item(i))->flag())) {
out << current_db_questions.value(LQListWidget->item(i))->allPublicProperties() << QString("\n");
}
} else if (rbtnSelectQuestions->isChecked()) {
if (used_items.contains(i)) {
out << current_db_questions.value(LQListWidget->item(i))->allPublicProperties() << QString("\n");
}
}
setProgress(((90/current_db_questions.size())*(i+1))+10);
out.device()->seek(0);
out << (quint64)(ba.size() - sizeof(quint64));
current_db_test << ba;
}
disableAll(); actionQuit->setEnabled(false);
actionNew->setEnabled(false); actionOpen->setEnabled(false);
mainStackedWidget->setCurrentIndex(5); updateGeometry();
SMIPortLabel->setText(tr("The server is running on port <b>%1</b>. "
"You may now run the Test Writer on each client PC. "
"Do not quit the Database Editor while testing!")
.arg(tcpServer->serverPort()));
setProgress(100); setProgress(-1); statusBar()->showMessage("Server ready", 10000);
}
void MainWindow::stopServer()
{
switch (QMessageBox::information(this, tr("iTest - Stop server"), tr("Are you sure you want to stop the server?"), tr("&Stop"), tr("Cancel"), 0, 1)) {
case 0: break;
case 1: return; break;
}
tcpServer->close();
if (actionSave_session->isChecked() && (numIdentifiedClients() > 0)) {
Session * session = new Session;
session->setName(current_db_testname);
session->setDateTimeFromString(current_db_testdate);
session->setPassMark(TSPassMarkSpinBox->value());
for (int i = 0; i < SMSLListWidget->count(); ++i) {
session->addLogEntry(SMSLListWidget->item(i)->background().color().red(),
SMSLListWidget->item(i)->background().color().green(),
SMSLListWidget->item(i)->background().color().blue(),
SMSLListWidget->item(i)->foreground().color().red(),
SMSLListWidget->item(i)->foreground().color().green(),
SMSLListWidget->item(i)->foreground().color().blue(),
SMSLListWidget->item(i)->text());
}
for (int i = 0; i < SMLCListWidget->count(); ++i) {
if (SMLCListWidget->item(i)->isHidden()) continue;
Student * student = new Student (current_db_clients.value(SMLCListWidget->item(i)));
session->addStudent(student);
}
current_db_sessions.insert(session->dateTime(), session);
QListWidgetItem * item = new QListWidgetItem (QString("%1 - %2").arg(session->dateTimeToString()).arg(session->name()));
VSSLSListWidget->insertItem(0, item);
item->setData(Qt::UserRole, session->dateTime());
}
for (int i = 0; i < SMLCListWidget->count(); ++i) {
delete current_db_clients.value(SMLCListWidget->item(i));
}
current_db_clients.clear(); SMLCListWidget->clear(); SMSLListWidget->clear();
enableAll(); actionQuit->setEnabled(true);
actionNew->setEnabled(true); actionOpen->setEnabled(true);
setPage(actionEdit_test); togglePrintEnabled();
if (actionUse_last_save_date->isChecked()) {
actionUse_last_save_date->setChecked(false);
save();
actionUse_last_save_date->setChecked(true);
} else { save(); }
}
void MainWindow::addClient()
{
QTcpSocket * clientConnection = tcpServer->nextPendingConnection();
Client * client = new Client (this, clientConnection);
QObject::connect(clientConnection, SIGNAL(readyRead()), client, SLOT(readClientFeedback()));
QObject::connect(clientConnection, SIGNAL(error(QAbstractSocket::SocketError)),
client, SLOT(displayError(QAbstractSocket::SocketError)));
QObject::connect(client, SIGNAL(identified(Client *)),
this, SLOT(clientIdentified(Client *)));
QObject::connect(client, SIGNAL(finished(Client *)),
this, SLOT(clientFinished(Client *)));
QObject::connect(client, SIGNAL(resultsLoaded(Client *)),
this, SLOT(clientResultsLoaded(Client *)));
QObject::connect(client, SIGNAL(disconnected(Client *)),
this, SLOT(clientDisconnected(Client *)));
QListWidgetItem * item = new QListWidgetItem (QString("%1").arg(SMLCListWidget->count()+1), SMLCListWidget);
current_db_clients.insert(item, client);
client->setNumber(item->text().toInt());
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 connected").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(item->text()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(197, 255, 120)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
updateLC(client);
QByteArray client_number;
QDataStream out1(&client_number, QIODevice::WriteOnly);
out1.setVersion(QDataStream::Qt_4_2);
out1 << (quint32)(client->number() + QDate::currentDate().day() + QTime::currentTime().hour());
QByteArray num_entries;
QDataStream out2(&num_entries, QIODevice::WriteOnly);
out2.setVersion(QDataStream::Qt_4_2);
out2 << (quint64)current_db_test.count();
clientConnection->write(client_number);
clientConnection->write(num_entries);
clientConnection->write(current_db_test.at(0));
}
void MainWindow::clientIdentified(Client * client)
{
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 identified as %3").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(17, 120, 122)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(255, 255, 255)));
if (current_db_clients.value(SMLCListWidget->currentItem()) == client)
{ setCurrentClient(); }
updateLC(client); toggleSaveSessionEnabled();
}
void MainWindow::clientFinished(Client * client)
{
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 (%3) finished the exam").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(255, 251, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
}
void MainWindow::clientResultsLoaded(Client * client)
{
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 (%3) submitted results").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(221, 255, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
if (current_db_clients.value(SMLCListWidget->currentItem()) == client)
{ setCurrentClient(); }
updateLC(client); sendCorrectAnswers(client);
if (!printClientResults(client, default_printer)) {
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 (%3) > failed to print the client's results").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(255, 0, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
} else {
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 (%3) > results printed successfully").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(221, 255, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
}
}
void MainWindow::clientDisconnected(Client * client)
{
QListWidgetItem * log_entry = new QListWidgetItem;
SMSLListWidget->insertItem(0, log_entry);
if (client->isIdentified()) {
log_entry->setText(tr("%1 > Client #%2 (%3) disconnected").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
} else {
log_entry->setText(tr("%1 > Client #%2 disconnected").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()));
}
log_entry->setBackground(QBrush::QBrush(QColor::QColor(204, 109, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
if (current_db_clients.value(SMLCListWidget->currentItem()) == client)
{ setCurrentClient(); }
updateLC(client);
}
void MainWindow::setCurrentClient()
{
if (SMLCListWidget->currentIndex().isValid()) {
if (SMLCListWidget->currentItem()->isHidden())
{ disableSMSC(); clearSMSC(); togglePrintEnabled(); return; }
enableSMSC(); clearSMSC(); togglePrintEnabled();
Client * client = current_db_clients.value(SMLCListWidget->currentItem());
if (client->isIdentified()) { SMSCNameLabel->setText(client->name()); }
else { SMSCNameLabel->setText(tr("Not identified yet")); }
setClientStatus(client->socket()->state());
if (client->isReady()) {
SMSCScoreLabel->setText(tr("%1 out of %2 (%3)").arg(client->score()).arg(TSQnumSpinBox->value()).arg(TSPassMarkSpinBox->value() <= client->score() ? tr("PASSED") : tr("FAILED")));
loadClientResults(client->results(), SMSCResultsTableWidget);
}
} else {
disableSMSC(); clearSMSC(); togglePrintEnabled();
}
}
void MainWindow::loadClientResults(QMap<QString, QuestionAnswer> * results, QTableWidget * tw)
{
QMapIterator<QString, QuestionAnswer> i(*results); int row = 0;
QTableWidgetItem * item; QuestionAnswer qans;
tw->setRowCount(results->count());
while (i.hasNext()) {
i.next();
item = new QTableWidgetItem (i.key()); qans = i.value();
tw->setItem(row, 0, item);
item = new QTableWidgetItem (qans.isAnsweredCorrectly() ? tr("yes") : tr("no"));
if (qans.isAnsweredCorrectly()) {
item->setBackground(QBrush::QBrush(QColor::QColor(197, 255, 120)));
item->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
} else {
item->setBackground(QBrush::QBrush(QColor::QColor(204, 109, 0)));
item->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
}
tw->setItem(row, 1, item);
item = new QTableWidgetItem;
switch (qans.answered()) {
case QuestionItem::None: item->setText(tr("None")); break;
case QuestionItem::A: item->setText("A"); break;
case QuestionItem::B: item->setText("B"); break;
case QuestionItem::C: item->setText("C"); break;
case QuestionItem::D: item->setText("D"); break;
default: item->setText(tr("None")); break;
}
tw->setItem(row, 2, item);
item = new QTableWidgetItem;
switch (qans.correctAnswer()) {
case QuestionItem::None: item->setText(tr("None")); break;
case QuestionItem::A: item->setText("A"); break;
case QuestionItem::B: item->setText("B"); break;
case QuestionItem::C: item->setText("C"); break;
case QuestionItem::D: item->setText("D"); break;
default: item->setText(tr("None")); break;
}
tw->setItem(row, 3, item);
row++;
}
tw->resizeRowsToContents();
}
void MainWindow::sendCorrectAnswers(Client * client)
{
QMap<QString, QuestionAnswer> * results = client->results();
QByteArray correct_answers;
QDataStream out(&correct_answers, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_2);
out << (quint64)0;
QMapIterator<QString, QuestionAnswer> i(*results); QuestionAnswer qans;
while (i.hasNext()) {
i.next(); qans = i.value();
out << QString("[Q_NAME]\n") << i.key() << QString("\n[Q_C_ANS]\n");
out << QString("%1\n").arg(qans.correctAnswer());
}
out.device()->seek(0);
out << (quint64)(correct_answers.size() - sizeof(quint64));
client->socket()->write(correct_answers);
}
void MainWindow::updateLC(Client * client)
{
QList<QListWidgetItem *> client_items = current_db_clients.keys(client);
for (int i = 0; i < client_items.count(); ++i) {
if ((!client->isIdentified()) &&
(client->socket()->state() == QAbstractSocket::UnconnectedState)) {
client_items.at(i)->setHidden(true);
} else {client_items.at(i)->setHidden(false);}
if (client->isIdentified())
client_items.at(i)->setText(client->name());
switch (client->socket()->state()) {
case QAbstractSocket::UnconnectedState:
client_items.at(i)->setBackground(QBrush::QBrush(QColor::QColor(204, 109, 0)));
client_items.at(i)->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
break;
case QAbstractSocket::ConnectedState:
client_items.at(i)->setBackground(QBrush::QBrush(QColor::QColor(197, 255, 120)));
client_items.at(i)->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
break;
case QAbstractSocket::HostLookupState:
case QAbstractSocket::ConnectingState:
case QAbstractSocket::BoundState:
case QAbstractSocket::ClosingState:
case QAbstractSocket::ListeningState:
default:
client_items.at(i)->setBackground(QBrush::QBrush(QColor::QColor(201, 204, 0)));
client_items.at(i)->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
break;
}
}
}
int MainWindow::numIdentifiedClients()
{
int num = 0;
QMapIterator<QListWidgetItem *, Client *> i(current_db_clients);
while (i.hasNext()) { i.next(); if (i.value()->isIdentified()) { num++; } }
return num;
}
void MainWindow::toggleSaveSessionEnabled()
{
if ((mainStackedWidget->currentIndex() == 5) && (numIdentifiedClients() > 0)) {
actionSave_session->setEnabled(true);
} else { actionSave_session->setEnabled(false); }
}
void MainWindow::setClientStatus(QAbstractSocket::SocketState socketState)
{
switch (socketState) {
case QAbstractSocket::UnconnectedState:
SMSCStatusLabel->setText(tr("Disconnected")); break;
case QAbstractSocket::HostLookupState:
SMSCStatusLabel->setText(tr("Performing a host name lookup")); break;
case QAbstractSocket::ConnectingState:
SMSCStatusLabel->setText(tr("Connecting")); break;
case QAbstractSocket::ConnectedState:
SMSCStatusLabel->setText(tr("Connected")); break;
case QAbstractSocket::BoundState:
SMSCStatusLabel->setText(tr("Bound to an address and port")); break;
case QAbstractSocket::ClosingState:
SMSCStatusLabel->setText(tr("Closing")); break;
case QAbstractSocket::ListeningState:
SMSCStatusLabel->setText(tr("Listening")); break;
default:
SMSCStatusLabel->setText(tr("Unknown")); break;
}
}
void MainWindow::addOfflineClient()
{
QString file_name = QFileDialog::getOpenFileName(this, tr("Add off-line client"), "", tr("iTest off-line client logs (*.itcl);;All files (*.*)"));
if (file_name.isEmpty()) { return; }
if (!addOfflineClient(file_name)) {
QMessageBox::critical(this, tr("Add off-line client"), tr("Failed to add off-line client. Either this file contains client data of a different test session or it contains invalid data."));
}
}
bool MainWindow::addOfflineClient(QString file_name)
{
if (file_name.isEmpty()) return false;
QFile file(file_name);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::critical(this, tr("Add off-line client"), tr("Cannot read file %1:\n%2.").arg(file_name).arg(file.errorString()));
return true;
}
QTextStream rfile(&file);
rfile.setCodec("UTF-8");
if (rfile.readLine() != "[TEST_NAME]") return false;
if (rfile.readLine() != current_db_testname) return false;
if (rfile.readLine() != "[TEST_TIMESTAMP]") return false;
if (rfile.readLine() != current_db_testdate) return false;
if (rfile.readLine() != "[TIME_FINISHED]") return false;
rfile.readLine();
if (rfile.readLine() != "[CLIENT_NAME]") return false;
Client * client = new Client (this, rfile.readLine());
QListWidgetItem * item = new QListWidgetItem (QString("%1").arg(SMLCListWidget->count()+1), SMLCListWidget);
current_db_clients.insert(item, client);
client->setNumber(item->text().toInt()); item->setText(client->name());
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Client #%2 (%3) added").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")).arg(client->number()).arg(client->name()));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(0, 125, 163)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(255, 255, 255)));
updateLC(client); toggleSaveSessionEnabled();
QObject::connect(client, SIGNAL(resultsLoaded(Client *)),
this, SLOT(clientResultsLoaded(Client *)));
client->loadResults(rfile.readAll());
return true;
}
void MainWindow::addOfflineClients()
{
#ifdef Q_WS_WIN
QString dir_path = QFileDialog::getExistingDirectory(this, tr("Add off-line clients"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks | QFileDialog::DontUseNativeDialog);
#else
QString dir_path = QFileDialog::getExistingDirectory(this, tr("Add off-line clients"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
#endif
if (dir_path.isEmpty()) { return; }
QDir dir (dir_path);
QStringList filter; filter << "*.itcl";
QFileInfoList client_logs = dir.entryInfoList(filter, QDir::Files, QDir::Time);
if (client_logs.count() == 0) { QMessageBox::information(this, tr("Add off-line clients"), tr("No iTest client logs found in the folder you selected.")); }
for (int i = 0; i < client_logs.count(); ++i) {
if (!addOfflineClient(client_logs.at(i).absoluteFilePath())) {
QListWidgetItem * log_entry = new QListWidgetItem (tr("%1 > Failed to add off-line client").arg(QDateTime::currentDateTime().toString("yyyy.MM.dd-hh:mm:ss")));
SMSLListWidget->insertItem(0, log_entry);
log_entry->setBackground(QBrush::QBrush(QColor::QColor(204, 109, 0)));
log_entry->setForeground(QBrush::QBrush(QColor::QColor(0, 0, 0)));
}
}
}
void MainWindow::exportTest()
{
QString datetime = current_db_testdate; datetime.replace(13, 1, '.');
QString save_file_name = QFileDialog::getSaveFileName(this, tr("Export test"), QString("%1-%2.itos").arg(current_db_testname).arg(datetime), tr("iTest off-line test sessions (*.itos)"));
if (save_file_name.isNull() || save_file_name.isEmpty()) { return; }
QFile file(save_file_name);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::critical(this, tr("Export test"), tr("Cannot write file %1:\n%2.").arg(save_file_name).arg(file.errorString()));
return;
}
QTextStream sfile(&file);
sfile.setCodec("UTF-8");
for (int i = 0; i < current_db_test.count(); ++i) {
QDataStream in(current_db_test.at(i));
in.setVersion(QDataStream::Qt_4_2);
quint64 num; in >> num; QString buffer;
do {
in >> buffer; sfile << buffer;
} while (!in.atEnd());
setProgress(100 / current_db_test.count() * (i + 1)); }
setProgress(100); setProgress(-1); statusBar()->showMessage(tr("Test exported"), 10000);
}
void MainWindow::exportLog()
{
QListWidget * lw; QString testname; QString datetime;
if (mainStackedWidget->currentIndex() == 5) {
lw = SMSLListWidget; testname = current_db_testname;
datetime = QDateTime::currentDateTime().toString("yyyy.MM.dd-hh.mm");
} else if (mainStackedWidget->currentIndex() == 6) {
if (current_db_session == NULL) { return; }
lw = VSSSLListWidget; testname = current_db_session->name();
datetime = current_db_session->dateTimeToString();
datetime.replace(13, 1, '.');
} else { return; }
QString timestamp = datetime; timestamp.replace(13, 1, ':');
QString save_file_name = QFileDialog::getSaveFileName(this, tr("Export server log"), QString("%1-%2.html").arg(testname).arg(datetime), tr("iTest Server logs (*.html)"));
if (save_file_name.isNull() || save_file_name.isEmpty()) { return; }
QFile file(save_file_name);
if (!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::critical(this, tr("Export server log"), tr("Cannot write file %1:\n%2.").arg(save_file_name).arg(file.errorString()));
return;
}
QTextStream sfile(&file);
sfile.setCodec("UTF-8");
setProgress(0); sfile << "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><title>" << endl;
sfile << tr("iTest Server Log") << " - " << testname << " - ";
sfile << timestamp << endl << "</title></head><body>" << endl;
for (int i = 0; i < lw->count(); ++i) {
sfile << "<div style=\"background-color: rgb(";
sfile << lw->item(i)->background().color().red() << ", ";
sfile << lw->item(i)->background().color().green() << ", ";
sfile << lw->item(i)->background().color().blue() << "); ";
sfile << "color: rgb(";
sfile << lw->item(i)->foreground().color().red() << ", ";
sfile << lw->item(i)->foreground().color().green() << ", ";
sfile << lw->item(i)->foreground().color().blue() << ")\">";
sfile << endl << lw->item(i)->text() << "\n</div>" << endl;
setProgress(100 / lw->count() * i); }
sfile << "</body></html>" << endl;
setProgress(100); setProgress(-1); }
void MainWindow::enableSMSC()
{
SMSelectedClientGroupBox->setEnabled(true);
}
void MainWindow::disableSMSC()
{
SMSelectedClientGroupBox->setEnabled(false);
}
void MainWindow::clearSMSC()
{
SMSCNameLabel->setText(tr("Not identified yet"));
SMSCStatusLabel->setText(tr("Disconnected"));
SMSCScoreLabel->setText(tr("Not ready yet"));
SMSCResultsTableWidget->setRowCount(0);
}
void MainWindow::enableSMTools()
{
switch (mainStackedWidget->currentIndex()) {
case 4:
actionStart_server->setEnabled(true);
actionStop_server->setEnabled(false);
actionExport_test->setEnabled(false);
actionAdd_offline_client->setEnabled(false);
actionAdd_offline_clients->setEnabled(false);
actionExport_log->setEnabled(false);
actionSave_session->setEnabled(false);
break;
case 5:
actionStart_server->setEnabled(false);
actionStop_server->setEnabled(true);
actionExport_test->setEnabled(true);
actionAdd_offline_client->setEnabled(true);
actionAdd_offline_clients->setEnabled(true);
actionExport_log->setEnabled(true);
toggleSaveSessionEnabled();
break;
default:
actionStart_server->setEnabled(false);
actionStop_server->setEnabled(false);
actionExport_test->setEnabled(false);
actionAdd_offline_client->setEnabled(false);
actionAdd_offline_clients->setEnabled(false);
actionExport_log->setEnabled(false);
actionSave_session->setEnabled(false);
break;
}
}
void MainWindow::togglePrintEnabled()
{
if ((mainStackedWidget->currentIndex() == 5) && (SMLCListWidget->currentIndex().isValid())) {
actionQuickPrint->setEnabled(true);
actionPrint->setEnabled(true);
actionPrint_session_summary->setEnabled(false);
actionPrint_all->setEnabled(false);
} else if ((mainStackedWidget->currentIndex() == 6) && (VSSLCListWidget->currentIndex().isValid())) {
actionQuickPrint->setEnabled(false);
actionPrint->setEnabled(true);
if (VSSCSGroupBox->isEnabled()) {
actionPrint_session_summary->setEnabled(true);
} else { actionPrint_session_summary->setEnabled(false); }
if (VSSLCListWidget->count() > 0) { actionPrint_all->setEnabled(true); }
else { actionPrint_all->setEnabled(false); }
} else if ((mainStackedWidget->currentIndex() == 6) && (!VSSLCListWidget->currentIndex().isValid())) {
actionQuickPrint->setEnabled(false);
actionPrint->setEnabled(false);
if (VSSCSGroupBox->isEnabled()) {
actionPrint_session_summary->setEnabled(true);
} else { actionPrint_session_summary->setEnabled(false); }
if (VSSLCListWidget->count() > 0) { actionPrint_all->setEnabled(true); }
else { actionPrint_all->setEnabled(false); }
} else {
actionQuickPrint->setEnabled(false);
actionPrint->setEnabled(false);
actionPrint_session_summary->setEnabled(false);
actionPrint_all->setEnabled(false);
}
}
void MainWindow::clearSM()
{
TSAdvancedSetupGroupBox->setChecked(false);
rbtnSelectFlags->setChecked(true);
TSSearchAvailableLineEdit->clear();
TSSearchUsedLineEdit->clear();
TSExcludeListWidget->clear();
TSIncludeListWidget->clear();
TSMaxQnumCheckBox->setChecked(false);
rbtnTestTime->setChecked(true);
TSTestTimeEdit->setTime(QTime::QTime(0, 0));
TSQuestionTimeEdit->setTime(QTime::QTime(0, 0));
}