File indexing completed on 2022-09-27 12:25:39

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 
0020 #include <KLocalizedString>
0021 
0022 #include <QGridLayout>
0023 #include <QLabel>
0024 #include <QString>
0025 
0026 ButtonGrid::ButtonGrid( QWidget *parent, RadicalFile *radicalInfo )
0027 : QWidget( parent )
0028 , CurrentMode( Selection )
0029 , m_radicalInfo( radicalInfo )
0030 , m_sortByFrequency( false )
0031 {
0032   if ( m_radicalInfo )
0033   {
0034     buildRadicalButtons();
0035   }
0036 }
0037 
0038 ButtonGrid::~ButtonGrid()
0039 {
0040 }
0041 
0042 void ButtonGrid::buildRadicalButtons()
0043 {
0044   if( layout() )
0045   {
0046     // Instead of iterating over our children and deleting them one by one, we
0047     // simply reparent the previous layout to a temporary widget; when it goes
0048     // out of scope, everything will be automatically deleted.
0049     // Thanks to https://stackoverflow.com/a/10439207 for the tip!
0050     QWidget().setLayout( layout() );
0051   }
0052 
0053   //Setup the grid
0054   QGridLayout *grid = new QGridLayout( this );
0055 
0056   //Now make labels
0057   for( unsigned int i = 0; i < number_of_radical_columns; i++ )
0058   {
0059     QString headerString = QString::number( i + 1 );
0060     if( i == ( number_of_radical_columns - 1 ) )
0061     {
0062       headerString.append( QStringLiteral( "+" ) );
0063     }
0064     QLabel *header = new QLabel( headerString, this );
0065     header->setAlignment( Qt::AlignHCenter );
0066     grid->addWidget( header, 0, i );
0067   }
0068 
0069   //Get a list of radicals (organized by strokes)
0070   QMultiMap<int, Radical> *radicalMap = m_radicalInfo->mapRadicalsByStrokes( number_of_radical_columns );
0071   QList<int> radicalStrokeCounts = radicalMap->uniqueKeys();
0072   //Now create all the buttons
0073   foreach( int strokeCount, radicalStrokeCounts )
0074   {
0075     //(0-based column index)
0076     unsigned int column_index = strokeCount - 1;
0077     int row_index = 1;
0078 
0079     QList<Radical> radicals = radicalMap->values( strokeCount );
0080     std::sort( radicals.begin(), radicals.end(),
0081                m_sortByFrequency ? Radical::compareFrequencies : Radical::compareIndices );
0082     foreach( const Radical &radical, radicals )
0083     {
0084       //Make the button
0085       RadicalButton *button = new RadicalButton( radical.toString(), this );
0086       grid->addWidget( button, row_index++, column_index );
0087       //Bind slots/signals for this button
0088       connect( button, &RadicalButton::userClicked,
0089                  this,   &ButtonGrid::radicalClicked );
0090       connect(   this, &ButtonGrid::clearButtonSelections,
0091                button,   &RadicalButton::resetButton );
0092 
0093       //Add this button to our list
0094       m_buttons.insert( radical.toString(), button );
0095     }
0096   }
0097   delete radicalMap;
0098   setLayout( grid );
0099 
0100   updateButtons();
0101 }
0102 
0103 void ButtonGrid::setSortByFrequency( bool enable )
0104 {
0105   if( m_sortByFrequency != enable )
0106   {
0107     m_sortByFrequency = enable;
0108     buildRadicalButtons();
0109   }
0110 }
0111 
0112 void ButtonGrid::clearSelections()
0113 {
0114   m_selectedRadicals.clear();
0115   Q_EMIT clearButtonSelections();
0116 }
0117 
0118 void ButtonGrid::radicalClicked(  const QString &newrad
0119                                 , RadicalButton::ButtonStatus newStatus )
0120 {
0121   if( newStatus == RadicalButton::Related )
0122   {
0123     ; //Do something fancy
0124   }
0125   else if( newStatus == RadicalButton::Normal
0126     || newStatus == RadicalButton::Selected )
0127   {
0128     CurrentMode = Selection;
0129 
0130     if( newStatus == RadicalButton::Normal )
0131     {
0132       m_selectedRadicals.remove( newrad );
0133       if( m_selectedRadicals.isEmpty() )
0134       {
0135         Q_EMIT signalChangeStatusbar( i18n( "No Radicals Selected" ) );
0136       }
0137     }
0138     else
0139     {
0140       m_selectedRadicals.insert( newrad );
0141     }
0142 
0143     updateButtons();
0144   }
0145 }
0146 
0147 void ButtonGrid::updateButtons()
0148 {
0149   if ( ! m_radicalInfo )
0150   {
0151     return;
0152   }
0153   //Special Case/Early exit: no radicals selected
0154   if( m_selectedRadicals.isEmpty() )
0155   {
0156     QList<Kanji> blankList;
0157     foreach( RadicalButton *button, m_buttons )
0158     {
0159       button->setStatus( RadicalButton::Normal );
0160     }
0161 
0162     Q_EMIT possibleKanji( blankList );
0163     return;
0164   }
0165 
0166   //Figure out what our kanji possibilities are
0167   QSet<Kanji> kanjiSet = m_radicalInfo->kanjiContainingRadicals( m_selectedRadicals );
0168 
0169   //Convert to a list, sort, and tell the world!
0170   QList<Kanji> kanjiList = kanjiSet.values();
0171   std::sort(kanjiList.begin(), kanjiList.end());
0172   Q_EMIT possibleKanji( kanjiList );
0173 
0174   //Do the announcement of the selected radical list
0175   QStringList radicalList( m_selectedRadicals.values() );
0176   Q_EMIT signalChangeStatusbar( i18n( "Selected Radicals: " )
0177                               + radicalList.join(QLatin1String(", ") ) );
0178 
0179   //Now figure out what our remaining radical possibilities are
0180   QSet<QString> remainingRadicals = m_radicalInfo->radicalsInKanji( kanjiSet );
0181   //Remove the already selected ones
0182   remainingRadicals -= m_selectedRadicals;
0183 
0184   //Now go through and set status appropriately
0185   QHash<QString, RadicalButton*>::iterator i = m_buttons.begin();
0186   while( i != m_buttons.end() )
0187   {
0188     if( m_selectedRadicals.contains( i.key() ) )
0189     {
0190       i.value()->setStatus( RadicalButton::Selected );
0191     }
0192     else if( remainingRadicals.contains( i.key() ) )
0193     {
0194       i.value()->setStatus( RadicalButton::Normal );
0195     }
0196     else
0197     {
0198       i.value()->setStatus( RadicalButton::NotAppropriate );
0199     }
0200 
0201     ++i;
0202   }
0203 }
0204 
0205