File indexing completed on 2024-04-21 03:42:03
0001 /* 0002 SPDX-FileCopyrightText: 2001-2008 Anne-Marie Mahfouf <annma@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "klettres.h" 0008 0009 //Qt includes 0010 #include <QAction> 0011 #include <QBitmap> 0012 #include <QFile> 0013 #include <QLabel> 0014 #include <QPainter> 0015 #include <QStatusBar> 0016 #include <QIcon> 0017 #include <QTextStream> 0018 #include <QMenuBar> 0019 #include <QDomDocument> 0020 #include <QWidget> 0021 #include <QStandardPaths> 0022 #include <QPointer> 0023 0024 //KDE includes 0025 #include <KActionCollection> 0026 #include <KConfigDialog> 0027 #include <KLocalizedString> 0028 #include <KMessageBox> 0029 #include <KSelectAction> 0030 #include <KStandardAction> 0031 #include <KToolBar> 0032 #include <KToggleAction> 0033 0034 #include <KNSWidgets/Dialog> 0035 //Project includes 0036 #include "ui_fontsdlg.h" 0037 #include "timer.h" 0038 #include "prefs.h" 0039 #include "langutils.h" 0040 #include "kltheme.h" 0041 0042 class FontChooser : public KFontChooser, public Ui::fontsdlg 0043 { 0044 public: 0045 FontChooser(QWidget * parent) 0046 : KFontChooser(KFontChooser::NoDisplayFlags, parent) 0047 { 0048 setupUi(this); 0049 } 0050 }; 0051 0052 const int ID_KIDB = 100; 0053 const int ID_GROWNB = 101; 0054 const int ID_MENUBARB = 102; 0055 0056 KLettres::KLettres() 0057 : KXmlGuiWindow( nullptr ) 0058 { 0059 setObjectName( QStringLiteral("KLettres") ); 0060 mNewStuff = nullptr; 0061 m_view = new KLettresView(this); 0062 setMinimumSize( QSize( 800, 600 ) ); 0063 //Tell the KXmlGuiWindow that this is indeed the main widget 0064 setCentralWidget(m_view); 0065 //Populate Languages menu with m_languageNames 0066 m_languageNames = LangUtils::getLanguagesNames(LangUtils::getLanguages()); 0067 //MainWindow GUI: menus, tolbars and statusbar 0068 setupActions(); 0069 setupStatusbar(); 0070 setupToolbars(); 0071 //Load Settings 0072 loadSettings(); 0073 //Setup current language sounds 0074 soundFactory = new SoundFactory(this, QStringLiteral("sounds")); 0075 //Start game 0076 m_view->game(); 0077 } 0078 0079 KLettres::~KLettres() 0080 { 0081 } 0082 0083 bool KLettres::loadLayout(QDomDocument &layoutDocument) 0084 { 0085 QFile layoutFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, 0086 QStringLiteral("klettres/")+Prefs::language()+QStringLiteral("/sounds.xml"))); 0087 0088 //if xml file is not found, program exits 0089 if (!layoutFile.exists()) { 0090 qWarning() << "sounds.xml file not found in $KDEDIR/share/apps/klettres/" << Prefs::language() ; 0091 QString mString=i18n("The file sounds.xml was not found in\n" 0092 "$KDEDIR/share/apps/klettres/\n\n" 0093 "Please install this file and start KLettres again.\n\n"); 0094 KMessageBox::information( this, mString,i18n("KLettres - Error") ); 0095 qApp->quit();//exit(1); 0096 } 0097 0098 if (!layoutFile.open(QIODevice::ReadOnly)) { 0099 return false; 0100 } 0101 0102 //Check if document is well-formed 0103 if (!layoutDocument.setContent(&layoutFile)) { 0104 layoutFile.close(); 0105 return false; 0106 } 0107 0108 layoutFile.close(); 0109 0110 return true; 0111 } 0112 0113 void KLettres::setupActions() 0114 { 0115 QAction *m_newAction = actionCollection()->addAction(QStringLiteral("play_new")); 0116 m_newAction->setText(i18n("New Sound")); 0117 actionCollection()->setDefaultShortcut(m_newAction,QKeySequence(Qt::CTRL | Qt::Key_N)); 0118 m_newAction->setIcon(QIcon::fromTheme(QStringLiteral("document-new"))); // ### better icon for this? 0119 connect(m_newAction, &QAction::triggered, m_view, &KLettresView::game); 0120 m_newAction->setToolTip(i18n("Play a new sound")); 0121 m_newAction->setWhatsThis(i18n("You can play a new sound by clicking this button or using the File menu, New Sound.")); 0122 0123 QAction *m_stuffAction = actionCollection()->addAction(QStringLiteral("downloadnewstuff")); 0124 m_stuffAction->setText(i18n("Get Alphabet in New Language...")); 0125 m_stuffAction->setIcon(QIcon::fromTheme(QStringLiteral("get-hot-new-stuff"))); 0126 connect(m_stuffAction, &QAction::triggered, this, &KLettres::slotDownloadNewStuff); 0127 0128 QAction *m_playAgainAction = actionCollection()->addAction(QStringLiteral("play_again")); 0129 m_playAgainAction->setText(i18n("Replay Sound")); 0130 actionCollection()->setDefaultShortcut(m_playAgainAction,QKeySequence(Qt::Key_F5)); 0131 m_playAgainAction->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); 0132 m_playAgainAction->setToolTip(i18n("Play the same sound again")); 0133 connect(m_playAgainAction, &QAction::triggered, m_view, &KLettresView::slotPlayAgain); 0134 m_playAgainAction->setWhatsThis(i18n("You can replay the same sound again by clicking this button or using the File menu, Replay Sound.")); 0135 KStandardAction::quit(qApp, SLOT(quit()), actionCollection()); 0136 0137 m_menubarAction = KStandardAction::showMenubar(this, SLOT(slotMenubar()), actionCollection()); 0138 0139 m_levelAction = actionCollection()->add<KSelectAction>(QStringLiteral("levels")); 0140 m_levelAction->setText(i18nc("@label:listbox which difficulty level to use", "L&evel")); 0141 m_levelAction->setToolTip(i18n("Select the level")); 0142 m_levelAction->setWhatsThis(i18n("You can select the level: level 1 displays a letter and you hear it; level 2 does not display the letter, you only hear it; level 3 displays a syllable and you hear it; level 4 does not display the syllable, you only hear it.")); 0143 0144 m_languageAction = actionCollection()->add<KSelectAction>(QStringLiteral("languages")); 0145 m_languageAction->setText(i18nc("@label:listbox", "&Language")); 0146 m_languageAction->setItems(m_languageNames); 0147 0148 m_levelsNames.append(i18ncp("@item:inlistbox choose level", "Level %1" , "Level %1", 1)); 0149 m_levelsNames.append(i18ncp("@item:inlistbox choose level", "Level %1" , "Level %1", 2)); 0150 m_levelsNames.append(i18ncp("@item:inlistbox choose level", "Level %1" , "Level %1", 3)); 0151 m_levelsNames.append(i18ncp("@item:inlistbox choose level", "Level %1" , "Level %1", 4)); 0152 m_levelAction->setItems(m_levelsNames); 0153 m_levelAction->setCurrentItem(Prefs::level()-1); 0154 0155 m_themeAction = actionCollection()->add<KSelectAction>(QStringLiteral("looks")); 0156 m_themeAction->setText(i18n("Themes")); 0157 m_themeAction->setItems(KLThemeFactory::instance()->themeList()); 0158 m_themeAction->setCurrentItem(Prefs::theme()); 0159 m_themeAction->setToolTip(i18n("Select the theme")); 0160 m_themeAction->setWhatsThis(i18n("Here you can change the theme for KLettres. A theme consists in the background picture and the font color for the letter displayed.")); 0161 0162 m_kidAction = actionCollection()->add<KToggleAction>(QStringLiteral("mode_kid")); 0163 m_kidAction->setText(i18n("Mode Kid")); 0164 actionCollection()->setDefaultShortcut(m_kidAction,QKeySequence(Qt::CTRL | Qt::Key_K)); 0165 m_kidAction->setIcon(QIcon::fromTheme(QStringLiteral("klettres_kids"))); 0166 connect(m_kidAction, &KToggleAction::triggered, this, &KLettres::slotModeKid); 0167 m_kidAction->setWhatsThis(i18n("If you are in the Grown-up mode, clicking on this button will set up the Kid mode. The Kid mode has no menubar and the font is bigger in the statusbar.")); 0168 0169 m_grownupAction = actionCollection()->add<KToggleAction>(QStringLiteral("mode_grownup")); 0170 m_grownupAction->setText(i18n("Mode Grown-up")); 0171 actionCollection()->setDefaultShortcut(m_grownupAction,QKeySequence(Qt::CTRL | Qt::Key_G)); 0172 m_grownupAction->setIcon(QIcon::fromTheme(QStringLiteral("klettres_grownup"))); 0173 connect(m_grownupAction, &KToggleAction::triggered, this, &KLettres::slotModeGrownup); 0174 m_grownupAction->setWhatsThis(i18n("The Grownup mode is the normal mode where you can see the menubar.")); 0175 0176 connect(m_levelAction, &KSelectAction::indexTriggered, this, &KLettres::slotChangeLevel); 0177 connect(m_languageAction, &KSelectAction::indexTriggered, this, &KLettres::slotChangeLanguage); 0178 connect(m_themeAction, &KSelectAction::indexTriggered, this, &KLettres::slotChangeTheme); 0179 0180 KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); 0181 0182 setupGUI(); 0183 } 0184 0185 void KLettres::setupStatusbar() 0186 { 0187 QStatusBar *st=statusBar(); 0188 m_langLabel = new QLabel(st); 0189 m_levLabel = new QLabel(st); 0190 st->addWidget(m_langLabel); 0191 // st->insertFixedItem("", 1);//add a space 0192 st->addWidget(m_levLabel); 0193 statusBar(); 0194 } 0195 0196 void KLettres::setupToolbars() 0197 { 0198 // Toolbar for special characters 0199 specialCharToolbar = toolBar(QStringLiteral("specialCharToolbar")); 0200 addToolBar ( Qt::BottomToolBarArea, specialCharToolbar); 0201 } 0202 0203 void KLettres::optionsPreferences() 0204 { 0205 if(KConfigDialog::showDialog(QStringLiteral("settings"))) { 0206 return; 0207 } 0208 0209 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Prefs::self()); 0210 dialog->addPage(new FontChooser(nullptr), i18n("Font"), QStringLiteral("preferences-desktop-font"), i18n("Font Settings")); 0211 Timer *m_timer = new Timer(); 0212 dialog->addPage(m_timer, i18n("Timer"), QStringLiteral("chronometer"), i18n("Timer Settings")); 0213 connect(dialog, &KConfigDialog::settingsChanged, this, &KLettres::slotUpdateSettings); 0214 dialog->setAttribute( Qt::WA_DeleteOnClose ); 0215 // dialog->setHelp(QString(), "klettres"); 0216 dialog->show(); 0217 } 0218 0219 void KLettres::loadSettings() 0220 { 0221 if (LangUtils::getLanguages().indexOf(Prefs::language()) < 0) { 0222 Prefs::setLanguage(QStringLiteral("en")); 0223 } 0224 QString langString = LangUtils::getLanguagesNames(LangUtils::getLanguages())[LangUtils::getLanguages().indexOf(Prefs::language())]; 0225 m_languageAction->setCurrentItem(LangUtils::getLanguages().indexOf(Prefs::language())); 0226 langString.remove(QLatin1Char('&')); 0227 m_langLabel->setText(langString); 0228 loadLangToolBar(); 0229 // load default level 0230 m_levLabel->setText(i18nc("@info:status the current level chosen", "(Level %1)", Prefs::level())); 0231 0232 m_view->setTheme(KLThemeFactory::instance()->buildTheme(Prefs::theme())); 0233 0234 if (Prefs::mode() == Prefs::EnumMode::grownup) { 0235 slotModeGrownup(); 0236 } else { 0237 slotModeKid(); 0238 } 0239 0240 m_menubarAction->setChecked(Prefs::menuBarBool()); 0241 slotMenubar(); 0242 } 0243 0244 void KLettres::slotDownloadNewStuff() 0245 { 0246 KNSWidgets::Dialog *dialog = new KNSWidgets::Dialog(QStringLiteral("khangman.knsrc"), this); 0247 dialog->open(); 0248 connect(dialog, &KNSWidgets::Dialog::finished, this, [this, dialog] { 0249 const QList<KNSCore::Entry> entries = dialog->changedEntries(); 0250 if (!entries.isEmpty()) { 0251 //look for languages dirs installed 0252 QStringList languages = LangUtils::getLanguages(); 0253 m_languageNames = LangUtils::getLanguagesNames(languages); 0254 0255 //refresh Languages menu 0256 m_languageAction->setItems(m_languageNames); 0257 slotChangeLanguage(languages.indexOf(Prefs::language())); 0258 m_languageAction->setCurrentItem(languages.indexOf(Prefs::language())); 0259 } 0260 dialog->deleteLater(); 0261 }); 0262 0263 } 0264 0265 void KLettres::slotMenubar() 0266 { 0267 menuBar()->setVisible(m_menubarAction->isChecked()); 0268 Prefs::setMenuBarBool(m_menubarAction->isChecked()); 0269 Prefs::self()->save(); 0270 } 0271 0272 void KLettres::slotUpdateSettings() 0273 { 0274 m_view->m_timer = Prefs::kidTimer(); 0275 m_view->m_timer = Prefs::grownTimer(); 0276 //apply the font 0277 m_view->setFont(Prefs::font()); 0278 } 0279 0280 void KLettres::slotChangeLevel(int newLevel) 0281 { 0282 Prefs::setLevel(newLevel+1); 0283 Prefs::self()->save(); 0284 updateLevMenu(newLevel); 0285 //TODO is that necessary? Change level effectively by reloading sounds 0286 0287 //this is duplicated in changeLanguage() 0288 soundFactory->change(Prefs::language()); 0289 //update game effectively 0290 m_view->randomInt = 0; 0291 m_view->game(); 0292 } 0293 0294 void KLettres::updateLevMenu(int id) 0295 { 0296 //m_levelCombo->setCurrentItem(id); 0297 m_levelAction->setCurrentItem(id); 0298 m_levLabel->setText(i18nc("@info:status the current level chosen", "(Level %1)", Prefs::level())); 0299 } 0300 0301 void KLettres::slotChangeLanguage(int newIndex) 0302 { 0303 // Write new language ISO in config 0304 QString newLanguage = LangUtils::getLanguages()[newIndex]; 0305 Prefs::setLanguage(newLanguage); 0306 Prefs::self()->save(); 0307 // Update the StatusBar 0308 QString langString = LangUtils::getLanguagesNames(LangUtils::getLanguages())[newIndex]; 0309 langString.remove(QLatin1Char('&')); 0310 m_langLabel->setText(langString); 0311 loadLangToolBar(); 0312 // Change language effectively 0313 bool ok = loadLayout(soundFactory->m_layoutsDocument); 0314 0315 if (ok) { 0316 soundFactory->change(Prefs::language()); 0317 } 0318 0319 m_view->randomInt = 0; 0320 m_view->game(); 0321 } 0322 0323 void KLettres::slotChangeTheme(int index) 0324 { 0325 Prefs::setTheme(index); 0326 Prefs::self()->save(); 0327 m_view->setTheme(KLThemeFactory::instance()->buildTheme(index)); 0328 } 0329 0330 void KLettres::slotModeGrownup() 0331 { 0332 QPalette pal; 0333 pal.setColor( QPalette::Window, Qt::white); 0334 statusBar()->setPalette( pal ); 0335 QFont f_lab( QStringLiteral("Serif") , 10); //font for statusBar 0336 m_levLabel->setFont(f_lab); 0337 m_langLabel->setFont(f_lab); 0338 m_menubarAction->setChecked(true); 0339 m_grownupAction->setChecked(true); 0340 m_kidAction->setChecked(false); 0341 m_grownupAction->setToolTip(i18n("Grown-up mode is currently active")); 0342 m_kidAction->setToolTip(i18n("Switch to Kid mode")); 0343 menuBar()->show(); 0344 m_view->m_timer = Prefs::grownTimer(); 0345 Prefs::setMode(Prefs::EnumMode::grownup); 0346 Prefs::self()->save(); 0347 } 0348 0349 void KLettres::slotModeKid() 0350 { 0351 QPalette pal; 0352 pal.setColor( QPalette::Window, Qt::white); 0353 statusBar()->setPalette( pal ); 0354 QFont f_lab( QStringLiteral("Serif") , 12); //font for statusBar 0355 f_lab.setBold(true); 0356 m_levLabel->setFont(f_lab); 0357 m_langLabel->setFont(f_lab); 0358 m_menubarAction->setChecked(false); 0359 m_kidAction->setChecked(true); 0360 m_kidAction->setToolTip(i18n("Kid mode is currently active")); 0361 m_grownupAction->setToolTip(i18n("Switch to Grown-up mode")); 0362 m_grownupAction->setChecked(false); 0363 menuBar()->hide(); 0364 m_view->m_timer = Prefs::kidTimer(); 0365 Prefs::setMode(Prefs::EnumMode::kid); 0366 Prefs::self()->save(); 0367 } 0368 0369 void KLettres::loadLangToolBar() 0370 { 0371 QString lang = Prefs::language(); 0372 0373 specialCharToolbar->clear(); 0374 0375 if (LangUtils::hasSpecialChars(lang)) {//Dutch, English, French and Italian have no special characters 0376 allData.clear(); 0377 QString myString=QStringLiteral("klettres/%1.txt").arg(lang); 0378 QFile myFile; 0379 myFile.setFileName(QStandardPaths::locate(QStandardPaths::GenericDataLocation, myString)); 0380 0381 if (!myFile.exists()) { 0382 QString mString=i18n("File $KDEDIR/share/apps/klettres/%1.txt not found;\n" 0383 "please check your installation.", lang); 0384 KMessageBox::error( this, mString, 0385 i18n("Error") ); 0386 qApp->quit(); 0387 } 0388 0389 //we open the file and store info into the stream... 0390 QFile openFileStream(myFile.fileName()); 0391 openFileStream.open(QIODevice::ReadOnly); 0392 QTextStream readFileStr(&openFileStream); 0393 //allData contains all the words from the file 0394 allData = readFileStr.readAll().split(QLatin1Char('\n')); 0395 openFileStream.close(); 0396 0397 for (int i=0; i<(int) allData.count(); ++i) { 0398 if (!allData[i].isEmpty()) { 0399 QAction *act = specialCharToolbar->addAction(allData.at(i)); 0400 act->setIcon(charIcon(allData.at(i).at(0))); 0401 // used to carry the id 0402 act->setData(i); 0403 connect(act, &QAction::triggered, this, &KLettres::slotPasteChar); 0404 } 0405 } 0406 0407 specialCharToolbar->show(); 0408 update(); 0409 } else { 0410 specialCharToolbar->hide(); 0411 } 0412 } 0413 0414 void KLettres::slotPasteChar() 0415 { 0416 QAction *act = qobject_cast<QAction*>(sender()); 0417 if (!act) { 0418 return; 0419 } 0420 0421 bool ok = true; 0422 int id = act->data().toInt(&ok); 0423 0424 if (!ok || id < 0 || id >= allData.count()) { 0425 return; 0426 } 0427 0428 m_view->m_letterEdit->insert(allData.at(id)); 0429 } 0430 0431 QIcon KLettres::charIcon(QChar c) 0432 { 0433 ///Create a name and path for the icon 0434 // 0435 // FIXME: This code used KStandardDirs::locateLocal("icon", ...) before 0436 // and I am not sure if GenericCacheLocation is what we are aiming 0437 // for. So best would be if somebody experienced in QStandardPaths 0438 // could confirm or change it. 0439 0440 QString s = QStandardPaths::locate(QStandardPaths::GenericCacheLocation, 0441 QStringLiteral("char") + QString::number(c.unicode()) + QStringLiteral(".png")); 0442 0443 QRect r(4, 4, 120, 120); 0444 0445 ///A font to draw the character with 0446 QFont font; 0447 font.setFamily( QStringLiteral("Arial") ); 0448 font.setPixelSize(120); 0449 font.setWeight(QFont::Normal); 0450 0451 ///Create the pixmap 0452 QPixmap pm(128, 128); 0453 pm.fill(Qt::white); 0454 QPainter p(&pm); 0455 p.setFont(font); 0456 p.setPen(Qt::black); 0457 p.drawText(r, Qt::AlignCenter, (QString) c); 0458 0459 ///Create transparency mask 0460 QBitmap bm(128, 128); 0461 bm.fill(Qt::color0); 0462 QPainter b(&bm); 0463 b.setFont(font); 0464 b.setPen(Qt::color1); 0465 b.drawText(r, Qt::AlignCenter, (QString) c); 0466 0467 ///Mask the pixmap 0468 pm.setMask(bm); 0469 0470 ///Save the icon to disk 0471 pm.save(s, "PNG"); 0472 0473 return QIcon(pm); 0474 } 0475 0476 #include "moc_klettres.cpp"