/*************************************************************************** manage queries ----------------------------------------------------------------------- begin : Sat Jul 11 20:50:53 MET 1999 copyright : (C) 1999-2001 Ewald Arnold (C) 2001 The KDE-EDU team (C) 2005 Peter Hedlund ----------------------------------------------------------------------- ***************************************************************************/ /*************************************************************************** * * * 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 #include #include #include using namespace std; #include "QueryManager.h" #include "kvoctraincore.h" #include vector 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 QueryManager::getRelation (bool only_maintypes) { vector 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 &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 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; }