File indexing completed on 2023-05-30 10:42:10
0001 /* 0002 This file is part of Kiten, a KDE Japanese Reference Tool 0003 SPDX-FileCopyrightText: 2011 Daniel E. Moctezuma <democtezuma@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kanjibrowserview.h" 0009 0010 #include "DictKanjidic/dictfilekanjidic.h" 0011 #include "DictKanjidic/entrykanjidic.h" 0012 #include "dictquery.h" 0013 #include "entrylist.h" 0014 #include "kanjibrowser.h" 0015 #include "kanjibrowserconfig.h" 0016 0017 #include <KActionCollection> 0018 #include <KLocalizedString> 0019 #include <KMessageBox> 0020 #include <QAction> 0021 #include <QClipboard> 0022 #include <QDebug> 0023 0024 KanjiBrowserView::KanjiBrowserView(QWidget *parent) 0025 : QWidget(parent) 0026 , _currentKanji(0) 0027 { 0028 setupUi(this); 0029 loadSettings(); 0030 } 0031 0032 KanjiBrowserView::~KanjiBrowserView() 0033 { 0034 } 0035 0036 void KanjiBrowserView::changeGrade(const int grade) 0037 { 0038 _currentGradeList.clear(); 0039 0040 // Indexes of items in the ComboBox: 0041 // All Jouyou Kanji Grades: 0 0042 // Grade 1: 1 0043 // Grade 2: 2 0044 // . 0045 // . 0046 // . 0047 // Not in Jouyou list: ComboBox->count() - 1 0048 0049 if (grade == AllJouyouGrades) { 0050 // Add the all the grades found in our list. 0051 foreach (const int grd, _gradeList) { 0052 _currentGradeList << grd; 0053 } 0054 } 0055 // Here the user selected "Not in Jouyou list". 0056 else if (grade == (_grades->count() - 1)) { 0057 // Only show the kanji with grade 0 (not in Jouyou). 0058 _currentGradeList << 0; 0059 } 0060 // It seems KANJIDIC doesn't have a G7 (grade 7) kanji. 0061 // If the user selects G8 or above, we need to add 1 to the grade 0062 // because the index (from the ComboBox) and the grade will be different. 0063 else if (grade >= Grade7) { 0064 _currentGradeList << (grade + 1); 0065 } 0066 // Show the kanji with the selected grade. 0067 else { 0068 _currentGradeList << grade; 0069 } 0070 0071 // Reload our QListWidget widget. 0072 reloadKanjiList(); 0073 } 0074 0075 void KanjiBrowserView::changeStrokeCount(const int strokes) 0076 { 0077 _currentStrokesList.clear(); 0078 0079 // Indexes of items in the ComboBox: 0080 // No stroke limit: 0 0081 // 1 stroke: 1 0082 // 2 strokes: 2 0083 // . 0084 // . 0085 // . 0086 0087 // We don't need to filter any kanji by stroke number. 0088 if (strokes == NoStrokeLimit) { 0089 // Add all the strokes found to our the list. 0090 foreach (const int stroke, _strokesList) { 0091 _currentStrokesList << stroke; 0092 } 0093 } 0094 // Show the kanji with the selected number of strokes. 0095 else { 0096 _currentStrokesList << strokes; 0097 } 0098 0099 // Reload our QListWidget widget. 0100 reloadKanjiList(); 0101 } 0102 0103 void KanjiBrowserView::changeToInfoPage() 0104 { 0105 _stackedWidget->setCurrentIndex(Info); 0106 } 0107 0108 void KanjiBrowserView::changeToListPage() 0109 { 0110 _stackedWidget->setCurrentIndex(List); 0111 } 0112 0113 QString KanjiBrowserView::convertToCSS(const QFont &font) 0114 { 0115 QString weight; 0116 switch (font.weight()) { 0117 case QFont::Light: 0118 weight = QStringLiteral("lighter"); 0119 break; 0120 case QFont::Normal: 0121 weight = QStringLiteral("normal"); 0122 break; 0123 case QFont::Bold: 0124 weight = QStringLiteral("bold"); 0125 break; 0126 } 0127 0128 QString style; 0129 switch (font.style()) { 0130 case QFont::StyleNormal: 0131 style = QStringLiteral("normal"); 0132 break; 0133 case QFont::StyleItalic: 0134 style = QStringLiteral("italic"); 0135 break; 0136 case QFont::StyleOblique: 0137 style = QStringLiteral("oblique"); 0138 break; 0139 } 0140 0141 return QString( 0142 "font-family:\"%1\";" 0143 "font-size:%2px;" 0144 "font-weight:%3;" 0145 "font-style:%4;") 0146 .arg(font.family()) 0147 .arg(font.pointSizeF()) 0148 .arg(weight) 0149 .arg(style); 0150 } 0151 0152 void KanjiBrowserView::loadSettings() 0153 { 0154 _kanjiList->setFont(KanjiBrowserConfigSkeleton::self()->kanjiListFont()); 0155 _kanjiSize = KanjiBrowserConfigSkeleton::self()->kanjiSize(); 0156 _kanaFont = KanjiBrowserConfigSkeleton::self()->kanaFont(); 0157 _labelFont = KanjiBrowserConfigSkeleton::self()->labelFont(); 0158 0159 // Reload the Kanji Information page with the new font changes. 0160 if (_currentKanji != nullptr) { 0161 showKanjiInformation(_currentKanji); 0162 } 0163 } 0164 0165 void KanjiBrowserView::reloadKanjiList() 0166 { 0167 // Grade and strokes lists have the information of 0168 // which kanji we are going to filter. 0169 // We just iterate on them to actually do the filtering. 0170 QStringList list; 0171 foreach (const int strokes, _currentStrokesList) { 0172 foreach (const int grade, _currentGradeList) { 0173 list.append(_kanji.keys(qMakePair(grade, strokes))); 0174 } 0175 } 0176 0177 _kanjiList->clear(); 0178 _kanjiList->addItems(list); 0179 0180 // Update our status bar with the number of kanji filtered. 0181 statusBarChanged(i18np("%1 kanji found", "%1 kanji found", _kanjiList->count())); 0182 } 0183 0184 void KanjiBrowserView::searchKanji(QListWidgetItem *item) 0185 { 0186 if (_currentKanji != nullptr && item->text() == _currentKanji->getWord()) { 0187 return; 0188 } 0189 0190 _goToKanjiInfo->setText(i18n("About %1", item->text())); 0191 _copyToClipboard->setText(i18n("Copy %1 to clipboard", item->text())); 0192 _copyToClipboard->setVisible(true); 0193 0194 Entry *result = _parent->_dictFileKanjidic->doSearch(DictQuery(item->text()))->first(); 0195 EntryKanjidic *kanji = static_cast<EntryKanjidic *>(result); 0196 _currentKanji = kanji; 0197 0198 showKanjiInformation(kanji); 0199 } 0200 0201 void KanjiBrowserView::setupView(KanjiBrowser *parent, const QHash<QString, QPair<int, int>> &kanji, QList<int> &kanjiGrades, QList<int> &strokeCount) 0202 { 0203 if (kanji.isEmpty() || kanjiGrades.isEmpty() || strokeCount.isEmpty()) { 0204 qDebug() << "One or more of our lists are empty (kanji, grades, strokes)."; 0205 qDebug() << "Could not load the view properly."; 0206 KMessageBox::error(this, i18n("Could not load the necessary kanji information.")); 0207 return; 0208 } 0209 0210 _parent = parent; 0211 _kanji = kanji; 0212 _gradeList = kanjiGrades; 0213 _strokesList = strokeCount; 0214 0215 QAction *goToKanjiList = _parent->actionCollection()->addAction(QStringLiteral("kanji_list")); 0216 goToKanjiList->setText(i18n("Kanji &List")); 0217 0218 _goToKanjiInfo = _parent->actionCollection()->addAction(QStringLiteral("kanji_info")); 0219 _goToKanjiInfo->setText(i18n("Kanji &Information")); 0220 0221 _copyToClipboard = _parent->actionCollection()->addAction(QStringLiteral("copy_kanji_to_clipboard")); 0222 _copyToClipboard->setVisible(false); 0223 0224 _grades->addItem(i18n("All Jouyou Kanji grades")); 0225 foreach (const int &grade, kanjiGrades) { 0226 // Grades 9 and above are considered Jinmeiyou. 0227 if (grade >= Jinmeiyou) { 0228 _grades->addItem(i18n("Grade %1 (Jinmeiyou)", grade)); 0229 } else { 0230 _grades->addItem(i18n("Grade %1", grade)); 0231 } 0232 } 0233 _grades->addItem(i18n("Not in Jouyou list")); 0234 0235 _strokes->addItem(i18n("No stroke limit")); 0236 foreach (const int &stroke, strokeCount) { 0237 _strokes->addItem(i18np("%1 stroke", "%1 strokes", stroke)); 0238 } 0239 0240 connect(_grades, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this, &KanjiBrowserView::changeGrade); 0241 connect(_strokes, static_cast<void (KComboBox::*)(int)>(&KComboBox::currentIndexChanged), this, &KanjiBrowserView::changeStrokeCount); 0242 connect(_kanjiList, &QListWidget::itemClicked, this, &KanjiBrowserView::searchKanji); 0243 connect(_kanjiList, &QListWidget::itemClicked, _goToKanjiInfo, &QAction::triggered); 0244 connect(goToKanjiList, &QAction::triggered, this, &KanjiBrowserView::changeToListPage); 0245 connect(_goToKanjiInfo, &QAction::triggered, this, &KanjiBrowserView::changeToInfoPage); 0246 connect(_copyToClipboard, &QAction::triggered, this, &KanjiBrowserView::toClipboard); 0247 0248 // Set the current grade (Grade 1). 0249 _grades->setCurrentIndex(1); 0250 // Set the current number of strokes (No stroke limit). 0251 // NOTE: we change from '1 stroke' to 'No stroke limit' 0252 // to let the ComboBox notice the change and do the filter. 0253 _strokes->setCurrentIndex(1); 0254 _strokes->setCurrentIndex(NoStrokeLimit); 0255 0256 qDebug() << "Initial setup succeeded!"; 0257 } 0258 0259 void KanjiBrowserView::showKanjiInformation(const EntryKanjidic *kanji) 0260 { 0261 // This font is shipped with Kiten and should not be changed as it shows 0262 // the stroke order of a kanji. 0263 QFont kanjiFont(QStringLiteral("KanjiStrokeOrders")); 0264 kanjiFont.setPointSizeF(_kanjiSize.toReal()); 0265 0266 QString text; 0267 text.append("<html><body><style>"); 0268 text.append(QStringLiteral(".kanji { %1 }").arg(convertToCSS(kanjiFont))); 0269 text.append(QStringLiteral(".label { %1 }").arg(convertToCSS(_labelFont))); 0270 text.append(QStringLiteral(".kana { %1 }").arg(convertToCSS(_kanaFont))); 0271 text.append("</style>"); 0272 0273 // Put the kanji. 0274 text.append(QStringLiteral("<table><tr><td><p class=\"kanji\">%1</p></td>").arg(kanji->getWord())); 0275 0276 // Now the kanji grades and number of strokes. 0277 text.append("<td>"); 0278 if (!kanji->getKanjiGrade().isEmpty()) { 0279 text.append(QStringLiteral("<p class=\"label\">%1 %2</p></br>").arg(i18n("Grade:")).arg(kanji->getKanjiGrade())); 0280 } 0281 text.append(QStringLiteral("<p class=\"label\">%1 %2</p></td></tr></table>").arg(i18n("Strokes:")).arg(kanji->getStrokesCount())); 0282 0283 // Onyomi readings. 0284 if (!kanji->getOnyomiReadingsList().isEmpty()) { 0285 text.append(QString("<p class=\"label\">%1" 0286 "<span class=\"kana\">%2</span></p></br>") 0287 .arg(i18n("Onyomi: ")) 0288 .arg(kanji->getOnyomiReadings())); 0289 } 0290 0291 // Kunyomi readings. 0292 if (!kanji->getKunyomiReadingsList().isEmpty()) { 0293 text.append(QString("<p class=\"label\">%1" 0294 "<span class=\"kana\">%2</span></p></br>") 0295 .arg(i18n("Kunyomi: ")) 0296 .arg(kanji->getKunyomiReadings())); 0297 } 0298 0299 // Special readings used in names. 0300 if (!kanji->getInNamesReadingsList().isEmpty()) { 0301 text.append(QString("<p class=\"label\">%1" 0302 "<span class=\"kana\">%2</span></p></br>") 0303 .arg(i18n("In names: ")) 0304 .arg(kanji->getInNamesReadings())); 0305 } 0306 0307 // Reading used as radical. 0308 if (!kanji->getAsRadicalReadingsList().isEmpty()) { 0309 text.append(QString("<p class=\"label\">%1" 0310 "<span class=\"kana\">%2</span></p></br>") 0311 .arg(i18n("As radical: ")) 0312 .arg(kanji->getAsRadicalReadings())); 0313 } 0314 0315 // Meanings 0316 text.append("<p class=\"label\">"); 0317 if (kanji->getMeaningsList().count() == 1) { 0318 text.append(i18n("Meaning: ")); 0319 } else { 0320 text.append(i18n("Meanings: ")); 0321 } 0322 text.append(QStringLiteral("<span class=\"kana\">%1</span></p>").arg(kanji->getMeanings())); 0323 0324 // Close remaining tags and set the HTML text. 0325 text.append("</body></html>"); 0326 _kanjiInformation->setHtml(text); 0327 } 0328 0329 void KanjiBrowserView::toClipboard() 0330 { 0331 QClipboard *cb = QApplication::clipboard(); 0332 cb->setText(_currentKanji->getWord(), QClipboard::Clipboard); 0333 cb->setText(_currentKanji->getWord(), QClipboard::Selection); 0334 }