2 This file is part of Kiten, a KDE Japanese Reference Tool...
3 Copyright (C) 2001 Jason Katz-Brown <jason@katzbrown.com>
4 (C) 2005 Paul Temple <paul.temple@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 #include <kapplication.h>
28 #include <kmessagebox.h>
29 #include <kpushbutton.h>
30 #include <kstandarddirs.h>
32 #include <qbuttongroup.h>
33 #include <qcheckbox.h>
38 #include <qtextcodec.h>
41 #include "kitenconfig.h"
44 Rad::Rad() : QObject()
54 KStandardDirs
*dirs
= KGlobal::dirs();
55 QString radkfile
= dirs
->findResource("data", "kiten/radkfile");
56 if (radkfile
.isNull())
58 KMessageBox::error(0, i18n("Kanji radical information file not installed, so radical searching cannot be used."));
64 if (!f
.open(IO_ReadOnly
))
66 KMessageBox::error(0, i18n("Kanji radical information could not be loaded, so radical searching cannot be used."));
70 t
.setCodec(QTextCodec::codecForName("eucJP"));
74 QString s
= t
.readLine();
76 QChar first
= s
.at(0);
77 if (first
== '#') // comment!
81 else if (first
== '$') // header
84 if( !cur
.kanji().isNull() )
87 //first entry is trim(last 4 chars).. <rad><space><strokes>
88 unsigned int strokes
= s
.right(2).toUInt();
89 QString radical
= QString(s
.at(2));
90 cur
= Radical(radical
, strokes
);
98 // we gotta append the last one!!
99 // this nagged jasonkb for a bit wondering why fue wasn't showing up ;)
107 QStringList
Rad::radByStrokes(unsigned int strokes
)
113 QValueListIterator
<Radical
> it
= list
.begin();
117 if ((*it
).strokes() == strokes
)
119 ret
.append((*it
).radical());
122 else if(hadOne
) // shortcut because it's a sorted list
127 while (++it
!= list
.end());
132 QStringList
Rad::kanjiByRad(const QString
&text
)
134 //kdDebug() << "kanjiByRad, text is " << text << endl;
138 QValueListIterator
<Radical
> it
;
139 for (it
= list
.begin(); it
!= list
.end() && (*it
).radical() != text
; ++it
)
141 //kdDebug() << "kanjiByRad, looping, radical is " << (*it).radical() << endl;
144 QString kanji
= (*it
).kanji();
145 for (unsigned i
= 0; i
< kanji
.length(); ++i
)
147 //kdDebug() << "kanjiByRad, i is " << i << endl;
148 ret
.append(QString(kanji
.at(i
)));
154 QStringList
Rad::kanjiByRad(const QStringList
&list
)
156 //kdDebug() << "kanjiByRad (list version)\n";
159 QValueList
<QStringList
> lists
;
161 for (QStringList::ConstIterator it
= list
.begin(); it
!= list
.end(); ++it
)
163 //kdDebug() << "loading radical " << *it << endl;
164 lists
.append(kanjiByRad(*it
));
167 QStringList first
= lists
.first();
170 for (QStringList::Iterator kit
= first
.begin(); kit
!= first
.end(); ++kit
)
172 //kdDebug() << "kit is " << *kit << endl;
173 QValueList
<bool> outcomes
;
174 for (QValueList
<QStringList
>::Iterator it
= lists
.begin(); it
!= lists
.end(); ++it
)
176 //kdDebug() << "looping through lists\n";
177 outcomes
.append((*it
).contains(*kit
) > 0);
180 const bool containsBool
= false;
181 if ((outcomes
.contains(containsBool
) < 1))
183 //kdDebug() << "appending " << *kit << endl;
188 //kdDebug() << "not appending " << *kit << endl;
195 Radical
Rad::radByKanji(const QString
&text
)
200 QValueListIterator
<Radical
> it
;
201 for (it
= list
.end(); it
!= list
.begin() && (*it
).kanji().find(text
) == -1; --it
);
206 unsigned int Rad::strokesByRad(const QString
&text
)
209 QValueListIterator
<Radical
> it
;
210 for(it
= list
.begin(); it
!= list
.end() && (*it
).radical() != text
; ++it
);
212 return (*it
).strokes();
219 ///////////////////////////////////////////////
221 RadWidget::RadWidget(Rad
*_rad
, QWidget
*parent
, const char *name
) : QWidget(parent
, name
)
226 QHBoxLayout
*hlayout
= new QHBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint());
227 QVBoxLayout
*vlayout
= new QVBoxLayout(hlayout
, KDialog::spacingHint());
229 hotlistGroup
= new QButtonGroup(1, Horizontal
, i18n("Hotlist"), this);
230 //hotlistGroup->setRadioButtonExclusive(true);
231 vlayout
->addWidget(hotlistGroup
);
233 Config
* config
= Config::self();
235 hotlist
= config
->hotlist();
237 while (hotlist
.size() > hotlistNum
)
240 for (unsigned int i
= 0; i
< hotlistNum
; ++i
)
245 hotlistGroup
->insert(new KPushButton(*hotlist
.at(i
), hotlistGroup
), i
);
247 connect(hotlistGroup
, SIGNAL(clicked(int)), SLOT(hotlistClicked(int)));
249 QVBoxLayout
*layout
= new QVBoxLayout(vlayout
, KDialog::spacingHint());
251 totalStrokes
= new QCheckBox(i18n("Search by total strokes"), this);
252 connect(totalStrokes
, SIGNAL(clicked()), this, SLOT(totalClicked()));
253 layout
->addWidget(totalStrokes
);
255 QHBoxLayout
*strokesLayout
= new QHBoxLayout(layout
, KDialog::spacingHint());
256 totalSpin
= new QSpinBox(1, 30, 1, this);
257 strokesLayout
->addWidget(totalSpin
);
258 strokesLayout
->addStretch();
259 totalErrLabel
= new QLabel(i18n("+/-"), this);
260 strokesLayout
->addWidget(totalErrLabel
);
261 totalErrSpin
= new QSpinBox(0, 15, 1, this);
262 strokesLayout
->addWidget(totalErrSpin
);
264 ok
= new KPushButton(i18n("&Look Up"), this);
265 ok
->setEnabled(false);
266 connect(ok
, SIGNAL(clicked()), SLOT(apply()));
267 layout
->addWidget(ok
);
268 cancel
= new KPushButton( KStdGuiItem::cancel(), this );
270 connect(cancel
, SIGNAL(clicked()), SLOT(close()));
271 layout
->addWidget(cancel
);
273 QVBoxLayout
*middlevLayout
= new QVBoxLayout(hlayout
, KDialog::spacingHint());
275 strokesSpin
= new QSpinBox(1, 17, 1, this);
276 QToolTip::add(strokesSpin
, i18n("Show radicals having this number of strokes"));
277 middlevLayout
->addWidget(strokesSpin
);
279 List
= new KListBox(this);
280 middlevLayout
->addWidget(List
);
281 connect(List
, SIGNAL(executed(QListBoxItem
*)), this, SLOT(executed(QListBoxItem
*)));
282 connect(strokesSpin
, SIGNAL(valueChanged(int)), this, SLOT(updateList(int)));
284 QVBoxLayout
*rightvlayout
= new QVBoxLayout(hlayout
, KDialog::spacingHint());
285 selectedList
= new KListBox(this);
286 rightvlayout
->addWidget(selectedList
);
287 connect(selectedList
, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
289 remove
= new KPushButton(i18n("&Remove"), this);
290 rightvlayout
->addWidget(remove
);
291 connect(remove
, SIGNAL(clicked()), this, SLOT(removeSelected()));
292 remove
->setEnabled(false);
294 clear
= new KPushButton(KStdGuiItem::clear(), this);
295 rightvlayout
->addWidget(clear
);
296 connect(clear
, SIGNAL(clicked()), this, SLOT(clearSelected()));
297 clear
->setEnabled(false);
299 setCaption(kapp
->makeStdCaption(i18n("Radical Selector")));
301 strokesSpin
->setValue(config
->strokes());
302 strokesSpin
->setFocus();
304 totalSpin
->setValue(config
->totalStrokes());
305 totalErrSpin
->setValue(config
->totalStrokesErrorMargin());
306 totalStrokes
->setChecked(config
->searchByTotal());
308 // make sure the right parts of the total stroke
309 // selection system are enabled
312 // initially show the list of radicals to choose from
313 updateList(strokesSpin
->value());
316 RadWidget::~RadWidget()
320 void RadWidget::hotlistClicked(int num
)
322 addToSelected(*hotlist
.at(num
));
325 void RadWidget::executed(QListBoxItem
*item
)
327 addToSelected(item
->text());
330 void RadWidget::clearSelected()
332 selectedList
->clear();
337 void RadWidget::removeSelected()
339 int currentItem
= selectedList
->currentItem();
340 if (currentItem
!= -1)
342 selectedList
->removeItem(currentItem
);
343 selected
.remove(selected
.at(currentItem
));
350 void RadWidget::numChanged()
352 ok
->setEnabled(selectedList
->count() > 0);
353 clear
->setEnabled(selectedList
->count() > 0);
356 void RadWidget::addRadical(const QString
&radical
)
358 addToSelected(radical
);
361 void RadWidget::addToSelected(const QString
&text
)
363 if (!text
.isNull() && !selected
.contains(text
))
365 selectedList
->insertItem(text
);
366 selected
.append(text
);
373 void RadWidget::selectionChanged()
375 //kdDebug() << "selectionChanged()" << endl;
376 remove
->setEnabled(selectedList
->currentItem() != -1);
379 void RadWidget::updateList(int strokes
)
382 List
->insertStringList(rad
->radByStrokes(static_cast<unsigned int>(strokes
)));
385 void RadWidget::apply()
388 if (selected
.count() < 1)
391 emit
set(selected
, totalStrokes
->isChecked() ? totalSpin
->value() : 0, totalErrSpin
->value());
393 Config
* config
= Config::self();
394 config
->setStrokes(strokesSpin
->value());
395 config
->setTotalStrokes(totalSpin
->value());
396 config
->setTotalStrokesErrorMargin(totalErrSpin
->value());
397 config
->setSearchByTotal(totalStrokes
->isChecked());
399 for (QStringList::Iterator it
= selected
.begin(); it
!= selected
.end(); ++it
)
401 if (hotlist
.find(*it
) == hotlist
.end())
403 if (hotlist
.size() >= hotlistNum
)
404 hotlist
.pop_front(); // stupid stl functions in Qt .. ;)
407 config
->setHotlist(hotlist
);
410 config
->writeConfig();
414 void RadWidget::totalClicked()
416 bool enable
= totalStrokes
->isChecked();
417 totalSpin
->setEnabled(enable
);
418 totalErrSpin
->setEnabled(enable
);
419 totalErrLabel
->setEnabled(enable
);
422 //////////////////////////////////////////////
424 Radical::Radical(QString text
, unsigned int strokes
)
430 void Radical::addKanji(const QString
&text
)