/***************************************************************************
kwqquizmodel.cpp
-------------------
copyright : (C) 2008-2009 by Peter Hedlund
email : peter.hedlund@kdemail.net
***************************************************************************/
/***************************************************************************
* *
* 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 "kwqquizmodel.h"
#include "kwqsortfiltermodel.h"
#include "kwqtablemodel.h"
#include "krandomsequence.h"
#include "prefs.h"
KWQQuizModel::KWQQuizModel(QObject *parent) : QSortFilterProxyModel(parent)
{
m_sourceModel = 0;
m_currentQuestion = 0;
setSortCaseSensitivity(Qt::CaseInsensitive);
setFilterCaseSensitivity(Qt::CaseInsensitive);
setFilterKeyColumn(-1);
m_list.clear();
m_errorList.clear();
m_quizList.clear();
}
void KWQQuizModel::setSourceModel(KWQSortFilterModel * sourceModel)
{
m_sourceModel = sourceModel;
QSortFilterProxyModel::setSourceModel(sourceModel);
}
KWQSortFilterModel * KWQQuizModel::sourceModel() const
{
return m_sourceModel;
}
bool KWQQuizModel::lessThan(const QModelIndex & left, const QModelIndex & right) const
{
return m_list[left.row()] < m_list[right.row()];
}
bool KWQQuizModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QString text;
text.clear();
for (int i = 0 ; i < 2; i++)
text.append(sourceModel()->data(sourceModel()->index(sourceRow, i, sourceParent), Qt::DisplayRole).toString());
return !text.isEmpty();
}
int KWQQuizModel::column(int i)
{
int result = 0;
if (isOdd(m_quizMode))
result = 1;
if ((m_quizMode == 5) && qAbs(i) == i)
result = 0;
return result;
}
bool KWQQuizModel::atEnd()
{
return m_currentQuestion >= questionCount();
}
void KWQQuizModel::toNext()
{
++m_currentQuestion;
}
bool KWQQuizModel::hasErrors()
{
if (m_quizType == Prefs::EnumStartSession::MultipleChoice)
return m_errorList.count() > 2; //this is a hack until better multiple choice is written
else
return !m_errorList.isEmpty();
}
bool KWQQuizModel::init()
{
if (m_sourceModel == 0)
return false;
invalidate();
//check if enough in list
bool result = false;
switch (m_quizType) {
case Prefs::EnumStartSession::Editor:
//
break;
case Prefs::EnumStartSession::Flashcard:
result = (rowCount(QModelIndex()) > 0);
break;
case Prefs::EnumStartSession::QA:
result = (rowCount(QModelIndex()) > 0);
break;
case Prefs::EnumStartSession::MultipleChoice:
result = (rowCount(QModelIndex()) > 2);
break;
}
if (!result)
return false;
m_quizList.clear();
for (int i = 0; i < rowCount(QModelIndex()); ++i) {
m_quizList.append(i);
if (m_quizMode == 5)
m_quizList.append(-i);
}
activateBaseList();
return true;
}
void KWQQuizModel::activateBaseList()
{
m_list.clear();
m_errorList.clear();
foreach(int l, m_quizList)
m_list.append(l);
if (m_quizMode > 2) {
KRandomSequence rs;
rs.randomize(m_list);
};
m_questionCount = m_list.count();
m_currentQuestion = 0;
}
bool KWQQuizModel::checkAnswer(const QString & a)
{
bool result = false;
QString ans = a;
int row = m_list.at(m_currentQuestion);
QString tTemp = data(index(qAbs(row), column(row), QModelIndex()), Qt::DisplayRole).toString();
tTemp = tTemp.simplified();
ans = ans.simplified();
if (m_quizType == Prefs::EnumStartSession::QA) {
if (!m_correctBlank.isEmpty()) {
QStringList la, ls;
if (ans.indexOf(';') > 0)
ls = ans.split(';', QString::SkipEmptyParts);
else
ls.append(ans);
if (m_correctBlank.indexOf(';') > 0)
la = m_correctBlank.split(';', QString::SkipEmptyParts);
else
la.append(m_correctBlank);
result = (ls.count() == la.count());
if (result) {
for (int counter = 0; counter < la.count(); counter++) {
result = (ls[counter].simplified() == la[counter].simplified());
if (!result)
break;
}
}
}
else
{
result = (ans == tTemp);
}
}
else
{
if (m_quizType == Prefs::EnumStartSession::MultipleChoice) {
if (Prefs::enableBlanks()) {
tTemp.remove('[');
tTemp.remove(']');
}
result = (ans == tTemp);
}
else
{
result = (ans == tTemp);
}
}
///@todo currently the Leitner stuff crashes KWQ
//QString tmpLeitner( m_doc->entry(li.oneOp())->leitnerBox() );
if (!result) {
//m_doc->entry(li.oneOp())->setLeitnerBox(m_doc->leitnerSystem()->wrongBox( tmpLeitner ));
m_errorList.append(row);
}
//else
//m_doc->entry(li.oneOp())->setLeitnerBox(m_doc->leitnerSystem()->correctBox( tmpLeitner ));
return result;
}
QStringList KWQQuizModel::multiOptions()
{
QStringList ls;
KRandomSequence rs;
int a = -1;
int b = -1;
do
a = rs.getLong(m_questionCount);
while(a == m_currentQuestion);
do
b = rs.getLong(m_questionCount);
while(b == m_currentQuestion || b == a);
int row = m_list.at(m_currentQuestion);
int col = column(row);
if (col == 0)
col = 0;
else
col = 1;
ls.append(data(index(qAbs(row), col, QModelIndex()), Qt::DisplayRole).toString());
row = m_list.at(a);
ls.append(data(index(qAbs(row), col, QModelIndex()), Qt::DisplayRole).toString());
row = m_list.at(b);
ls.append(data(index(qAbs(row), col, QModelIndex()), Qt::DisplayRole).toString());
if (Prefs::enableBlanks()) {
for (int i = 0; i < ls.count(); i++) {
ls[i].remove('[');
ls[i].remove(']');
}
}
rs.randomize(ls);
return ls;
}
QString KWQQuizModel::quizIcon(QuizIcon ico)
{
QString s = "question";
int col = column(m_list.at(m_currentQuestion));
if (ico == IconLeftCol) {
if (col == 0)
s = "answer";
}
if (ico == IconRightCol) {
if (col != 0)
s = "answer";
}
return s;
}
QString KWQQuizModel::yourAnswer(const QString & s)
{
QString result = s;
if (!m_answerBlank.isEmpty()) {
result.clear();
QStringList ls;
if (s.indexOf(';') > 0)
ls = s.split(';');
else
ls.append(s);
result = m_answerBlank.replace("..........", "");
int offset = 0, counter = 0;
while (offset >= 0) {
offset = result.indexOf("", offset);
if (offset >= 0) {
result.insert(offset + 3, ls[counter]);
offset++;
counter++;
}
}
result.append("");
result.prepend("");
}
return result;
}
QString KWQQuizModel::hint()
{
if (!m_correctBlank.isEmpty())
return m_correctBlank;
else
return answer();
}
QString KWQQuizModel::question()
{
int row = m_list.at(m_currentQuestion);
int col = column(row);
if (col == 0)
col = 1;
else
col = 0;
QString s = data(index(qAbs(row), col, QModelIndex()), Qt::DisplayRole).toString();
if (Prefs::enableBlanks()) {
s.remove('[');
s.remove(']');
}
if (m_quizType != Prefs::EnumStartSession::Flashcard && m_currentQuestion > 0)
emit checkingAnswer(m_list.at(m_currentQuestion - 1));
else
emit checkingAnswer(row);
return s;
}
QString KWQQuizModel::blankAnswer()
{
QString r = "";
m_correctBlank.clear();
m_answerBlank.clear();
QString tTemp;
if (m_quizType == Prefs::EnumStartSession::QA && Prefs::enableBlanks()) {
int row = m_list.at(m_currentQuestion);
tTemp = data(index(qAbs(row), column(row), QModelIndex()), Qt::DisplayRole).toString();
r = tTemp;
QRegExp rx;
rx.setMinimal(true);
rx.setPattern("\\[.*\\]");
r.replace(rx, "..........");
if (r != tTemp) {
m_answerBlank = r;
int offset = 0;
while (offset >= 0) {
offset = rx.indexIn(tTemp, offset);
if (offset >= 0) {
if (m_correctBlank.length() > 0)
m_correctBlank = m_correctBlank + "; " + tTemp.mid(offset + 1, tTemp.indexOf(']', offset) - offset - 1);
else
m_correctBlank = tTemp.mid(offset + 1, tTemp.indexOf(']', offset) - offset - 1);
offset++;
}
}
}
}
return m_answerBlank;
}
QString KWQQuizModel::answer()
{
int row = m_list.at(m_currentQuestion);
QString s = data(index(qAbs(row), column(row), QModelIndex()), Qt::DisplayRole).toString();
if (m_quizType == Prefs::EnumStartSession::QA) {
if (Prefs::enableBlanks()) {
s.replace('[', "");
s.replace(']', "");
s.prepend("");
s.append("");
}
}
else
{
if (Prefs::enableBlanks()) {
s.remove('[');
s.remove(']');
}
}
return s;
}
QString KWQQuizModel::langQuestion()
{
if (column(m_list.at(m_currentQuestion)) == 1)
return headerData(0, Qt::Horizontal, Qt::DisplayRole).toString();
else
return headerData(1, Qt::Horizontal, Qt::DisplayRole).toString();
}
QString KWQQuizModel::langAnswer()
{
if (column(m_list.at(m_currentQuestion)) == 0)
return headerData(0, Qt::Horizontal, Qt::DisplayRole).toString();
else
return headerData(1, Qt::Horizontal, Qt::DisplayRole).toString();;
}
QString KWQQuizModel::kbAnswer()
{
int col = column(m_list.at(m_currentQuestion));
QString result;
if (col == 0)
return headerData(0, Qt::Horizontal, KWQTableModel::KeyboardLayoutRole).toString();
if (col == 1)
return headerData(1, Qt::Horizontal, KWQTableModel::KeyboardLayoutRole).toString();
return result;
}
int KWQQuizModel::questionCount()
{
return m_questionCount;
}
void KWQQuizModel::finish()
{
emit checkingAnswer(-1);
}
void KWQQuizModel::setQuizType(Prefs::EnumStartSession::type qt)
{
m_quizType = qt;
}
void KWQQuizModel::setQuizMode(int qm)
{
m_quizMode = qm;
}
void KWQQuizModel::activateErrorList()
{
m_list.clear();
foreach(int i, m_errorList)
m_list.append(i);
m_errorList.clear();
m_questionCount = m_list.count();
m_currentQuestion = 0;
}
inline bool KWQQuizModel::isOdd(int value) const { return value & 0x1; }