File indexing completed on 2024-09-15 03:28:20
0001 /* 0002 This file is part of Kiten, a KDE Japanese Reference Tool 0003 SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 /** 0009 * Future Plans: 0010 * 0011 * Design a custom QGridLayout to rearrange buttons dynamically to resize 0012 * Design multiple radical file handling 0013 * Icon set for displaying radicals outside of this bizarre unicode section 0014 * Radical decomposition implementation 0015 */ 0016 0017 #include "buttongrid.h" 0018 0019 #include <KLocalizedString> 0020 0021 #include <QGridLayout> 0022 #include <QLabel> 0023 #include <QString> 0024 0025 ButtonGrid::ButtonGrid(QWidget *parent, RadicalFile *radicalInfo) 0026 : QWidget(parent) 0027 , CurrentMode(Selection) 0028 , m_radicalInfo(radicalInfo) 0029 , m_sortByFrequency(false) 0030 { 0031 if (m_radicalInfo) { 0032 buildRadicalButtons(); 0033 } 0034 } 0035 0036 void ButtonGrid::buildRadicalButtons() 0037 { 0038 if (layout()) { 0039 // Instead of iterating over our children and deleting them one by one, we 0040 // simply reparent the previous layout to a temporary widget; when it goes 0041 // out of scope, everything will be automatically deleted. 0042 // Thanks to https://stackoverflow.com/a/10439207 for the tip! 0043 QWidget().setLayout(layout()); 0044 } 0045 0046 // Setup the grid 0047 auto grid = new QGridLayout(this); 0048 0049 // Now make labels 0050 for (unsigned int i = 0; i < number_of_radical_columns; i++) { 0051 QString headerString = QString::number(i + 1); 0052 if (i == (number_of_radical_columns - 1)) { 0053 headerString.append(QStringLiteral("+")); 0054 } 0055 auto header = new QLabel(headerString, this); 0056 header->setAlignment(Qt::AlignHCenter); 0057 grid->addWidget(header, 0, i); 0058 } 0059 0060 // Get a list of radicals (organized by strokes) 0061 QMultiMap<int, Radical> *radicalMap = m_radicalInfo->mapRadicalsByStrokes(number_of_radical_columns); 0062 QList<int> radicalStrokeCounts = radicalMap->uniqueKeys(); 0063 // Now create all the buttons 0064 for (int strokeCount : radicalStrokeCounts) { 0065 //(0-based column index) 0066 unsigned int column_index = strokeCount - 1; 0067 int row_index = 1; 0068 0069 QList<Radical> radicals = radicalMap->values(strokeCount); 0070 std::sort(radicals.begin(), radicals.end(), m_sortByFrequency ? Radical::compareFrequencies : Radical::compareIndices); 0071 for (const Radical &radical : radicals) { 0072 // Make the button 0073 auto button = new RadicalButton(radical.toString(), this); 0074 grid->addWidget(button, row_index++, column_index); 0075 // Bind slots/signals for this button 0076 connect(button, &RadicalButton::userClicked, this, &ButtonGrid::radicalClicked); 0077 connect(this, &ButtonGrid::clearButtonSelections, button, &RadicalButton::resetButton); 0078 0079 // Add this button to our list 0080 m_buttons.insert(radical.toString(), button); 0081 } 0082 } 0083 delete radicalMap; 0084 setLayout(grid); 0085 0086 updateButtons(); 0087 } 0088 0089 void ButtonGrid::setSortByFrequency(bool enable) 0090 { 0091 if (m_sortByFrequency != enable) { 0092 m_sortByFrequency = enable; 0093 buildRadicalButtons(); 0094 } 0095 } 0096 0097 void ButtonGrid::clearSelections() 0098 { 0099 m_selectedRadicals.clear(); 0100 Q_EMIT clearButtonSelections(); 0101 } 0102 0103 void ButtonGrid::radicalClicked(const QString &newrad, RadicalButton::ButtonStatus newStatus) 0104 { 0105 if (newStatus == RadicalButton::Related) { 0106 // TODO: Do something fancy 0107 } else if (newStatus == RadicalButton::Normal || newStatus == RadicalButton::Selected) { 0108 CurrentMode = Selection; 0109 0110 if (newStatus == RadicalButton::Normal) { 0111 m_selectedRadicals.remove(newrad); 0112 if (m_selectedRadicals.isEmpty()) { 0113 Q_EMIT signalChangeStatusbar(i18n("No Radicals Selected")); 0114 } 0115 } else { 0116 m_selectedRadicals.insert(newrad); 0117 } 0118 0119 updateButtons(); 0120 } 0121 } 0122 0123 void ButtonGrid::updateButtons() 0124 { 0125 if (!m_radicalInfo) { 0126 return; 0127 } 0128 // Special Case/Early exit: no radicals selected 0129 if (m_selectedRadicals.isEmpty()) { 0130 QList<Kanji> blankList; 0131 for (RadicalButton *button : m_buttons) { 0132 button->setStatus(RadicalButton::Normal); 0133 } 0134 0135 Q_EMIT possibleKanji(blankList); 0136 return; 0137 } 0138 0139 // Figure out what our kanji possibilities are 0140 QSet<Kanji> kanjiSet = m_radicalInfo->kanjiContainingRadicals(m_selectedRadicals); 0141 0142 // Convert to a list, sort, and tell the world! 0143 QList<Kanji> kanjiList = kanjiSet.values(); 0144 std::sort(kanjiList.begin(), kanjiList.end()); 0145 Q_EMIT possibleKanji(kanjiList); 0146 0147 // Do the announcement of the selected radical list 0148 QStringList radicalList(m_selectedRadicals.values()); 0149 Q_EMIT signalChangeStatusbar(i18n("Selected Radicals: ") + radicalList.join(QLatin1String(", "))); 0150 0151 // Now figure out what our remaining radical possibilities are 0152 QSet<QString> remainingRadicals = m_radicalInfo->radicalsInKanji(kanjiSet); 0153 // Remove the already selected ones 0154 remainingRadicals -= m_selectedRadicals; 0155 0156 // Now go through and set status appropriately 0157 QHash<QString, RadicalButton *>::iterator i = m_buttons.begin(); 0158 while (i != m_buttons.end()) { 0159 if (m_selectedRadicals.contains(i.key())) { 0160 i.value()->setStatus(RadicalButton::Selected); 0161 } else if (remainingRadicals.contains(i.key())) { 0162 i.value()->setStatus(RadicalButton::Normal); 0163 } else { 0164 i.value()->setStatus(RadicalButton::NotAppropriate); 0165 } 0166 0167 ++i; 0168 } 0169 } 0170 0171 #include "moc_buttongrid.cpp"