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.
955 lines
22 KiB
955 lines
22 KiB
/**
|
|
This file is part of Kiten, a KDE Japanese Reference Tool...
|
|
Copyright (C) 2001 Jason Katz-Brown <jason@katzbrown.com>
|
|
(C) 2005 Paul Temple <paul.temple@gmx.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.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
USA
|
|
**/
|
|
|
|
#include <kaction.h>
|
|
#include <kapplication.h>
|
|
#include <kdebug.h>
|
|
#include <kfiledialog.h>
|
|
#include <klistview.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kpushbutton.h>
|
|
#include <kstatusbar.h>
|
|
#include <kstringhandler.h>
|
|
#include <tqbuttongroup.h>
|
|
#include <tqheader.h>
|
|
#include <tqlayout.h>
|
|
#include <tqtabwidget.h>
|
|
#include <tqtimer.h>
|
|
#include <tqtextcodec.h>
|
|
|
|
#include <stdlib.h> // RAND_MAX
|
|
#include <cassert>
|
|
#include <set>
|
|
|
|
#include "kitenconfig.h"
|
|
#include "dict.h"
|
|
#include "kloader.h"
|
|
#include "ksaver.h"
|
|
#include "learn.h"
|
|
|
|
LearnItem::LearnItem(TQListView *parent, TQString label1, TQString label2, TQString label3, TQString label4, TQString label5, TQString label6, TQString label7, TQString label8)
|
|
: TQListViewItem(parent, label1, label2, label3, label4, label5, label6, label7, label8)
|
|
{
|
|
}
|
|
|
|
int LearnItem::compare(TQListViewItem *item, int col, bool ascending) const
|
|
{
|
|
// "Returns < 0 if this item is less than i [item] , 0 if they
|
|
// are equal and > 0 if this item is greater than i [item]."
|
|
return key(col, ascending).toInt() - item->key(col, ascending).toInt();
|
|
}
|
|
|
|
const int Learn::numberOfAnswers = 5;
|
|
|
|
Learn::Learn(Dict::Index *parentDict, TQWidget *parent, const char *name)
|
|
: KMainWindow(parent, name), initialized(false), isMod(false), prevItem(0), curItem(0)
|
|
{
|
|
index = parentDict;
|
|
|
|
TQWidget *dummy = new TQWidget(this);
|
|
setCentralWidget(dummy);
|
|
|
|
TQVBoxLayout *veryTop = new TQVBoxLayout(dummy, 0, KDialog::spacingHint());
|
|
Tabs = new TQTabWidget(dummy);
|
|
connect(Tabs, TQT_SIGNAL(currentChanged(TQWidget *)), TQT_SLOT(tabChanged(TQWidget *)));
|
|
veryTop->addWidget(Tabs);
|
|
|
|
listTop = new TQSplitter(Tabs);
|
|
listTop->setOrientation(Qt::Vertical);
|
|
quizTop = new TQWidget(Tabs);
|
|
Tabs->addTab(listTop, i18n("&List"));
|
|
Tabs->addTab(quizTop, i18n("&Quiz"));
|
|
|
|
View = new ResultView(true, listTop, "View");
|
|
View->setBasicMode(true);
|
|
connect(View, TQT_SIGNAL(linkClicked(const TQString &)), this, TQT_SIGNAL(linkClicked(const TQString &)));
|
|
|
|
List = new KListView(listTop);
|
|
|
|
List->addColumn(i18n("Kanji"));
|
|
List->addColumn(i18n("Meanings"));
|
|
List->addColumn(i18n("Readings"));
|
|
List->addColumn(i18n("Grade"));
|
|
List->addColumn(i18n("Your Score"));
|
|
|
|
List->setAllColumnsShowFocus(true);
|
|
List->setColumnWidthMode(0, TQListView::Maximum);
|
|
List->setColumnWidthMode(1, TQListView::Maximum);
|
|
List->setColumnWidthMode(2, TQListView::Maximum);
|
|
List->setColumnWidthMode(3, TQListView::Maximum);
|
|
List->setMultiSelection(true);
|
|
List->setDragEnabled(true);
|
|
List->setSorting(4);
|
|
List->setSelectionModeExt(KListView::Extended);
|
|
|
|
connect(List, TQT_SIGNAL(executed(TQListViewItem *)), TQT_SLOT(showKanji(TQListViewItem *)));
|
|
connect(List, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(itemSelectionChanged()));
|
|
|
|
TQStringList grades(i18n("Grade 1"));
|
|
grades.append(i18n("Grade 2"));
|
|
grades.append(i18n("Grade 3"));
|
|
grades.append(i18n("Grade 4"));
|
|
grades.append(i18n("Grade 5"));
|
|
grades.append(i18n("Grade 6"));
|
|
grades.append(i18n("Others in Jouyou"));
|
|
grades.append(i18n("Jinmeiyou"));
|
|
|
|
/*KAction *closeAction = */(void) KStdAction::close(TQT_TQOBJECT(this), TQT_SLOT(close()), actionCollection());
|
|
printAct = KStdAction::print(TQT_TQOBJECT(this), TQT_SLOT(print()), actionCollection());
|
|
forwardAct = KStdAction::forward(TQT_TQOBJECT(this), TQT_SLOT(next()), actionCollection());
|
|
forwardAct->plug(toolBar());
|
|
backAct = KStdAction::back(TQT_TQOBJECT(this), TQT_SLOT(prev()), actionCollection());
|
|
backAct->plug(toolBar());
|
|
cheatAct = new KAction(i18n("&Cheat"), CTRL + Key_C, TQT_TQOBJECT(this), TQT_SLOT(cheat()), actionCollection(), "cheat");
|
|
randomAct = new KAction(i18n("&Random"), "goto", CTRL + Key_R, TQT_TQOBJECT(this), TQT_SLOT(random()), actionCollection(), "random");
|
|
gradeAct = new KListAction(i18n("Grade"), 0, 0, 0, actionCollection(), "grade");
|
|
gradeAct->setItems(grades);
|
|
connect(gradeAct, TQT_SIGNAL(activated(const TQString&)), TQT_SLOT(updateGrade()));
|
|
removeAct = new KAction(i18n("&Delete"), "edit_remove", CTRL + Key_X, TQT_TQOBJECT(this), TQT_SLOT(del()), actionCollection(), "del");
|
|
addAct = new KAction(i18n("&Add"), "edit_add", CTRL + Key_A, TQT_TQOBJECT(this), TQT_SLOT(add()), actionCollection(), "add");
|
|
addAllAct = new KAction(i18n("Add A&ll"), 0, TQT_TQOBJECT(this), TQT_SLOT(addAll()), actionCollection(), "addall");
|
|
newAct = KStdAction::openNew(TQT_TQOBJECT(this), TQT_SLOT(openNew()), actionCollection());
|
|
openAct = KStdAction::open(TQT_TQOBJECT(this), TQT_SLOT(open()), actionCollection());
|
|
saveAct = KStdAction::save(TQT_TQOBJECT(this), TQT_SLOT(save()), actionCollection());
|
|
saveAsAct = KStdAction::saveAs(TQT_TQOBJECT(this), TQT_SLOT(saveAs()), actionCollection());
|
|
(void) KStdAction::preferences(TQT_TQOBJECT(this), TQT_SIGNAL(configureLearn()), actionCollection());
|
|
|
|
removeAct->setEnabled(false);
|
|
|
|
TQVBoxLayout *quizLayout = new TQVBoxLayout(quizTop, KDialog::marginHint(), KDialog::spacingHint());
|
|
|
|
quizLayout->addStretch();
|
|
TQHBoxLayout *hlayout = new TQHBoxLayout(quizLayout);
|
|
qKanji = new TQPushButton(quizTop);
|
|
connect(qKanji, TQT_SIGNAL(clicked()), this, TQT_SLOT(qKanjiClicked()));
|
|
hlayout->addStretch();
|
|
hlayout->addWidget(qKanji);
|
|
hlayout->addStretch();
|
|
quizLayout->addStretch();
|
|
|
|
answers = new TQButtonGroup(1,Qt::Horizontal, quizTop);
|
|
for (int i = 0; i < numberOfAnswers; ++i)
|
|
answers->insert(new KPushButton(answers), i);
|
|
quizLayout->addWidget(answers);
|
|
quizLayout->addStretch();
|
|
connect(answers, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(answerClicked(int)));
|
|
|
|
createGUI("learnui.rc");
|
|
//closeAction->plug(toolBar());
|
|
|
|
resize(600, 400);
|
|
applyMainWindowSettings(Config::self()->config(), "LearnWindow");
|
|
|
|
statusBar()->message(i18n("Put on your thinking cap!"));
|
|
|
|
nogood = false;
|
|
|
|
// this is so learn doesn't take so long to show itself
|
|
TQTimer::singleShot(200, this, TQT_SLOT(finishCtor()));
|
|
}
|
|
|
|
void Learn::finishCtor()
|
|
{
|
|
Config* config = Config::self();
|
|
|
|
setCurrentGrade(config->grade());
|
|
|
|
/*
|
|
* this must be done now, because
|
|
* to start a quiz, we need a working randomMeaning()
|
|
* and that needs a loaded grade!
|
|
*/
|
|
updateGrade();
|
|
updateQuizConfiguration(); // first
|
|
|
|
TQString entry = config->lastFile();
|
|
//kdDebug() << "lastFile: " << entry << endl;
|
|
if (!entry.isEmpty())
|
|
{
|
|
filename = entry;
|
|
read(filename);
|
|
}
|
|
else
|
|
{
|
|
openNew();
|
|
}
|
|
|
|
initialized = true;
|
|
}
|
|
|
|
Learn::~Learn()
|
|
{
|
|
emit destroyed(this);
|
|
}
|
|
|
|
bool Learn::warnClose()
|
|
{
|
|
if (isMod)
|
|
{
|
|
int result = KMessageBox::warningYesNoCancel(this, i18n("There are unsaved changes to learning list. Save them?"), i18n("Unsaved Changes"), KStdGuiItem::save(), KStdGuiItem::discard(), "DiscardAsk", true);
|
|
switch (result)
|
|
{
|
|
case KMessageBox::Yes:
|
|
saveAct->activate();
|
|
// fallthrough
|
|
case KMessageBox::No:
|
|
return true;
|
|
case KMessageBox::Cancel:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Learn::closeWindow()
|
|
{
|
|
if (!warnClose())
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
close();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Learn::queryClose()
|
|
{
|
|
if (!warnClose())
|
|
return false; // cancel
|
|
|
|
saveScores(); // also sync()s;
|
|
|
|
saveMainWindowSettings(Config::self()->config(), "LearnWindow");
|
|
return true;
|
|
}
|
|
|
|
void Learn::random()
|
|
{
|
|
int rand = static_cast<int>(static_cast<float>(list.count()) / (static_cast<float>(RAND_MAX) / kapp->random()));
|
|
|
|
current = list.at(rand - 1);
|
|
update();
|
|
}
|
|
|
|
void Learn::next()
|
|
{
|
|
++current;
|
|
if (current == list.end())
|
|
current = list.begin();
|
|
update();
|
|
}
|
|
|
|
void Learn::prev()
|
|
{
|
|
if (Tabs->currentPageIndex() == 1)
|
|
{
|
|
if (!prevItem)
|
|
return;
|
|
curItem = prevItem;
|
|
|
|
statusBar()->clear();
|
|
qupdate();
|
|
nogood = true;
|
|
backAct->setEnabled(false);
|
|
return;
|
|
}
|
|
|
|
if (current == list.begin())
|
|
current = list.end();
|
|
--current;
|
|
update();
|
|
}
|
|
|
|
void Learn::update()
|
|
{
|
|
View->clear();
|
|
Dict::Entry curKanji = *current;
|
|
|
|
if (!curKanji.kanji())
|
|
{
|
|
statusBar()->message(i18n("Grade not loaded")); // oops
|
|
return;
|
|
}
|
|
View->addKanjiResult(curKanji);
|
|
|
|
// now show some compounds in which this kanji appears
|
|
|
|
TQString kanji = curKanji.kanji();
|
|
|
|
Dict::SearchResult compounds = index->search(TQRegExp(kanji), kanji, true);
|
|
View->addHeader(i18n("%1 in compounds").arg(kanji));
|
|
|
|
for (TQValueListIterator<Dict::Entry> it = compounds.list.begin(); it != compounds.list.end(); ++it)
|
|
{
|
|
kapp->processEvents();
|
|
View->addResult(*it, true);
|
|
}
|
|
|
|
View->flush();
|
|
}
|
|
|
|
void Learn::updateGrade()
|
|
{
|
|
int grade = getCurrentGrade();
|
|
|
|
TQString regexp("G%1 ");
|
|
regexp = regexp.arg(grade);
|
|
|
|
Dict::SearchResult result = index->searchKanji(TQRegExp(regexp), regexp, false);
|
|
list = result.list;
|
|
|
|
statusBar()->message(i18n("%1 entries in grade %2").arg(list.count()).arg(grade));
|
|
|
|
list.remove(list.begin());
|
|
current = list.begin();
|
|
update();
|
|
|
|
Config::self()->setGrade(grade);
|
|
}
|
|
|
|
void Learn::read(const KURL &url)
|
|
{
|
|
List->clear();
|
|
|
|
KLoader loader(url);
|
|
if (!loader.open())
|
|
{
|
|
KMessageBox::error(this, loader.error(), i18n("Error"));
|
|
return;
|
|
}
|
|
|
|
TQTextCodec &codec = *TQTextCodec::codecForName("eucJP");
|
|
TQTextStream &stream = loader.textStream();
|
|
stream.setCodec(&codec);
|
|
|
|
while (!stream.atEnd())
|
|
{
|
|
TQChar kanji;
|
|
stream >> kanji;
|
|
// ignore whitespace
|
|
if (!kanji.isSpace())
|
|
{
|
|
TQRegExp regexp ( TQString("^%1\\W").arg(kanji) );
|
|
Dict::SearchResult res = index->searchKanji(regexp, kanji, false);
|
|
Dict::Entry first = Dict::firstEntry(res);
|
|
if (first.extendedKanjiInfo())
|
|
add(first, true);
|
|
}
|
|
}
|
|
|
|
setClean();
|
|
}
|
|
|
|
void Learn::open()
|
|
{
|
|
if (!warnClose())
|
|
return;
|
|
|
|
KURL prevname = filename;
|
|
filename = KFileDialog::getOpenURL(TQString(), "*.kiten");
|
|
if (filename.isEmpty())
|
|
{
|
|
filename = prevname;
|
|
return;
|
|
}
|
|
|
|
read(filename);
|
|
|
|
//kdDebug() << "saving lastFile\n";
|
|
Config* config = Config::self();
|
|
config->setLastFile(filename.url());
|
|
|
|
// redo quiz, because we deleted the current quiz item
|
|
curItem = List->firstChild();
|
|
backAct->setEnabled(false);
|
|
prevItem = curItem;
|
|
qnew();
|
|
|
|
numChanged();
|
|
}
|
|
|
|
void Learn::openNew()
|
|
{
|
|
if (!warnClose())
|
|
return;
|
|
|
|
filename = "";
|
|
setCaption("");
|
|
|
|
List->clear();
|
|
setClean();
|
|
|
|
numChanged();
|
|
}
|
|
|
|
void Learn::saveAs()
|
|
{
|
|
KURL prevname = filename;
|
|
filename = KFileDialog::getSaveURL(TQString(), "*.kiten");
|
|
if (filename.isEmpty())
|
|
{
|
|
filename = prevname;
|
|
return;
|
|
}
|
|
save();
|
|
}
|
|
|
|
void Learn::save()
|
|
{
|
|
if (filename.isEmpty())
|
|
saveAs();
|
|
if (filename.isEmpty())
|
|
return;
|
|
|
|
write(filename);
|
|
|
|
Config* config = Config::self();
|
|
config->setLastFile(filename.url());
|
|
}
|
|
|
|
void Learn::write(const KURL &url)
|
|
{
|
|
KSaver saver(url);
|
|
|
|
if (!saver.open())
|
|
{
|
|
KMessageBox::error(this, saver.error(), i18n("Error"));
|
|
return;
|
|
}
|
|
|
|
TQTextCodec &codec = *TQTextCodec::codecForName("eucJP");
|
|
TQTextStream &stream = saver.textStream();
|
|
stream.setCodec(&codec);
|
|
|
|
for (TQListViewItemIterator it(List); it.current(); ++it)
|
|
stream << it.current()->text(0).at(0);
|
|
|
|
if (!saver.close())
|
|
{
|
|
KMessageBox::error(this, saver.error(), i18n("Error"));
|
|
return;
|
|
}
|
|
|
|
saveScores();
|
|
|
|
setClean();
|
|
|
|
statusBar()->message(i18n("%1 written").arg(url.prettyURL()));
|
|
}
|
|
|
|
void Learn::saveScores()
|
|
{
|
|
TDEConfig &config = *Config::self()->config();
|
|
config.setGroup("Learn Scores");
|
|
for (TQListViewItemIterator it(List); it.current(); ++it)
|
|
config.writeEntry(it.current()->text(0), it.current()->text(4).toInt());
|
|
config.sync();
|
|
Config::self()->writeConfig();
|
|
}
|
|
|
|
void Learn::add(Dict::Entry toAdd, bool noEmit)
|
|
{
|
|
// Remove peripheral readings: This is a study mode, not a reference mode
|
|
TQRegExp inNames (",\\s*[A-Za-z ]+:.*");
|
|
TQString readings = Dict::prettyKanjiReading(toAdd.readings()).replace(inNames, "");
|
|
TQString meanings = shortenString(Dict::prettyMeaning(toAdd.meanings()).replace(inNames, ""));
|
|
TQString kanji = toAdd.kanji();
|
|
|
|
// here's a dirty rotten cheat (well, not really)
|
|
// noEmit always means it's not added by the user, so this check isn't needed
|
|
if (!noEmit)
|
|
{
|
|
for (TQListViewItemIterator it(List); it.current(); ++it)
|
|
{
|
|
if (it.current()->text(0) == kanji)
|
|
{
|
|
statusBar()->message(i18n("%1 already on your list").arg(kanji));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
statusBar()->message(i18n("%1 added to your list").arg(kanji));
|
|
|
|
TDEConfig &config = *Config::self()->config();
|
|
int score = 0;
|
|
config.setGroup("Learn Scores");
|
|
score = config.readNumEntry(kanji, score);
|
|
|
|
unsigned int grade = toAdd.grade();
|
|
addItem(new LearnItem(List, kanji, meanings, readings, TQString::number(grade), TQString::number(score)), noEmit);
|
|
|
|
numChanged();
|
|
}
|
|
|
|
void Learn::add()
|
|
{
|
|
add(*current);
|
|
setDirty();
|
|
}
|
|
|
|
void Learn::addAll()
|
|
{
|
|
int grade = getCurrentGrade();
|
|
|
|
TQString regexp("G%1 ");
|
|
regexp = regexp.arg(grade);
|
|
|
|
Dict::SearchResult result = index->searchKanji(TQRegExp(regexp), regexp, false);
|
|
for (TQValueListIterator<Dict::Entry> i = result.list.begin(); i != result.list.end(); ++i)
|
|
{
|
|
// don't add headers
|
|
if ((*i).dictName() == "__NOTSET" && (*i).header() == "__NOTSET")
|
|
add(*i);
|
|
}
|
|
}
|
|
|
|
void Learn::addItem(TQListViewItem *item, bool noEmit)
|
|
{
|
|
// 2 is the magic jump
|
|
if (List->childCount() == 2)
|
|
{
|
|
curItem = item;
|
|
prevItem = curItem;
|
|
qnew(); // init first quiz
|
|
//kdDebug() << "initting first quiz in addItem\n";
|
|
}
|
|
|
|
if (!noEmit)
|
|
{
|
|
List->ensureItemVisible(item);
|
|
|
|
setDirty();
|
|
}
|
|
}
|
|
|
|
void Learn::showKanji(TQListViewItem *item)
|
|
{
|
|
assert(item);
|
|
|
|
TQString kanji(item->text(0));
|
|
int grade = item->text(3).toUInt();
|
|
|
|
if (getCurrentGrade() != grade)
|
|
{
|
|
setCurrentGrade(grade);
|
|
updateGrade();
|
|
}
|
|
|
|
// Why does this fail to find the kanji sometimes?
|
|
for (current = list.begin(); current != list.end() && (*current).kanji() != kanji; ++current);
|
|
|
|
update();
|
|
}
|
|
|
|
void Learn::del()
|
|
{
|
|
// quiz page
|
|
if (Tabs->currentPageIndex() == 1)
|
|
{
|
|
delete curItem;
|
|
curItem = prevItem; // needs to be something
|
|
qnew();
|
|
}
|
|
else // setup page
|
|
{
|
|
TQPtrList<TQListViewItem> selected = List->selectedItems();
|
|
assert(selected.count());
|
|
|
|
bool makenewq = false; // must make new quiz if we
|
|
// delete the current item
|
|
for (TQPtrListIterator<TQListViewItem> i(selected); *i; ++i)
|
|
{
|
|
if (curItem == i)
|
|
makenewq = true;
|
|
delete *i;
|
|
}
|
|
|
|
curItem = List->firstChild();
|
|
prevItem = curItem;
|
|
backAct->setEnabled(false);
|
|
|
|
if (makenewq)
|
|
{
|
|
qnew();
|
|
}
|
|
|
|
setDirty();
|
|
}
|
|
|
|
itemSelectionChanged();
|
|
numChanged();
|
|
}
|
|
|
|
// too easy...
|
|
void Learn::print()
|
|
{
|
|
View->clear();
|
|
View->addHeader(TQString("<h1>%1</h1>").arg(i18n("Learning List")), 1);
|
|
|
|
TQListViewItemIterator it(List);
|
|
for (; it.current(); ++it)
|
|
{
|
|
TQString kanji = it.current()->text(0);
|
|
Dict::SearchResult result = index->searchKanji(TQRegExp(kanji), kanji, false);
|
|
for (TQValueListIterator<Dict::Entry> i = result.list.begin(); i != result.list.end(); ++i)
|
|
{
|
|
if ((*i).dictName() == "__NOTSET" && (*i).header() == "__NOTSET")
|
|
{
|
|
View->addKanjiResult(*i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
View->print();
|
|
}
|
|
|
|
void Learn::answerClicked(int i)
|
|
{
|
|
if (!curItem)
|
|
return;
|
|
|
|
int newscore = 0;
|
|
// TDEConfig &config = *Config::self()->config();
|
|
// config.setGroup("Learn");
|
|
bool donew = false;
|
|
|
|
if (seikai == i)
|
|
{
|
|
statusBar()->message(i18n("Good!"));
|
|
|
|
if (!nogood) // add two to their score
|
|
newscore = curItem->text(4).toInt() + 2;
|
|
else
|
|
{
|
|
qnew();
|
|
return;
|
|
}
|
|
|
|
donew = true;
|
|
}
|
|
else
|
|
{
|
|
statusBar()->message(i18n("Wrong"));
|
|
// take one off score
|
|
newscore = curItem->text(4).toInt() - 1;
|
|
|
|
if (!nogood)
|
|
nogood = true;
|
|
else
|
|
return;
|
|
}
|
|
|
|
//config.writeEntry(curItem->text(0) + "_4", newscore);
|
|
|
|
TQListViewItem *newItem = new LearnItem(List, curItem->text(0), curItem->text(1), curItem->text(2), curItem->text(3), TQString::number(newscore));
|
|
|
|
// readd, so it sorts
|
|
// 20 November 2004: why?? why not List->sort() ??
|
|
// haha I used to be naive
|
|
delete curItem;
|
|
curItem = newItem;
|
|
|
|
if (donew)
|
|
qnew();
|
|
}
|
|
|
|
TQString Learn::randomMeaning(TQStringList &oldMeanings)
|
|
{
|
|
TQString meaning;
|
|
|
|
do
|
|
{
|
|
float rand = kapp->random();
|
|
if ((rand > (RAND_MAX / 2)) || (List->childCount() < numberOfAnswers))
|
|
{
|
|
// get a meaning from dict
|
|
//kdDebug() << "from our dict\n";
|
|
rand = kapp->random();
|
|
float rand2 = RAND_MAX / rand;
|
|
rand = ((float)list.count() - 1) / rand2;
|
|
//rand -= 1;
|
|
//kdDebug() << "rand: " << rand << endl;
|
|
//kdDebug() << "list.count(): " << list.count() << endl;
|
|
|
|
switch (guessOn)
|
|
{
|
|
case 1:
|
|
meaning = shortenString(Dict::prettyMeaning((*list.at(static_cast<unsigned int>(rand))).meanings()));
|
|
break;
|
|
case 2:
|
|
meaning = Dict::prettyKanjiReading((*list.at(static_cast<unsigned int>(rand))).readings());
|
|
break;
|
|
case 0:
|
|
meaning = (*list.at(static_cast<unsigned int>(rand))).kanji();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// get a meaning from our list
|
|
//kdDebug() << "from our list\n";
|
|
rand = kapp->random();
|
|
float rand2 = RAND_MAX / rand;
|
|
rand = List->childCount() / rand2;
|
|
|
|
int max = (int) rand;
|
|
|
|
TQListViewItemIterator it(List);
|
|
it += max;
|
|
|
|
meaning = it.current()->text(guessOn);
|
|
}
|
|
|
|
//kdDebug() << "meaning: " << meaning << endl;
|
|
for (TQStringList::Iterator it = oldMeanings.begin(); it != oldMeanings.end(); ++it)
|
|
{
|
|
//kdDebug() << "oldMeaning: " << *it << endl;
|
|
}
|
|
//kdDebug() << "curMeaning: " << curItem->text(guessOn) << endl;
|
|
}
|
|
while (oldMeanings.contains(meaning) || meaning == curItem->text(guessOn));
|
|
|
|
oldMeanings.append(meaning);
|
|
meaning = shortenString(meaning);
|
|
|
|
return meaning;
|
|
}
|
|
|
|
void Learn::qupdate()
|
|
{
|
|
if (!curItem)
|
|
return;
|
|
|
|
qKanji->setText(curItem->text(quizOn));
|
|
TQFont newFont = font();
|
|
if (quizOn == 0)
|
|
newFont.setPixelSize(24);
|
|
qKanji->setFont(newFont);
|
|
|
|
float rand = kapp->random();
|
|
float rand2 = RAND_MAX / rand;
|
|
seikai = static_cast<int>(numberOfAnswers / rand2);
|
|
|
|
TQStringList oldMeanings;
|
|
for (int i = 0; i < numberOfAnswers; ++i)
|
|
answers->find(i)->setText(randomMeaning(oldMeanings));
|
|
|
|
answers->find(seikai)->setText(curItem->text(guessOn));
|
|
}
|
|
|
|
struct Learn::scoreCompare
|
|
{
|
|
bool operator()(const TQListViewItem* v1, const TQListViewItem* v2)
|
|
{
|
|
return v1->text(4).toInt() < v2->text(4).toInt();
|
|
}
|
|
};
|
|
|
|
void Learn::qnew() // new quiz kanji
|
|
{
|
|
//kdDebug() << "qnew\n";
|
|
nogood = false;
|
|
|
|
statusBar()->clear();
|
|
statusBar()->message(TQString("%1 %2 %3").arg(curItem->text(0)).arg(curItem->text(1)).arg(curItem->text(2)));
|
|
|
|
backAct->setEnabled(true);
|
|
|
|
unsigned int count = List->childCount();
|
|
|
|
if (count < 2)
|
|
return;
|
|
|
|
// the following lines calculate which kanji will be used next:
|
|
// use f(2) every third time, f(1) otherwise
|
|
// where f(1) = numberOfItems * rand[0..1]
|
|
// and f(2) = numberOfItems * rand[0..1] * rand[0..1]
|
|
// rand[0..1] = kapp->random() / RAND_MAX
|
|
float max = static_cast<float>(count) / (static_cast<float>(RAND_MAX) / kapp->random());
|
|
if (kapp->random() < (static_cast<float>(RAND_MAX) / 3.25))
|
|
max /= (static_cast<float>(RAND_MAX) / (kapp->random() + 1));
|
|
|
|
max = static_cast<int>(max);
|
|
|
|
if (max > count)
|
|
max = count;
|
|
|
|
std::multiset<const TQListViewItem*, scoreCompare> scores;
|
|
TQListViewItemIterator sIt(List);
|
|
|
|
for (; sIt.current(); ++sIt)
|
|
scores.insert(sIt.current());
|
|
|
|
std::multiset<const TQListViewItem*, scoreCompare>::iterator it = scores.begin();
|
|
std::multiset<const TQListViewItem*, scoreCompare>::iterator tmp = scores.begin();
|
|
|
|
int i;
|
|
for (i = 2; i <= max; ++it)
|
|
{i++; ++tmp;}
|
|
|
|
if (curItem->text(0) == (*it)->text(0)) // same, don't use
|
|
{
|
|
++it;
|
|
if (it == scores.end())
|
|
{
|
|
tmp--;
|
|
it = tmp;
|
|
}
|
|
}
|
|
|
|
if (it == scores.end())
|
|
{
|
|
return;
|
|
}
|
|
|
|
prevItem = curItem;
|
|
curItem = const_cast<TQListViewItem*>(*it);
|
|
|
|
qKanji->setFocus();
|
|
qupdate();
|
|
}
|
|
|
|
void Learn::cheat()
|
|
{
|
|
answers->find(seikai)->setFocus();
|
|
statusBar()->message(i18n("Better luck next time"));
|
|
nogood = true;
|
|
}
|
|
|
|
TQString Learn::shortenString(const TQString &thestring)
|
|
{
|
|
return KStringHandler::rsqueeze(thestring, 60).stripWhiteSpace();
|
|
}
|
|
|
|
void Learn::tabChanged(TQWidget *widget)
|
|
{
|
|
bool isQuiz = (widget == quizTop);
|
|
|
|
if (isQuiz)
|
|
backAct->setEnabled(prevItem != 0);
|
|
else
|
|
backAct->setEnabled(true);
|
|
|
|
forwardAct->setEnabled(!isQuiz);
|
|
gradeAct->setEnabled(!isQuiz);
|
|
saveAct->setEnabled(!isQuiz);
|
|
addAct->setEnabled(!isQuiz);
|
|
addAllAct->setEnabled(!isQuiz);
|
|
randomAct->setEnabled(!isQuiz);
|
|
openAct->setEnabled(!isQuiz);
|
|
newAct->setEnabled(!isQuiz);
|
|
saveAsAct->setEnabled(!isQuiz);
|
|
|
|
cheatAct->setEnabled(isQuiz);
|
|
|
|
// also handled below for !isQuiz case
|
|
removeAct->setEnabled(isQuiz);
|
|
|
|
if (isQuiz)
|
|
{
|
|
qKanji->setFocus();
|
|
|
|
}
|
|
else
|
|
{
|
|
// handle removeAct;
|
|
itemSelectionChanged();
|
|
}
|
|
|
|
statusBar()->clear();
|
|
}
|
|
|
|
void Learn::updateQuiz()
|
|
{
|
|
if (List->childCount() < 3)
|
|
Tabs->setTabEnabled(quizTop, false);
|
|
else
|
|
Tabs->setTabEnabled(quizTop, true);
|
|
}
|
|
|
|
void Learn::itemSelectionChanged()
|
|
{
|
|
removeAct->setEnabled(List->selectedItems().count() > 0);
|
|
}
|
|
|
|
int Learn::getCurrentGrade(void)
|
|
{
|
|
int grade = gradeAct->currentItem() + 1;
|
|
if (grade > 6) ++grade;
|
|
return grade;
|
|
}
|
|
|
|
void Learn::setCurrentGrade(int grade)
|
|
{
|
|
if (grade > 6) --grade;
|
|
gradeAct->setCurrentItem(grade - 1);
|
|
}
|
|
|
|
void Learn::updateQuizConfiguration()
|
|
{
|
|
Config* config = Config::self();
|
|
|
|
quizOn = config->quizOn();
|
|
guessOn = config->guessOn();
|
|
|
|
answers->setTitle(List->columnText(guessOn));
|
|
|
|
View->updateFont();
|
|
|
|
if (List->childCount() >= 2 && initialized)
|
|
qnew();
|
|
}
|
|
|
|
void Learn::setDirty()
|
|
{
|
|
isMod = true;
|
|
setCaption(filename.prettyURL(), true);
|
|
}
|
|
|
|
void Learn::setClean()
|
|
{
|
|
isMod = false;
|
|
if (!filename.prettyURL().isEmpty())
|
|
setCaption(filename.prettyURL(), false);
|
|
}
|
|
|
|
void Learn::qKanjiClicked()
|
|
{
|
|
if (!curItem)
|
|
return;
|
|
|
|
showKanji(curItem);
|
|
nogood = true;
|
|
}
|
|
|
|
void Learn::numChanged()
|
|
{
|
|
Tabs->setTabEnabled(quizTop, List->childCount() >= 2);
|
|
//quizTop->setEnabled(List->childCount() >= 2);
|
|
}
|
|
|
|
#include "learn.moc"
|