/*************************************************************************** * ktouch.cpp * * ---------- * * Copyright (C) 2000 by Håvard Frøiland, 2004 by Andreas Nicolai * * ghorwin@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "ktouch.h" #include "ktouch.moc" // Qt Header #include // KDE Header #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // KTouch Header #include "ktouch_build_config.h" #include "ktouchlecture.h" #include "ktouchtrainer.h" #include "ktouchstatuswidget.h" #include "ktouchkeyboardwidget.h" #include "ktouchtextlinewidget.h" #include "ktouchlectureeditordialog.h" #include "ktouchkeyboardeditordialog.h" #include "ktouchcoloreditordialog.h" #include "ktouchstatisticsdialog.h" #include "ktouchusersetupdialog.h" #include "ktouchprefgeneral.h" #include "ktouchpreftraining.h" #include "ktouchprefkeyboard.h" #include "ktouchprefcolors.h" #include "ktouchprefsound.h" #include "prefs.h" #include "ktouchcolorscheme.h" #include "ktouchutils.h" KTouch * KTouchPtr = NULL; KTouch::KTouch() : m_statusWidget(NULL), m_keyboardWidget(NULL), m_trainer(NULL) { setFocusPolicy(Qt::StrongFocus); setAttribute(Qt::WA_InputMethodEnabled, true); // setAttribute(Qt::WA_KeyCompression ); resetInputContext (); // Set global KTouchPtr to the main KTouch Object KTouchPtr = this; // General initialization of the program, common for all start modes init(); // *** Read and initialize user statistics *** // first clear statistics data (also make sure our mapping contains // the "default" user) clearStatistics(); KUrl stat_file = KGlobal::dirs()->findResource("data", "ktouch/statistics.xml"); // read previous stats from file KTouchStatisticsData::readUserStats(this, stat_file, m_userStats); // Setup our actions and connections setupActions(); // Init a training session initTrainingSession(); // Reload the last used training file. if (Prefs::currentLectureFile().isNull() || !m_lecture.loadXML(this, Prefs::currentLectureFile() )) { Prefs::setCurrentLectureFile(QString()); m_defaultLectureAction->setCurrentItem(-1); } else { updateFontFromLecture(); // adjust check marks in quick-select menus updateLectureActionCheck(); //kDebug() << "[KTouch::KTouch] lecture file = " << Prefs::currentLectureFile(); } statusBarLevel = new QLabel(this); statusBar()->addPermanentWidget(statusBarLevel); statusBarSession = new QLabel(this); statusBar()->addPermanentWidget(statusBarSession); setupGUI(); // Adjust check mark for the keyboard file updateKeyboardActionCheck(); // If the user doesn't want to restart with his old level, start from 0 (level 1) if (!Prefs::rememberLevel()) m_trainer->m_level = 0; else m_trainer->m_level = Prefs::currentTrainingLevel(); // now let's start the training in the current level m_trainer->startTraining(true); setFocus(); } // ---------------------------------------------------------------------------- // Free memory of objects that are not owned by the main KTouch object KTouch::~KTouch() { delete m_trainer; m_trainer = NULL; } // ---------------------------------------------------------------------------- KTouchLectureStats& KTouch::getCurrentLectureStats() { // kDebug() << "[KTouch::getCurrentLectureStats] "; KUrl lectureURL = Prefs::currentLectureFile(); if (lectureURL.url().isEmpty()) lectureURL = "default"; // kDebug() << " lectureURL = '" << lectureURL << "'"; KTouchLectureStats& stat = m_userStats[Prefs::currentUserName()].m_lectureStats[lectureURL]; // add additional info to the statistics stat.m_lectureURL = lectureURL; stat.m_lectureTitle = m_lecture.title(); return stat; } // ---------------------------------------------------------------------------- void KTouch::clearStatistics() { m_userStats.clear(); m_userStats[Prefs::currentUserName()].m_userName = i18n("Default User"); } // ---------------------------------------------------------------------------- // ******************** // *** Public slots *** // ******************** void KTouch::applyPreferences() { // This applies a new color scheme for the keyboard and also updates all other // changes for the keyboard widget changeColor(Prefs::currentColorScheme()); m_textLineWidget->applyPreferences(); m_statusWidget->applyPreferences(); } // ---------------------------------------------------------------------------- void KTouch::keyPressEvent(QKeyEvent *keyEvent) { if (keyEvent->text().isEmpty()) return; // if we the training session is paused, continue training now if (m_trainer->m_trainingPaused) { m_trainingPause->setEnabled(true); m_trainer->continueTraining(); } QChar key = keyEvent->text().at(0); // get first unicode character if (key.isPrint()) m_trainer->keyPressed(key); else if (key==QChar(8)) m_trainer->backspacePressed(); else if (key==QChar(13)) m_trainer->enterPressed(); else { keyEvent->ignore(); // unrecognised char -> don't accept it! Maybe the key is for somebody else? return; } keyEvent->accept(); } // ----------------------------------------------------------------------------- void KTouch::inputMethodEvent( QInputMethodEvent* m ){ m_trainer->keyPressed(m->commitString().at(0)); m->accept(); } // ----------------------------------------------------------------------------- // The action File->Open text... void KTouch::fileOpenText() { trainingPause(); KUrl tmp = KFileDialog::getOpenUrl(QString(), i18n("*.txt|Text files\n*.*|All files"), this, i18n("Select Practice Text") ); if (!tmp.isEmpty()) { // TODO : ask user for training options // create a default lecture KTouchLecture lec; // now read the file and replace the default mini level with the text in the file QString target; if (KIO::NetAccess::download(tmp, target, this)) { // Ok, that was successful, read the file into the first level of the lecture QFile infile(target); if ( !infile.open( QIODevice::ReadOnly ) ) { // FIXME : KIO::NetAccess::removeTempFile(target); return; } QTextStream in(&infile); // read text in stringlist int max_len = 0; int max_lines = 0; QString line = in.readLine(); QStringList lines; while (!line.isNull() && ++max_lines < 1000) { lines.append(line.trimmed()); max_len = qMax(max_len, line.length()); line = in.readLine(); } // store the lecture data lec.setTitle(i18n("Imported text from file '%1'", tmp.fileName())); KTouchLevelData dat(i18n("generated from text file"), i18n("all available")); dat.setLines(lines); lec.setLevel(0, dat); // first store training statistics m_trainer->storeTrainingStatistics(); Prefs::setCurrentLectureFile(tmp.url()); m_lecture = lec; updateFontFromLecture(); // adjust check marks in quick-select menus updateLectureActionCheck(); // restart training session from level 1 here... m_trainer->startTraining(false); m_trainingPause->setEnabled(true); } KIO::NetAccess::removeTempFile(target); } } // ---------------------------------------------------------------------------- // The action File->Open lecture... void KTouch::fileOpenLecture() { trainingPause(); KUrl tmp = KFileDialog::getOpenUrl(QString(), QString(), this, i18n("Select Training Lecture File") ); if (!tmp.isEmpty()) { // first store training statistics m_trainer->storeTrainingStatistics(); Prefs::setCurrentLectureFile(tmp.url()); m_lecture.loadXML(this, Prefs::currentLectureFile() ); updateFontFromLecture(); // adjust check marks in quick-select menus updateLectureActionCheck(); } // restart training session from level 1 here... m_trainer->startTraining(false); m_trainingPause->setEnabled(true); } // ---------------------------------------------------------------------------- // The action File->Edit lecture... void KTouch::fileEditLecture() { trainingPause(); m_trainer->storeTrainingStatistics(); // Create and execute editor KTouchLectureEditorDialog dlg(this); dlg.startEditor( Prefs::currentLectureFile() ); // Reload lecture in case it was modified m_lecture.loadXML(this, Prefs::currentLectureFile() ); updateFontFromLecture(); // adjust check marks in quick-select menus updateLectureActionCheck(); // restart training session here (keep level)... m_trainer->startTraining(true); m_trainingPause->setEnabled(true); } // ---------------------------------------------------------------------------- // The action File->Edit colors... void KTouch::fileEditColors() { trainingPause(); // Create a copy of the currently editable color schemes. QList tmp_list; int default_schemes = 0; for (QList::const_iterator it = KTouchColorScheme::m_colorSchemes.constBegin(); it != KTouchColorScheme::m_colorSchemes.constEnd(); ++it) { if (!it->m_default) tmp_list.append(*it); else ++default_schemes; } KTouchColorEditorDialog dlg(this); // Create editor // start editor int selected; dlg.startEditor( tmp_list, Prefs::currentColorScheme() - default_schemes, selected); KTouchColorScheme::createDefaults(); for (QList::const_iterator it = tmp_list.constBegin(); it != tmp_list.constEnd(); ++it) { KTouchColorScheme::m_colorSchemes.append(*it); } // update the quick select menu QStringList schemes_list; for (int i=0; isetItems(schemes_list); int index = selected + default_schemes; if (index >=0 && index < KTouchColorScheme::m_colorSchemes.count()) { Prefs::setCurrentColorScheme(index); } else { Prefs::setCurrentColorScheme(1); // fall back on default in case active was deleted } m_keyboardColorAction->setCurrentItem(Prefs::currentColorScheme()); applyPreferences(); } // ---------------------------------------------------------------------------- // The action File->Edit keyboard... void KTouch::fileEditKeyboard() { trainingPause(); // Create and execute editor KTouchKeyboardEditorDialog dlg(this); if (dlg.startEditor( Prefs::currentKeyboardFile() )) { // Reload keyboard in case it was modified m_keyboardWidget->applyPreferences(this, false); // adjust check marks in quick-select menus updateKeyboardActionCheck(); } } // ---------------------------------------------------------------------------- void KTouch::fileQuit() { qApp->quit(); } // ---------------------------------------------------------------------------- void KTouch::trainingNewSession() { trainingPause(); int result = KMessageBox::questionYesNoCancel(this, i18n("Would you like to keep the current level for the new training session?"), i18n("Start new training session"),KGuiItem(i18n("Keep current level")),KGuiItem(i18n("Start from first level"))); if (result == KMessageBox::Cancel) return; // store the statistics obtained so far in the trainer object m_trainer->storeTrainingStatistics(); // start new training session here m_trainer->startTraining(result == KMessageBox::Yes); m_trainingPause->setEnabled(true); } // ---------------------------------------------------------------------------- void KTouch::trainingPause() { m_trainingPause->setEnabled(false); m_trainer->pauseTraining(); } // ---------------------------------------------------------------------------- void KTouch::trainingStatistics() { trainingPause(); KTouchStatisticsDialog dlg(this); // TODO : this is somewhat messy: we have to get the words in the // current line (since they are not stored in the current // level and session stats, because the student may delete // the whole line again) and add them manually to copies // of the currents stats KTouchSessionStats kss = m_trainer->m_sessionStats; KTouchLevelStats kls = m_trainer->m_levelStats; kss.m_words += m_trainer->wordsInCurrentLine(); kls.m_words += m_trainer->wordsInCurrentLine(); // by calling getCurrentLectureStats we ensure that there is // data for the current lecture present for the dialog to function // properly getCurrentLectureStats(); dlg.run(Prefs::currentLectureFile(), m_userStats[Prefs::currentUserName()], kls, kss); } // ---------------------------------------------------------------------------- void KTouch::optionsPreferences() { trainingPause(); if ( KConfigDialog::showDialog( "settings" ) ) return; // KConfigDialog didn't find an instance of this dialog, so lets create it : KConfigDialog* dialog = new KConfigDialog(this, "settings", Prefs::self()); m_pageGeneral = new KTouchPrefGeneral(dialog); dialog->addPage(m_pageGeneral, i18n("General Options"), "configure-toolbars","",""); m_pageTraining = new KTouchPrefTraining(dialog); dialog->addPage(m_pageTraining, i18n("Training Options"), "chronometer"); m_pageKeyboard = new KTouchPrefKeyboard(dialog); dialog->addPage(m_pageKeyboard, i18n("Keyboard Settings"), "preferences-desktop-keyboard"); m_pageColors = new KTouchPrefColors(dialog); dialog->addPage(m_pageColors, i18n("Color Settings"), "preferences-desktop-color"); #ifdef KDEEDU_KTOUCH_BUILD_WITH_PHONON m_pageSound = new KTouchPrefSound(dialog); dialog->addPage(m_pageSound, i18n("Sound Settings"), "preferences-desktop-sound"); #endif // KDEEDU_KTOUCH_BUILD_WITH_PHONON connect(dialog, SIGNAL(settingsChanged(const QString &)), this, SLOT(applyPreferences())); dialog->show(); } // ---------------------------------------------------------------------------- void KTouch::optionsSetupUsers() { KTouchUserSetupDialog dlg(this); QStringList users = m_userStats.keys(); // call setup users dialog dlg.showDialog(users); // loop over all users and store only the statistics data already present in our // statistics map QMap new_stats; for (QStringList::const_iterator it = users.constBegin(); it != users.constEnd(); ++it) { new_stats[*it] = m_userStats[*it]; new_stats[*it].m_userName = *it; } m_userStats = new_stats; m_currentUserAction->setItems(m_userStats.keys()); updateCurrentUserActionCheck(); } // ---------------------------------------------------------------------------- void KTouch::changeStatusbarMessage(const QString& text) { statusBar()->showMessage(text); } // ---------------------------------------------------------------------------- void KTouch::changeStatusbarStats(unsigned int level_correct, unsigned int level_total, unsigned int level_words, unsigned int session_correct, unsigned int session_total, unsigned int session_words) { statusBarLevel->setText(i18n( "Level: Correct/Total chars: %1/%2 Words: %3", level_correct, level_total, level_words)); statusBarSession->setText(i18n( "Session: Correct/Total chars: %1/%2 Words: %3", session_correct, session_total, session_words)); } // ---------------------------------------------------------------------------- void KTouch::changeKeyboard(int num) { if (num > m_keyboardFiles.count()) return; if (num == m_keyboardFiles.count()) { // TODO : open dialog with user provided keyboard files return; } if (m_keyboardFiles[num] != Prefs::currentKeyboardFile()) { KMessageBox::information(this, i18n("Note that in different countries touch typing is taught slightly different which " "usually affects only the top row of keys. For instance, in the United States only the leftmost key and the key " "with the 1 are pressed by the little finger of the left hand. In Germany the little " "finger also presses the 2 key, and thus the fingers shift one key to the right on the top row.\n" "Normally this only makes a difference for split or ergonomic keyboards."), QString(), "KeyboardLayoutChangeInfo"); Prefs::setCurrentKeyboardFile( m_keyboardFiles[num] ); //kDebug() << "[KTouch::changeKeyboard] new keyboard layout = " << Prefs::currentKeyboardFile(); m_keyboardLayoutAction->setCurrentItem(num); // call Apply-Preferenzes in "noisy"-mode, pop up an error if the chosen layout file is corrupt m_keyboardWidget->applyPreferences(this, false); } } // ---------------------------------------------------------------------------- void KTouch::changeColor(int num) { if (num >= KTouchColorScheme::m_colorSchemes.count()) return; Prefs::setCurrentColorScheme(num); m_keyboardWidget->applyPreferences(this, false); m_textLineWidget->applyPreferences(); } // ---------------------------------------------------------------------------- void KTouch::changeLecture(int num) { if (num >= m_lectureFiles.count()) return; trainingPause(); KTouchLecture l; QString fileName = m_lectureFiles[num]; if (!l.loadXML(this, KUrl(fileName))) { KMessageBox::sorry(0, i18n("Could not find/open the lecture file '%1'.", fileName) ); m_defaultLectureAction->setCurrentItem(-1); } else { // store the statistics obtained so far in the trainer object m_trainer->storeTrainingStatistics(); // set new lecture as current Prefs::setCurrentLectureFile( fileName ); m_lecture = l; updateFontFromLecture(); m_defaultLectureAction->setCurrentItem(num); // now let's start the training in the first level of the training lecture m_trainer->startTraining(false); m_trainingPause->setEnabled(true); } } // ---------------------------------------------------------------------------- void KTouch::changeUser(int num) { if (num >= m_userStats.keys().count()) return; trainingPause(); m_trainer->storeTrainingStatistics(); QString new_name = m_userStats.keys()[num]; Prefs::setCurrentUserName(new_name); KMessageBox::information(this, i18n("Changing user to '%1'. Restarting training session at current level.", new_name) ); m_trainer->startTraining(true); } // ---------------------------------------------------------------------------- // ********************************* // *** Protected member function *** // ********************************* bool KTouch::queryExit() { // store config data Prefs::setCurrentTrainingLevel( m_trainer->m_level ); Prefs::self()->writeConfig(); // update and save statistics m_trainer->storeTrainingStatistics(); KUrl stat_file = KGlobal::dirs()->saveLocation("data","ktouch", true) + "statistics.xml"; // make sure all stats have the user names // for (QStringList::iterator it = m_userStats.keys().begin(); it != m_userStats.keys().end(); ++it) // m_userStats[*it].m_userName = *it; KTouchStatisticsData::writeUserStats(this, stat_file, m_userStats); //m_userStats[Prefs::currentUserName()].write(this, stat_file); KUrl color_file = KGlobal::dirs()->saveLocation("data","ktouch", true) + "color_schemes.xml"; KTouchColorScheme::writeList(this, color_file); return true; } // ---------------------------------------------------------------------------- void KTouch::resizeEvent(QResizeEvent * event) { changeStatusbarStats(m_trainer->m_levelStats.m_correctChars, m_trainer->m_levelStats.m_totalChars, m_trainer->m_levelStats.m_words, m_trainer->m_sessionStats.m_correctChars, m_trainer->m_sessionStats.m_totalChars, m_trainer->m_sessionStats.m_words); KXmlGuiWindow::resizeEvent(event); } // ---------------------------------------------------------------------------- // ******************************* // *** Private member function *** // ******************************* // Initialises the program during a normal startup void KTouch::init() { //kDebug() << "[KTouch::init] populating file lists..."; updateFileLists(); // create lists with default lecture/keyboard/examination files/colour scheme files //kDebug() << "[KTouch::init] " << m_lectureFiles.count() << " lectures available"; //kDebug() << "[KTouch::init] " << m_keyboardFiles.count() << " keyboard layouts available"; //kDebug() << "[KTouch::init] " << m_examinationFiles.count() << " examination files available"; if (Prefs::currentLectureFile() == "default") { Prefs::setCurrentLectureFile(QString()); // /// \todo look up a lecture in the language of the KDE locale /* QString default_lecture = "default"; if (m_lectureFiles.count() > 0) default_lecture = m_lectureFiles[0]; Prefs::setCurrentLectureFile( default_lecture ); */ } // if keyboard layout (loaded by Prefs is not available (e.g. the // layout file has been deleted) switch to default keyboard if (m_keyboardFiles.contains(Prefs::currentKeyboardFile() )==0) { QString default_keyboard; // determine locale QString lang = KGlobal::locale()->language(); QString fname = lang + ".keyboard"; // try to find keyboard with current locale QStringList::const_iterator it = m_keyboardFiles.constBegin(); while (it != m_keyboardFiles.constEnd() && (*it).indexOf(fname) == -1) ++it; if (it == m_keyboardFiles.constEnd()) { fname = lang.left(2) + ".keyboard"; // try to find more general version it = m_keyboardFiles.constBegin(); while (it != m_keyboardFiles.constEnd() && (*it).indexOf(fname) == -1) ++it; } if (it != m_keyboardFiles.constEnd()) default_keyboard = *it; else default_keyboard = "number.keyboard"; Prefs::setCurrentKeyboardFile ( default_keyboard ); } // create some default colour schemes KTouchColorScheme::createDefaults(); // read additional color schemes KUrl color_file = KGlobal::dirs()->findResource("data", "ktouch/color_schemes.xml"); KTouchColorScheme::readList(this, color_file); } // ---------------------------------------------------------------------------- // Creates the layout and GUI setup for a practice session void KTouch::initTrainingSession() { //kDebug() << "[KTouch::initTrainingSession] setting up layouts and widgets for new training session..."; // Build the training area. The status widget has a fixed vertical size, the slide line and the // keyboard grow according to their vertical stretch factors (see last argument in the constructors // of QSizePolicy) QWidget *main = new QWidget(this); QVBoxLayout *layout = new QVBoxLayout(main); m_statusWidget = new KTouchStatusWidget( main ); m_textLineWidget = new KTouchTextLineWidget( main ); QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::Expanding); sp.setVerticalStretch(1); sp.setHorizontalStretch(10); m_textLineWidget->setSizePolicy( sp ); m_keyboardWidget = new KTouchKeyboardWidget( main ); sp.setVerticalStretch(3); m_keyboardWidget->setSizePolicy( sp ); layout->addWidget(m_statusWidget); layout->addWidget(m_textLineWidget); layout->addWidget(m_keyboardWidget); // apply the settings to the widgets m_textLineWidget->applyPreferences(); m_keyboardWidget->applyPreferences(this, true); // set preferences silently here // create our trainer, the master object for the training stuff... if (m_trainer != NULL) delete m_trainer; m_trainer = new KTouchTrainer(m_statusWidget, m_textLineWidget, m_keyboardWidget, &m_lecture); setCentralWidget(main); } // ---------------------------------------------------------------------------- // Creates the (standard) actions and entries in the menu. void KTouch::setupActions() { // here we create actions for the menu and toolbar // the placement is defined in the ktouchui.rc file // *** File menu *** QAction *action; action = actionCollection()->addAction( "file_opentext" ); action->setText( i18n("&Open Plain Text File...") ); action->setIcon( KIcon("document-open") ); connect(action, SIGNAL(triggered(bool)), SLOT(fileOpenText())); action = actionCollection()->addAction( "file_openlecture" ); action->setText( i18n("&Open Lecture...") ); action->setIcon( KIcon("document-open") ); connect(action, SIGNAL(triggered(bool)), SLOT(fileOpenLecture())); action = actionCollection()->addAction( "file_editlecture" ); action->setText( i18n("&Edit Lecture...") ); action->setIcon( KIcon("document-properties") ); connect(action, SIGNAL(triggered(bool)), SLOT(fileEditLecture())); action = actionCollection()->addAction( "file_editcolors" ); action->setText( i18n("&Edit Color Scheme...") ); action->setIcon( KIcon("format-fill-color") ); connect(action, SIGNAL(triggered(bool)), SLOT(fileEditColors())); action = actionCollection()->addAction( "file_editkeyboard" ); action->setText( i18n("&Edit Keyboard Layout...") ); action->setIcon( KIcon("preferences-desktop-keyboard-layout") ); connect(action, SIGNAL(triggered(bool)), SLOT(fileEditKeyboard())); KStandardAction::quit(this, SLOT(fileQuit()), actionCollection()); // *** Training menu *** action = actionCollection()->addAction( "training_newsession" ); action->setText( i18n("&Start New Session") ); action->setIcon( KIcon("media-playback-start") ); connect(action, SIGNAL(triggered(bool)), SLOT(trainingNewSession())); m_trainingPause=actionCollection()->addAction( "training_pause" ); m_trainingPause->setText( i18n("&Pause Session") ); m_trainingPause->setIcon(KIcon("media-playback-pause") ); connect(m_trainingPause, SIGNAL(triggered(bool)), SLOT(trainingPause())); action = actionCollection()->addAction("training_stats" ); action->setText( i18n("&Lecture Statistics") ); action->setIcon( KIcon("view-statistics") ); connect(action, SIGNAL(triggered(bool)), SLOT(trainingStatistics())); // Setup menu entries for the training lectures m_defaultLectureAction = actionCollection()->add( "training_default_lectures" ); m_defaultLectureAction->setText( i18n("Default &Lectures") ); m_defaultLectureAction->setMenuAccelsEnabled(false); m_defaultLectureAction->setItems(m_lectureTitles); m_defaultLectureAction->setCurrentItem(0); connect (m_defaultLectureAction, SIGNAL(triggered(int)), this, SLOT(changeLecture(int))); // *** Options menu *** KStandardAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); // Setup menu entries for keyboard layouts m_keyboardLayoutAction= actionCollection()->add( "keyboard_layouts" ); m_keyboardLayoutAction->setText( i18n("&Keyboard Layouts") ); m_keyboardLayoutAction->setMenuAccelsEnabled(false); // TODO : add this back in when we have the KNewStuff feature implemented, were users // can anonymously upload their keyboards and lectures which will then be offered in // the diaolg that pops up for the "More keyboard layouts..." menu entry // m_keyboardTitles << i18n("More keyboard layouts..."); m_keyboardLayoutAction->setItems(m_keyboardTitles); connect (m_keyboardLayoutAction, SIGNAL(triggered(int)), this, SLOT(changeKeyboard(int))); // Setup menu entries for colour schemes m_keyboardColorAction = actionCollection()->add( "keyboard_schemes" ); m_keyboardColorAction->setText( i18n("Keyboards &Color Schemes") ); QStringList schemes_list; for (int i=0; isetMenuAccelsEnabled(false); m_keyboardColorAction->setItems(schemes_list); if (Prefs::currentColorScheme() >= schemes_list.count()) Prefs::setCurrentColorScheme(1); m_keyboardColorAction->setCurrentItem(Prefs::currentColorScheme()); connect (m_keyboardColorAction, SIGNAL(triggered(int)), this, SLOT(changeColor(int))); // *** User settings *** action = actionCollection()->addAction( "settings_setup_users" ); action->setText( i18n("&Setup Users...") ); action->setIcon( KIcon("system-users") ); connect(action, SIGNAL(triggered(bool)), SLOT(optionsSetupUsers())); m_currentUserAction = actionCollection()->add( "settings_current_user" ); m_currentUserAction->setText( i18n("&Current User") ); m_currentUserAction->setMenuAccelsEnabled(false); m_currentUserAction->setItems(m_userStats.keys()); updateCurrentUserActionCheck(); connect (m_currentUserAction, SIGNAL(triggered(int)), this, SLOT(changeUser(int))); } // ---------------------------------------------------------------------------- // This function updates the font used in the sliding line of a font suggestions was // made for the current lecture. void KTouch::updateFontFromLecture() { // if the lecture requires a font, try this if (!m_lecture.m_fontSuggestions.isEmpty()) { QFont f; // TODO : if multiple font suggestions are given, try one after another until a // suggested font is found if (f.fromString(m_lecture.m_fontSuggestions)) m_textLineWidget->setFont(f); else if (f.fromString("Monospace")) m_textLineWidget->setFont(f); } } // ---------------------------------------------------------------------------- // This function populates the file lists with the installed training, keyboard and // examination files. void KTouch::updateFileLists() { // first search for all installed new format keyboard files KStandardDirs *dirs = KGlobal::dirs(); m_keyboardFiles = dirs->findAllResources("data","ktouch/*.keyboard.xml"); // extract titles from keyboard files and store them in the // m_keyboardTitles string list m_keyboardTitles.clear(); kDebug() << "Keyboard files in XML format:"; for (QStringList::const_iterator cit = m_keyboardFiles.constBegin(); cit != m_keyboardFiles.constEnd(); ++cit) { KUrl url = (*cit); QString target; // try to read language code and keyboard name from file if (!KIO::NetAccess::download(url, target, this)) continue; // Ok, that was successful, store the lectureURL and read the file QFile infile(target); if ( !infile.open( QIODevice::ReadOnly ) ) continue; QDomDocument doc; doc.setContent( &infile ); QDomElement root = doc.documentElement(); if (root.isNull() || root.tagName() != "KTouchKeyboard") continue; // get the title QString title; QDomElement e = root.firstChildElement("Title"); if (!e.isNull()) title = i18nc("Keyboard Layout Name", e.firstChild().nodeValue().toUtf8()); else title = i18n("untitled keyboard layout"); QString langid; // retrieve the language id e = root.firstChildElement("Language"); if (!e.isNull()) langid = e.firstChild().nodeValue(); // compose title for main menu if (!langid.isEmpty()) title = QString("%1 (%2)").arg(title).arg(langid); m_keyboardTitles.append( title ); kDebug() << " " << m_keyboardTitles.back() << "\t [" << url << "]"; } // now sort the files and titles accordingly sort_lists(m_keyboardTitles, m_keyboardFiles); // and add the number keypad to the front // Now lets find the lecture files. // TODO : search in i18n() directories QStringList lectureFiles = dirs->findAllResources("data","ktouch/*.ktouch.xml"); // Now extract the titles of the lecture files and populate the string lists used in the program m_lectureFiles.clear(); m_lectureTitles.clear(); if (!lectureFiles.isEmpty()) { // extract the prefixes for (QStringList::iterator it=lectureFiles.begin(); it!=lectureFiles.end(); ++it) { KUrl url(KUrl::fromPath(*it)); KTouchLecture l; // only add lecture if we can actually load it if (l.loadXML(this, url)) { // since we could read the lecture, we remember the URL m_lectureFiles.push_back(*it); // store the title of the lecture if (l.title().isEmpty()) m_lectureTitles.push_back(i18n("untitled lecture") + " - (" + url.fileName() + ')'); else m_lectureTitles.push_back(l.title()); } } sort_lists(m_lectureTitles, m_lectureFiles); } // Now find predefined files with colour schemes QStringList colour_schemes = dirs->findAllResources("data","ktouch/*.colour_scheme"); // TODO : read in colour schemes and populate QValueList } // ---------------------------------------------------------------------------- void KTouch::updateLectureActionCheck() { int num = 0; QStringList::iterator it = m_lectureFiles.begin(); QString fname = Prefs::currentLectureFile(); while (it != m_lectureFiles.end() && !(*it).contains(fname)) { ++it; ++num; } if (it == m_lectureFiles.end()) m_defaultLectureAction->setCurrentItem(-1); else m_defaultLectureAction->setCurrentItem(num); } // ---------------------------------------------------------------------------- void KTouch::updateKeyboardActionCheck() { int num = 0; QStringList::iterator it = m_keyboardFiles.begin(); QString fname = Prefs::currentKeyboardFile(); while (it != m_keyboardFiles.end() && !(*it).contains(fname)) { ++it; ++num; } if (it == m_keyboardFiles.end()) m_keyboardLayoutAction->setCurrentItem(-1); else m_keyboardLayoutAction->setCurrentItem(num); } // ---------------------------------------------------------------------------- void KTouch::updateCurrentUserActionCheck() { QStringList user_list = m_userStats.keys(); int index = user_list.indexOf(Prefs::currentUserName()); if( index < 0) return; // if not found, fall back on Default User if (index == -1) { index = user_list.indexOf("Default User"); KMessageBox::information(this, i18n("Changing user to '%1'. Restarting training session at current level.", user_list[index]) ); m_trainer->startTraining(true); } Prefs::setCurrentUserName(user_list[index]); m_currentUserAction->setCurrentItem(index); } // ----------------------------------------------------------------------------