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/kvoctrain/kvoctrain/kvt-core/QueryManager.cpp

674 lines
18 KiB

/***************************************************************************
manage queries
-----------------------------------------------------------------------
begin : Sat Jul 11 20:50:53 MET 1999
copyright : (C) 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
(C) 2001 The KDE-EDU team
(C) 2005 Peter Hedlund <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 <tdelocale.h>
#include <tdeconfig.h>
#include <iostream>
#include <vector>
using namespace std;
#include "QueryManager.h"
#include "kvoctraincore.h"
#include <prefs.h>
vector<TQString> QueryManager::userTypes;
struct t_type_rel
{
const char *short_ref;
const char *long_ref;
};
// types are hierarchical !
// - . divides main from sub type
// - sub types must follow main type
// user types are strings-references like this: #1
static t_type_rel InternalTypeRelations [] =
{
{ TQM_ADJ, I18N_NOOP("Adjective") },
{ TQM_ADV, I18N_NOOP("Adverb") },
{ TQM_ART, I18N_NOOP("Article") },
{ TQM_ART TQM_TYPE_DIV TQM_ART_DEF, I18N_NOOP("Article Definite") },
{ TQM_ART TQM_TYPE_DIV TQM_ART_IND, I18N_NOOP("Article Indefinite") },
{ TQM_CON, I18N_NOOP("Conjunction") },
{ TQM_NAME, I18N_NOOP("Name") }, // old type "3"
{ TQM_NOUN, I18N_NOOP("Noun") }, // old type "2"
{ TQM_NOUN TQM_TYPE_DIV TQM_NOUN_M, I18N_NOOP("Noun Male") },
{ TQM_NOUN TQM_TYPE_DIV TQM_NOUN_F, I18N_NOOP("Noun Female") },
{ TQM_NOUN TQM_TYPE_DIV TQM_NOUN_S, I18N_NOOP("Noun Neutral") },
{ TQM_NUM, I18N_NOOP("Numeral") },
{ TQM_NUM TQM_TYPE_DIV TQM_NUM_ORD, I18N_NOOP("Numeral Ordinal") },
{ TQM_NUM TQM_TYPE_DIV TQM_NUM_CARD, I18N_NOOP("Numeral Cardinal") },
{ TQM_PHRASE, I18N_NOOP("Phrase") },
{ TQM_PREP, I18N_NOOP("Preposition") },
{ TQM_PRON, I18N_NOOP("Pronoun") },
{ TQM_PRON TQM_TYPE_DIV TQM_PRON_POS, I18N_NOOP("Pronoun Possessive") },
{ TQM_PRON TQM_TYPE_DIV TQM_PRON_PER, I18N_NOOP("Pronoun Personal") },
{ TQM_QUEST, I18N_NOOP("Question") },
{ TQM_VERB, I18N_NOOP("Verb") }, // old type "1"
{ TQM_VERB TQM_TYPE_DIV TQM_VERB_IRR, I18N_NOOP("Verb Irregular") },
{ TQM_VERB TQM_TYPE_DIV TQM_VERB_REG, I18N_NOOP("Verb Regular") },
{ 0, 0 } // the end
};
TQString QueryManager::getSubType (const TQString & type)
{
int i;
TQString t = type;
if ((i = t.find(TQM_TYPE_DIV)) >= 0) {
t.remove(0, i+1);
return t;
}
else
return TQString();
}
TQString QueryManager::getMainType (const TQString & type)
{
int i;
if ((i = type.find(TQM_TYPE_DIV)) >= 0)
return type.left(i);
else
return type;
}
QueryManager::QueryManager()
{
lessonitems.clear();
}
QuerySelection QueryManager::select(kvoctrainDoc *doc, int act_lesson, int oindex, int tindex)
{
QuerySelection random;
random.resize(doc->numLessons()+1);
for (int i = 0; i < doc->numEntries(); i++)
doc->getEntry(i)->setInQuery(false);
// selecting might take rather long
int ent_no = 0;
int ent_percent = doc->numEntries() / 100;
float f_ent_percent = doc->numEntries() / 100.0;
emit doc->progressChanged(doc, 0);
//Note that Leitner style learning (altlearn) normally only uses 20
//entries, we just ignore that here
for (int i = 0; i < doc->numEntries(); i++) {
ent_no++;
if (ent_percent != 0 && (ent_no % ent_percent) == 0 )
emit doc->progressChanged(doc, int (ent_no / f_ent_percent));
kvoctrainExpr *expr = doc->getEntry(i);
unsigned int lessonno;
if (Prefs::altLearn())
lessonno = 0; //We only use a single array in Leitner style
else
lessonno = expr->getLesson();
if (expr->isActive() ){
if (Prefs::swapDirection()) {
if ( validate (expr, act_lesson, oindex, tindex)
|| validate (expr, act_lesson, tindex, oindex)) {
random[lessonno].push_back (QueryEntryRef(expr, i));
expr->setInQuery(true);
}
}
else {
if (validate (expr, act_lesson, oindex, tindex)) {
random[lessonno].push_back (QueryEntryRef(expr, i));
expr->setInQuery(true);
}
}
}
}
// remove empty lesson elements
for (int i = (int) random.size()-1; i >= 0; i--)
if (random[i].size() == 0)
random.erase(random.begin() + i);
return random;
}
bool QueryManager::validate(kvoctrainExpr *expr, int act_lesson, int oindex, int tindex)
{
int index = tindex ? tindex : oindex;
if ((compareExpiring(expr->getGrade(index, oindex != 0),
expr->getQueryDate(index, oindex != 0), Prefs::expire())
||
(
compareGrade ((CompType) Prefs::compType(Prefs::EnumType::Grade), expr->getGrade(index, oindex != 0), Prefs::gradeItem())
&& compareQuery ((CompType) Prefs::compType(Prefs::EnumType::Query), expr->getQueryCount(index, oindex != 0), Prefs::queryItem())
&& compareBad ((CompType) Prefs::compType(Prefs::EnumType::Bad), expr->getBadCount(index, oindex != 0), Prefs::badItem())
&& compareDate ((CompType) Prefs::compType(Prefs::EnumType::Date), expr->getQueryDate(index, oindex != 0), Prefs::dateItem())
&& compareBlocking(expr->getGrade(index, oindex != 0),
expr->getQueryDate(index, oindex != 0), Prefs::block())
)
)
// lesson + word type must ALWAYS match
// (and there must be a word on both sides)
&& compareLesson ((CompType) Prefs::compType(Prefs::EnumType::Lesson), expr->getLesson(), lessonitems, act_lesson)
&& compareType ((CompType) Prefs::compType(Prefs::EnumType::WordType), expr->getType(index), Prefs::typeItem())
&& !expr->getOriginal().stripWhiteSpace().isEmpty()
&& !expr->getTranslation(index).stripWhiteSpace().isEmpty()
)
return true;
else
return false;
}
QuerySelection QueryManager::select(kvoctrainDoc *doc, int act_lesson, int idx, TQString type)
{
QuerySelection random;
random.resize(doc->numLessons()+1);
for (int i = 0; i < doc->numEntries(); i++)
doc->getEntry(i)->setInQuery(false);
// selecting might take rather long
int ent_no = 0;
int ent_percent = doc->numEntries() / 100;
float f_ent_percent = doc->numEntries() / 100.0;
emit doc->progressChanged(doc, 0);
for (int i = 0; i < doc->numEntries(); i++) {
ent_no++;
if (ent_percent != 0 && (ent_no % ent_percent) == 0 )
emit doc->progressChanged(doc, int (ent_no / f_ent_percent));
kvoctrainExpr *expr = doc->getEntry(i);
if (expr->isActive() && validate (expr, act_lesson, idx, type)) {
random[expr->getLesson()].push_back (QueryEntryRef(expr, i));
expr->setInQuery(true);
}
}
// remove empty lesson elements
for (int i = (int) random.size()-1; i >= 0; i--)
if (random[i].size() == 0)
random.erase(random.begin() + i);
return random;
}
bool QueryManager::validate(kvoctrainExpr *expr, int act_lesson, int idx, TQString query_type)
{
TQString qtype;
int pos = query_type.find (TQM_TYPE_DIV);
if (pos >= 0)
qtype = query_type.left (pos);
else
qtype = query_type;
TQString expr_type = expr->getType(idx);
bool type_ok = false;
if (qtype == TQM_NOUN) {
type_ok = expr_type == TQM_NOUN TQM_TYPE_DIV TQM_NOUN_S
|| expr_type == TQM_NOUN TQM_TYPE_DIV TQM_NOUN_M
|| expr_type == TQM_NOUN TQM_TYPE_DIV TQM_NOUN_F;
}
else if (qtype == TQM_VERB) {
type_ok = ( expr_type == TQM_VERB
|| expr_type == TQM_VERB TQM_TYPE_DIV TQM_VERB_IRR
|| expr_type == TQM_VERB TQM_TYPE_DIV TQM_VERB_REG
)
&& expr->getConjugation(idx).numEntries() > 0;
}
else if (qtype == TQM_ADJ) {
type_ok = expr_type == TQM_ADJ
&& !expr->getComparison(idx).isEmpty();
}
else
return false;
if (compareLesson ((CompType) Prefs::compType(Prefs::EnumType::Lesson), expr->getLesson(),
lessonitems, act_lesson)
&& type_ok) {
return true;
}
else {
return false;
}
}
QuerySelection QueryManager::select(kvoctrainDoc *doc, int act_lesson, int idx, QueryType type)
{
QuerySelection random;
random.resize(doc->numLessons()+1);
for (int i = 0; i < doc->numEntries(); i++)
doc->getEntry(i)->setInQuery(false);
// selecting might take rather long
int ent_no = 0;
int ent_percent = doc->numEntries() / 100;
float f_ent_percent = doc->numEntries() / 100.0;
emit doc->progressChanged(doc, 0);
for (int i = 0; i < doc->numEntries(); i++) {
ent_no++;
if (ent_percent != 0 && (ent_no % ent_percent) == 0 )
emit doc->progressChanged(doc, int (ent_no / f_ent_percent));
kvoctrainExpr *expr = doc->getEntry(i);
if (expr->isActive() && validate (expr, act_lesson, idx, type)) {
random[expr->getLesson()].push_back (QueryEntryRef(expr, i));
expr->setInQuery(true);
}
}
// remove empty lesson elements
for (int i = (int) random.size()-1; i >= 0; i--)
if (random[i].size() == 0)
random.erase(random.begin() + i);
return random;
}
bool QueryManager::validate(kvoctrainExpr *expr, int act_lesson, int idx, QueryType query_type)
{
bool type_ok = false;
if (query_type == TQT_Synonym) {
type_ok = !expr->getSynonym(idx).stripWhiteSpace().isEmpty();
}
else if (query_type == TQT_Antonym) {
type_ok = !expr->getAntonym(idx).stripWhiteSpace().isEmpty();
}
else if (query_type == TQT_Paraphrase) {
type_ok = !expr->getParaphrase(idx).stripWhiteSpace().isEmpty();
}
else if (query_type == TQT_Example) {
type_ok = !expr->getExample(idx).stripWhiteSpace().isEmpty();
}
if (compareLesson ((CompType) Prefs::compType(Prefs::EnumType::Lesson), expr->getLesson(),
lessonitems, act_lesson)
&& type_ok)
return true;
return false;
}
TQString QueryManager::compStr(Prefs::EnumCompType::type type)
{
TQString str = "???";
switch (type)
{
case DontCare: str = i18n("Do not Care"); break;
case WorseThan: str = i18n("Worse Than"); break;
case WorseEqThan: str = i18n("Equal/Worse Than"); break;
case MoreThan: str = i18n(">"); break;
case MoreEqThan: str = i18n(">="); break;
case BetterEqThan: str = i18n("Equal/Better Than"); break;
case BetterThan: str = i18n("Better Than"); break;
case LessEqThan: str = i18n("<="); break;
case LessThan: str = i18n("<"); break;
case EqualTo : str = i18n("Equal To"); break;
case NotEqual: str = i18n("Not Equal"); break;
case OneOf : str = i18n("Contained In"); break;
case NotOneOf: str = i18n("Not Contained In"); break;
case Within : str = i18n("Within Last"); break;
case Before : str = i18n("Before"); break;
case NotQueried: str = i18n("Not Queried"); break;
case Current : return i18n("Current Lesson"); break;
case NotAssigned: return i18n("Not Assigned"); break;
default:
;
}
return str;
}
TQString QueryManager::gradeStr (int i)
{
switch (i) {
case KV_NORM_GRADE: return i18n(KV_NORM_TEXT); break;
case KV_LEV1_GRADE: return i18n(KV_LEV1_TEXT); break;
case KV_LEV2_GRADE: return i18n(KV_LEV2_TEXT); break;
case KV_LEV3_GRADE: return i18n(KV_LEV3_TEXT); break;
case KV_LEV4_GRADE: return i18n(KV_LEV4_TEXT); break;
case KV_LEV5_GRADE: return i18n(KV_LEV5_TEXT); break;
case KV_LEV6_GRADE: return i18n(KV_LEV6_TEXT); break;
case KV_LEV7_GRADE: return i18n(KV_LEV7_TEXT); break;
default: return i18n(KV_LEV1_TEXT); break;
}
}
vector<TypeRelation> QueryManager::getRelation (bool only_maintypes)
{
vector<TypeRelation> vec;
for (int i = 0; i < (int) userTypes.size(); i++) {
TQString s;
s.setNum(i+1);
s.insert(0, TQM_USER_TYPE);
vec.push_back(TypeRelation(s, userTypes[i]));
}
t_type_rel *type = InternalTypeRelations;
while (type->short_ref != 0) {
if (!only_maintypes || strstr (type->short_ref, TQM_TYPE_DIV) == 0)
vec.push_back(TypeRelation(type->short_ref, i18n(type->long_ref)));
type++;
}
return vec;
}
TQString QueryManager::typeStr (const TQString id)
{
if (id.left(1) == TQM_USER_TYPE) {
TQString num = id;
num.remove (0, 1);
int i = num.toInt()-1;
if (i >= 0 && i < (int) userTypes.size() )
return userTypes[i];
else
return TQString();
}
else {
t_type_rel *type = InternalTypeRelations;
while (type->short_ref != 0) {
if (type->short_ref == id)
return i18n(type->long_ref);
type++;
}
}
return TQString();
}
bool QueryManager::compareBlocking (int grade, int date, bool use_it)
{
time_t cmp = Prefs::blockItem(grade);
if (grade == KV_NORM_GRADE || cmp == 0 || !use_it) // don't care || all off
return true;
else {
time_t now = time(0);
return date+cmp < now;
}
}
bool QueryManager::compareExpiring (int grade, int date, bool use_it)
{
time_t cmp = Prefs::expireItem(grade);
if (grade == KV_NORM_GRADE || cmp == 0 || !use_it) // don't care || all off
return false;
else {
time_t now = time(0);
return date+cmp < now;
}
}
bool QueryManager::compareDate (CompType type, time_t qd, time_t limit)
{
time_t now = time(0);
bool erg = true;
switch (type) {
case DontCare: erg = true;
break;
case Before: erg = qd == 0 || qd < now-limit; // never queried or older date
break;
case Within: erg = qd >= now-limit; // newer date
break;
case NotQueried: erg = qd == 0;
break;
default:
;
}
return erg;
}
bool QueryManager::compareQuery (CompType type, int qgrade, int limit)
{
bool erg = true;
switch (type) {
case DontCare: erg = true;
break;
case MoreThan: erg = qgrade > limit; // sel has higher query count
break;
case MoreEqThan: erg = qgrade >= limit;
break;
case EqualTo: erg = qgrade == limit;
break;
case NotEqual: erg = qgrade != limit;
break;
case LessEqThan: erg = qgrade <= limit; // sel has less count
break;
case LessThan: erg = qgrade < limit;
break;
default:
;
}
return erg;
}
bool QueryManager::compareBad (CompType type, int bcount, int limit)
{
bool erg = true;
switch (type) {
case DontCare: erg = true;
break;
case MoreThan: erg = bcount > limit; // sel has higher bad count
break;
case MoreEqThan: erg = bcount >= limit;
break;
case EqualTo: erg = bcount == limit;
break;
case NotEqual: erg = bcount != limit;
break;
case LessEqThan: erg = bcount <= limit; // sel has less count
break;
case LessThan: erg = bcount < limit;
break;
default:
;
}
return erg;
}
bool QueryManager::compareGrade (CompType type, grade_t qgrade, grade_t limit)
{
bool erg = true;
switch (type) {
case DontCare: erg = true;
break;
case WorseThan: erg = qgrade < limit; // sel has worse grade
break;
case WorseEqThan: erg = qgrade <= limit;
break;
case EqualTo: erg = qgrade == limit;
break;
case NotEqual: erg = qgrade != limit;
break;
case BetterEqThan: erg = qgrade >= limit; // sel has better grade
break;
case BetterThan: erg = qgrade > limit;
break;
default:
;
}
return erg;
}
bool QueryManager::compareType (CompType type, const TQString & exprtype, const TQString & limit)
{
bool erg = true;
switch (type) {
case DontCare: erg = true;
break;
case EqualTo: erg = getMainType(exprtype) == getMainType(limit); // type is same
break;
case NotEqual: erg = getMainType(exprtype) != getMainType(limit); // other type
break;
default:
;
}
return erg;
}
bool QueryManager::compareLesson (CompType type, int less, const vector<int> &limit, int current)
{
bool erg = true;
switch (type) {
case DontCare:
erg = true;
break;
case OneOf:
{
erg = false;
for (int i = 0; !erg && i < (int) limit.size(); i++)
if (limit[i] == less)
erg = true;
}
break;
case NotOneOf:
{
erg = true;
for (int i = 0; erg && i < (int) limit.size(); i++)
if (limit[i] == less)
erg = false;
}
break;
case Current:
erg = less == current;
break;
case NotAssigned:
erg = less == 0;
break;
default:
;
}
return erg;
}
void QueryManager::setTypeNames (vector<TQString> names)
{
userTypes = names;
}
void QueryManager::setLessonItemStr (const TQString & indices)
{
int pos;
TQString indices_copy = indices;
lessonitems.clear();
while ((pos = indices_copy.find(' ')) >= 0) {
TQString s = indices_copy.left(pos);
indices_copy.remove(0, pos+1);
lessonitems.push_back(s.toInt());
}
if (indices_copy.length() != 0) {
lessonitems.push_back(indices_copy.toInt());
}
}
TQString QueryManager::lessonItemStr() const
{
TQString s, ret;
for (int i = 0; i < (int) lessonitems.size(); i++) {
s.setNum (lessonitems[i]);
if (i != 0)
ret += ' ';
ret += s;
}
return ret;
}