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.
436 lines
10 KiB
436 lines
10 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 <kapplication.h>
|
|
#include <kconfig.h>
|
|
#include <kdebug.h>
|
|
#include <kdialog.h>
|
|
#include <klistbox.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kpushbutton.h>
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <tqbuttongroup.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqfile.h>
|
|
#include <tqlabel.h>
|
|
#include <tqlayout.h>
|
|
#include <tqspinbox.h>
|
|
#include <tqtextcodec.h>
|
|
#include <tqtooltip.h>
|
|
|
|
#include "kitenconfig.h"
|
|
#include "rad.h"
|
|
|
|
Rad::Rad() : TQObject()
|
|
{
|
|
loaded = false;
|
|
}
|
|
|
|
void Rad::load()
|
|
{
|
|
if (loaded)
|
|
return;
|
|
|
|
KStandardDirs *dirs = KGlobal::dirs();
|
|
TQString radkfile = dirs->findResource("data", "kiten/radkfile");
|
|
if (radkfile.isNull())
|
|
{
|
|
KMessageBox::error(0, i18n("Kanji radical information file not installed, so radical searching cannot be used."));
|
|
return;
|
|
}
|
|
|
|
TQFile f(radkfile);
|
|
|
|
if (!f.open(IO_ReadOnly))
|
|
{
|
|
KMessageBox::error(0, i18n("Kanji radical information could not be loaded, so radical searching cannot be used."));
|
|
}
|
|
|
|
TQTextStream t(&f);
|
|
t.setCodec(TQTextCodec::codecForName("eucJP"));
|
|
Radical cur;
|
|
while (!t.eof())
|
|
{
|
|
TQString s = t.readLine();
|
|
|
|
TQChar first = s.at(0);
|
|
if (first == '#') // comment!
|
|
{
|
|
// nothing
|
|
}
|
|
else if (first == '$') // header
|
|
{
|
|
// save previous one
|
|
if( !cur.kanji().isNull() )
|
|
list.append(cur);
|
|
|
|
//first entry is trim(last 4 chars).. <rad><space><strokes>
|
|
unsigned int strokes = s.right(2).toUInt();
|
|
TQString radical = TQString(s.at(2));
|
|
cur = Radical(radical, strokes);
|
|
}
|
|
else // continuation
|
|
{
|
|
cur.addKanji(s);
|
|
}
|
|
}
|
|
|
|
// we gotta append the last one!!
|
|
// this nagged jasonkb for a bit wondering why fue wasn't showing up ;)
|
|
list.append(cur);
|
|
|
|
f.close();
|
|
|
|
loaded = true;
|
|
}
|
|
|
|
TQStringList Rad::radByStrokes(unsigned int strokes)
|
|
{
|
|
load();
|
|
|
|
TQStringList ret;
|
|
bool hadOne = false;
|
|
TQValueListIterator<Radical> it = list.begin();
|
|
|
|
do
|
|
{
|
|
if ((*it).strokes() == strokes)
|
|
{
|
|
ret.append((*it).radical());
|
|
hadOne = true;
|
|
}
|
|
else if(hadOne) // shortcut because it's a sorted list
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
while (++it != list.end());
|
|
|
|
return ret;
|
|
}
|
|
|
|
TQStringList Rad::kanjiByRad(const TQString &text)
|
|
{
|
|
//kdDebug() << "kanjiByRad, text is " << text << endl;
|
|
load();
|
|
TQStringList ret;
|
|
|
|
TQValueListIterator<Radical> it;
|
|
for (it = list.begin(); it != list.end() && (*it).radical() != text; ++it)
|
|
{
|
|
//kdDebug() << "kanjiByRad, looping, radical is " << (*it).radical() << endl;
|
|
}
|
|
|
|
TQString kanji = (*it).kanji();
|
|
for (unsigned i = 0; i < kanji.length(); ++i)
|
|
{
|
|
//kdDebug() << "kanjiByRad, i is " << i << endl;
|
|
ret.append(TQString(kanji.at(i)));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
TQStringList Rad::kanjiByRad(const TQStringList &list)
|
|
{
|
|
//kdDebug() << "kanjiByRad (list version)\n";
|
|
|
|
TQStringList ret;
|
|
TQValueList<TQStringList> lists;
|
|
|
|
for (TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
|
|
{
|
|
//kdDebug() << "loading radical " << *it << endl;
|
|
lists.append(kanjiByRad(*it));
|
|
}
|
|
|
|
TQStringList first = lists.first();
|
|
lists.pop_front();
|
|
|
|
for (TQStringList::Iterator kit = first.begin(); kit != first.end(); ++kit)
|
|
{
|
|
//kdDebug() << "kit is " << *kit << endl;
|
|
TQValueList<bool> outcomes;
|
|
for (TQValueList<TQStringList>::Iterator it = lists.begin(); it != lists.end(); ++it)
|
|
{
|
|
//kdDebug() << "looping through lists\n";
|
|
outcomes.append((*it).contains(*kit) > 0);
|
|
}
|
|
|
|
const bool containsBool = false;
|
|
if ((outcomes.contains(containsBool) < 1))
|
|
{
|
|
//kdDebug() << "appending " << *kit << endl;
|
|
ret.append(*kit);
|
|
}
|
|
else
|
|
{
|
|
//kdDebug() << "not appending " << *kit << endl;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Radical Rad::radByKanji(const TQString &text)
|
|
{
|
|
load();
|
|
TQString ret;
|
|
|
|
TQValueListIterator<Radical> it;
|
|
for (it = list.end(); it != list.begin() && (*it).kanji().find(text) == -1; --it);
|
|
|
|
return (*it);
|
|
}
|
|
|
|
unsigned int Rad::strokesByRad(const TQString &text)
|
|
{
|
|
load();
|
|
TQValueListIterator<Radical> it;
|
|
for(it = list.begin(); it != list.end() && (*it).radical() != text; ++it);
|
|
|
|
return (*it).strokes();
|
|
}
|
|
|
|
Rad::~Rad()
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////
|
|
|
|
RadWidget::RadWidget(Rad *_rad, TQWidget *parent, const char *name) : TQWidget(parent, name)
|
|
{
|
|
hotlistNum = 3;
|
|
|
|
rad = _rad;
|
|
TQHBoxLayout *htqlayout = new TQHBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
|
|
TQVBoxLayout *vtqlayout = new TQVBoxLayout(htqlayout, KDialog::spacingHint());
|
|
|
|
hotlistGroup = new TQButtonGroup(1,Qt::Horizontal, i18n("Hotlist"), this);
|
|
//hotlistGroup->setRadioButtonExclusive(true);
|
|
vtqlayout->addWidget(hotlistGroup);
|
|
|
|
Config* config = Config::self();
|
|
|
|
hotlist = config->hotlist();
|
|
|
|
while (hotlist.size() > hotlistNum)
|
|
hotlist.pop_front();
|
|
|
|
for (unsigned int i = 0; i < hotlistNum; ++i)
|
|
{
|
|
if (i >= hotlistNum)
|
|
break;
|
|
|
|
hotlistGroup->insert(new KPushButton(*hotlist.at(i), hotlistGroup), i);
|
|
}
|
|
connect(hotlistGroup, TQT_SIGNAL(clicked(int)), TQT_SLOT(hotlistClicked(int)));
|
|
|
|
TQVBoxLayout *tqlayout = new TQVBoxLayout(vtqlayout, KDialog::spacingHint());
|
|
|
|
totalStrokes = new TQCheckBox(i18n("Search by total strokes"), this);
|
|
connect(totalStrokes, TQT_SIGNAL(clicked()), this, TQT_SLOT(totalClicked()));
|
|
tqlayout->addWidget(totalStrokes);
|
|
|
|
TQHBoxLayout *strokesLayout = new TQHBoxLayout(tqlayout, KDialog::spacingHint());
|
|
totalSpin = new TQSpinBox(1, 30, 1, this);
|
|
strokesLayout->addWidget(totalSpin);
|
|
strokesLayout->addStretch();
|
|
totalErrLabel = new TQLabel(i18n("+/-"), this);
|
|
strokesLayout->addWidget(totalErrLabel);
|
|
totalErrSpin = new TQSpinBox(0, 15, 1, this);
|
|
strokesLayout->addWidget(totalErrSpin);
|
|
|
|
ok = new KPushButton(i18n("&Look Up"), this);
|
|
ok->setEnabled(false);
|
|
connect(ok, TQT_SIGNAL(clicked()), TQT_SLOT(apply()));
|
|
tqlayout->addWidget(ok);
|
|
cancel = new KPushButton( KStdGuiItem::cancel(), this );
|
|
|
|
connect(cancel, TQT_SIGNAL(clicked()), TQT_SLOT(close()));
|
|
tqlayout->addWidget(cancel);
|
|
|
|
TQVBoxLayout *middlevLayout = new TQVBoxLayout(htqlayout, KDialog::spacingHint());
|
|
|
|
strokesSpin = new TQSpinBox(1, 17, 1, this);
|
|
TQToolTip::add(strokesSpin, i18n("Show radicals having this number of strokes"));
|
|
middlevLayout->addWidget(strokesSpin);
|
|
|
|
List = new KListBox(this);
|
|
middlevLayout->addWidget(List);
|
|
connect(List, TQT_SIGNAL(executed(TQListBoxItem *)), this, TQT_SLOT(executed(TQListBoxItem *)));
|
|
connect(strokesSpin, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(updateList(int)));
|
|
|
|
TQVBoxLayout *rightvtqlayout = new TQVBoxLayout(htqlayout, KDialog::spacingHint());
|
|
selectedList = new KListBox(this);
|
|
rightvtqlayout->addWidget(selectedList);
|
|
connect(selectedList, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(selectionChanged()));
|
|
|
|
remove = new KPushButton(i18n("&Remove"), this);
|
|
rightvtqlayout->addWidget(remove);
|
|
connect(remove, TQT_SIGNAL(clicked()), this, TQT_SLOT(removeSelected()));
|
|
remove->setEnabled(false);
|
|
|
|
clear = new KPushButton(KStdGuiItem::clear(), this);
|
|
rightvtqlayout->addWidget(clear);
|
|
connect(clear, TQT_SIGNAL(clicked()), this, TQT_SLOT(clearSelected()));
|
|
clear->setEnabled(false);
|
|
|
|
setCaption(kapp->makeStdCaption(i18n("Radical Selector")));
|
|
|
|
strokesSpin->setValue(config->strokes());
|
|
strokesSpin->setFocus();
|
|
|
|
totalSpin->setValue(config->totalStrokes());
|
|
totalErrSpin->setValue(config->totalStrokesErrorMargin());
|
|
totalStrokes->setChecked(config->searchByTotal());
|
|
|
|
// make sure the right parts of the total stroke
|
|
// selection system are enabled
|
|
totalClicked();
|
|
|
|
// initially show the list of radicals to choose from
|
|
updateList(strokesSpin->value());
|
|
}
|
|
|
|
RadWidget::~RadWidget()
|
|
{
|
|
}
|
|
|
|
void RadWidget::hotlistClicked(int num)
|
|
{
|
|
addToSelected(*hotlist.at(num));
|
|
}
|
|
|
|
void RadWidget::executed(TQListBoxItem *item)
|
|
{
|
|
addToSelected(item->text());
|
|
}
|
|
|
|
void RadWidget::clearSelected()
|
|
{
|
|
selectedList->clear();
|
|
selected.clear();
|
|
numChanged();
|
|
}
|
|
|
|
void RadWidget::removeSelected()
|
|
{
|
|
int currentItem = selectedList->currentItem();
|
|
if (currentItem != -1)
|
|
{
|
|
selectedList->removeItem(currentItem);
|
|
selected.remove(selected.at(currentItem));
|
|
|
|
numChanged();
|
|
selectionChanged();
|
|
}
|
|
}
|
|
|
|
void RadWidget::numChanged()
|
|
{
|
|
ok->setEnabled(selectedList->count() > 0);
|
|
clear->setEnabled(selectedList->count() > 0);
|
|
}
|
|
|
|
void RadWidget::addRadical(const TQString &radical)
|
|
{
|
|
addToSelected(radical);
|
|
}
|
|
|
|
void RadWidget::addToSelected(const TQString &text)
|
|
{
|
|
if (!text.isNull() && !selected.contains(text))
|
|
{
|
|
selectedList->insertItem(text);
|
|
selected.append(text);
|
|
|
|
numChanged();
|
|
selectionChanged();
|
|
}
|
|
}
|
|
|
|
void RadWidget::selectionChanged()
|
|
{
|
|
//kdDebug() << "selectionChanged()" << endl;
|
|
remove->setEnabled(selectedList->currentItem() != -1);
|
|
}
|
|
|
|
void RadWidget::updateList(int strokes)
|
|
{
|
|
List->clear();
|
|
List->insertStringList(rad->radByStrokes(static_cast<unsigned int>(strokes)));
|
|
}
|
|
|
|
void RadWidget::apply()
|
|
{
|
|
|
|
if (selected.count() < 1)
|
|
return;
|
|
|
|
emit set(selected, totalStrokes->isChecked() ? totalSpin->value() : 0, totalErrSpin->value());
|
|
|
|
Config* config = Config::self();
|
|
config->setStrokes(strokesSpin->value());
|
|
config->setTotalStrokes(totalSpin->value());
|
|
config->setTotalStrokesErrorMargin(totalErrSpin->value());
|
|
config->setSearchByTotal(totalStrokes->isChecked());
|
|
|
|
for (TQStringList::Iterator it = selected.begin(); it != selected.end(); ++it)
|
|
{
|
|
if (hotlist.find(*it) == hotlist.end())
|
|
{
|
|
if (hotlist.size() >= hotlistNum)
|
|
hotlist.pop_front(); // stupid stl functions in TQt .. ;)
|
|
hotlist.append(*it);
|
|
|
|
config->setHotlist(hotlist);
|
|
}
|
|
}
|
|
config->writeConfig();
|
|
close();
|
|
}
|
|
|
|
void RadWidget::totalClicked()
|
|
{
|
|
bool enable = totalStrokes->isChecked();
|
|
totalSpin->setEnabled(enable);
|
|
totalErrSpin->setEnabled(enable);
|
|
totalErrLabel->setEnabled(enable);
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
|
|
Radical::Radical(TQString text, unsigned int strokes)
|
|
{
|
|
_Radical = text;
|
|
Strokes = strokes;
|
|
}
|
|
|
|
void Radical::addKanji(const TQString &text)
|
|
{
|
|
Kanji.append(text);
|
|
}
|
|
|
|
#include "rad.moc"
|