diff options
Diffstat (limited to 'ktouch/src/ktouch.cpp')
-rw-r--r-- | ktouch/src/ktouch.cpp | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/ktouch/src/ktouch.cpp b/ktouch/src/ktouch.cpp new file mode 100644 index 00000000..231bc402 --- /dev/null +++ b/ktouch/src/ktouch.cpp @@ -0,0 +1,878 @@ +/*************************************************************************** + * 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" + +// Standard files +#include <algorithm> + +// QT Header +#include <qvbox.h> +#include <qsignalmapper.h> +#include <qcheckbox.h> +#include <qlabel.h> +#include <qgroupbox.h> +//#include <qimevent.h> + +// KDE Header +#include <klocale.h> +#include <kstatusbar.h> +#include <kfiledialog.h> +#include <kaction.h> +#include <kstandarddirs.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <kpopupmenu.h> +#include <kconfigdialog.h> +#include <kaction.h> +#include <kcombobox.h> +#include <kfontrequester.h> +#include <knuminput.h> + +// Own header files +#include "ktouchlecture.h" +#include "ktouchlectureeditor.h" +#include "ktouchstatus.h" +#include "ktouchslideline.h" +#include "ktouchkeyboardwidget.h" +#include "ktouchcoloreditor.h" +#include "ktouchtrainer.h" +#include "ktouchstatistics.h" +#include "ktouchprefgenerallayout.h" +#include "ktouchpreftraininglayout.h" +#include "ktouchprefkeyboardlayout.h" +#include "ktouchprefcolorslayout.h" +#include "ktouchutils.h" +#include "prefs.h" +#include "ktouchcolorscheme.h" + +KTouch * KTouchPtr = NULL; + +KTouch::KTouch() + : KMainWindow( 0, "KTouch" ), + m_statusWidget(NULL), + m_keyboardWidget(NULL), + m_trainer(NULL) +{ + setFocusPolicy(StrongFocus); + setInputMethodEnabled(true); + + // Set global KTouchPtr to the main KTouch Object + KTouchPtr = this; + // General initialization of the program, common for all start modes + init(); + // Setup our actions and connections + setupActions(); + // create the GUI reading the ui.rc file + if (!initialGeometrySet()) + resize( QSize(700, 510).expandedTo(minimumSizeHint())); + setupGUI(ToolBar | Keys | StatusBar | Create); + setAutoSaveSettings(); + // Read user statistics + KURL stat_file = KGlobal::dirs()->findResource("data", "ktouch/statistics.xml"); + //kdDebug() << "[KTouch::KTouch] readings statistics from file '" << stat_file << "'" << endl; + if (!m_stats.read(this, stat_file)) + m_stats.clear(); // if we can't read it, start with empty statistics + + // Init a training session + initTrainingSession(); + + // If session was restored, the function readProperties() was already called + if (kapp->isRestored()) { + kdDebug() << "[KTouch::KTouch] restoring session..." << endl; + /// \todo Rewrite all the session management stuff. + /// For now we just do the same as for the standard startup. + } +// else { + //kdDebug() << "[KTouch::KTouch] starting standard training..." << endl; + // A note about safety: In this function there are a lot of things that might go + // wrong. What happens if the training file can't be found? What if the + // file cannot be opened or is corrupt? Whatever happens, the function loadXML() + // ensures, that there is at least the default mini-level in the lecture + // so that the training won't crash. + + // Load statistics data from statistics-file + + // Reload the last used training file. + if (Prefs::currentLectureFile().isNull() || + !m_lecture.loadXML(this, Prefs::currentLectureFile() )) + { + Prefs::setCurrentLectureFile(QString::null); + m_defaultLectureAction->setCurrentItem(-1); + } + else { + updateFontFromLecture(); + // adjust check marks in quick-select menus + updateLectureActionCheck(); + //kdDebug() << "[KTouch::KTouch] lecture file = " << Prefs::currentLectureFile() << endl; + } + + // 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); +// } +} +// ---------------------------------------------------------------------------- + +// Free memory of objects that are not owned by the main KTouch object +KTouch::~KTouch() { + delete m_trainer; + m_trainer = NULL; +} +// ---------------------------------------------------------------------------- + +KTouchLectureStats& KTouch::getCurrentLectureStats() { +// kdDebug() << "[KTouch::getCurrentLectureStats] " << endl; + KURL lectureURL = Prefs::currentLectureFile(); + if (lectureURL.url().isEmpty()) lectureURL = "default"; +// kdDebug() << " lectureURL = '" << lectureURL << "'" << endl; + KTouchLectureStats& stat = m_stats.m_lectureStats[lectureURL]; + // add additional info to the statistics + if (stat.m_lectureURL.isEmpty()) + stat.m_lectureURL = lectureURL; + if (stat.m_lectureTitle.isEmpty()) + stat.m_lectureTitle = m_lecture.m_title; + return stat; +} +// ---------------------------------------------------------------------------- + +void KTouch::clearStatistics() { + m_stats.clear(); +} +// ---------------------------------------------------------------------------- + +// ******************** +// *** 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_slideLineWidget->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(); + } + if (keyEvent->text().length() > 1) { + kdDebug() << "[KTouch::keyPressEvent] text = '" << keyEvent->text() << "'" << endl; + } + QChar key = keyEvent->text().at(0); // get first unicode character + // HACK : manually filter out known dead keys +// bool has_dead_key = true; + switch (key.unicode()) { + case 94 : m_lastDeadKey = QChar(uint(94)); break; + case 176 : m_lastDeadKey = QChar(uint(176)); break; + case 180 : m_lastDeadKey = QChar(uint(180)); break; + case 96 : m_lastDeadKey = QChar(uint(96)); break; + case 126 : m_lastDeadKey = QChar(uint(126)); break; + default : m_lastDeadKey = QChar(uint(0)); + } + if (m_lastDeadKey != QChar(uint(0)) && key == m_lastDeadKey) { +// kdDebug() << "Got dead key = " << m_lastDeadKey << endl; + //keyEvent->accept(); +// return; + } + + if (key.isPrint()) + m_trainer->keyPressed(key); + else if (key==QChar(8)) + m_trainer->backspacePressed(); + else if (key==QChar(13)) + m_trainer->enterPressed(); + else + return; // unrecognised char -> don't accept it! Maybe the key is for somebody else? + keyEvent->accept(); +} +// ---------------------------------------------------------------------------- + + +void KTouch::imEndEvent ( QIMEvent * e ){ + m_trainer->keyPressed(e->text().at(0)); + e->accept(); +} + + +void KTouch::configOverrideLectureFontToggled(bool on) { + if (on) { + m_pageGeneral->fontTextLabel->setEnabled(true); + m_pageGeneral->kcfg_Font->setEnabled(true); + } + else { + m_pageGeneral->fontTextLabel->setEnabled(false); + m_pageGeneral->kcfg_Font->setEnabled(false); + } +} +// ---------------------------------------------------------------------------- + +void KTouch::configOverrideKeyboardFontToggled(bool on) { + if (on) { + m_pageKeyboard->textLabel1->setEnabled(true); + m_pageKeyboard->kcfg_KeyboardFont->setEnabled(true); + } + else { + m_pageKeyboard->textLabel1->setEnabled(false); + m_pageKeyboard->kcfg_KeyboardFont->setEnabled(false); + } +} +// ---------------------------------------------------------------------------- + +void KTouch::configAutoLevelChangeToggled(bool on) { + if (on) { + m_pageTraining->l1->setEnabled(true); + m_pageTraining->l2->setEnabled(true); + m_pageTraining->l3->setEnabled(true); + m_pageTraining->l4->setEnabled(true); + m_pageTraining->l5->setEnabled(true); + m_pageTraining->l6->setEnabled(true); + m_pageTraining->l7->setEnabled(true); + m_pageTraining->l8->setEnabled(true); + m_pageTraining->l9->setEnabled(true); + m_pageTraining->l10->setEnabled(true); + m_pageTraining->kcfg_UpSpeedLimit->setEnabled(true); + m_pageTraining->kcfg_UpCorrectLimit->setEnabled(true); + m_pageTraining->kcfg_DownSpeedLimit->setEnabled(true); + m_pageTraining->kcfg_DownCorrectLimit->setEnabled(true); + m_pageTraining->kcfg_DisableManualLevelChange->setEnabled(true); + } + else { + m_pageTraining->l1->setEnabled(false); + m_pageTraining->l2->setEnabled(false); + m_pageTraining->l3->setEnabled(false); + m_pageTraining->l4->setEnabled(false); + m_pageTraining->l5->setEnabled(false); + m_pageTraining->l6->setEnabled(false); + m_pageTraining->l7->setEnabled(false); + m_pageTraining->l8->setEnabled(false); + m_pageTraining->l9->setEnabled(false); + m_pageTraining->l10->setEnabled(false); + m_pageTraining->kcfg_UpSpeedLimit->setEnabled(false); + m_pageTraining->kcfg_UpCorrectLimit->setEnabled(false); + m_pageTraining->kcfg_DownSpeedLimit->setEnabled(false); + m_pageTraining->kcfg_DownCorrectLimit->setEnabled(false); + m_pageTraining->kcfg_DisableManualLevelChange->setEnabled(false); + } +} +// ---------------------------------------------------------------------------- + +void KTouch::configCommonColorsToggled(bool on) { + m_pageColors->colorsGroup->setEnabled(on); +} +// ---------------------------------------------------------------------------- + +// The action File->Open lecture... +void KTouch::fileOpenLecture() { + trainingPause(); + KURL tmp = KFileDialog::getOpenURL(QString::null, QString::null, 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 + KTouchLectureEditor 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. + QValueList<KTouchColorScheme> tmp_list; + int default_schemes = 0; + for (QValueVector<KTouchColorScheme>::const_iterator it = KTouchColorScheme::m_colorSchemes.constBegin(); + it != KTouchColorScheme::m_colorSchemes.constEnd(); ++it) + { + if (!it->m_default) tmp_list.append(*it); + else ++default_schemes; + } + + KTouchColorEditor dlg(this); // Create editor + // start editor + int selected; + dlg.startEditor( tmp_list, Prefs::currentColorScheme() - default_schemes, selected); + KTouchColorScheme::createDefaults(); + for (QValueList<KTouchColorScheme>::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 (unsigned int i=0; i<KTouchColorScheme::m_colorSchemes.count(); ++i) + schemes_list.append(KTouchColorScheme::m_colorSchemes[i].m_name); + m_keyboardColorAction->setItems(schemes_list); + int index = selected + default_schemes; + if (index >=0 && index < static_cast<int>(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 +// KTouchKeyboardEditor dlg(this); +// dlg.startEditor( Prefs::currentKeyboardFile() ); + // Reload lecture in case it was modified + //m_keyboard.loadXML(this, Prefs::currentKeyboardFile() ); + //updateFontFromLecture(); + // adjust check marks in quick-select menus + //updateKeyboardActionCheck(); +} +// ---------------------------------------------------------------------------- + +void KTouch::fileQuit() { + kapp->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"),i18n("Keep Current Level"),i18n("Do Not Keep")); + 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(); + KTouchStatistics 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_stats, 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 KTouchPrefGeneralLayout(0, "General"); + dialog->addPage(m_pageGeneral, i18n("General Options"), "style"); + m_pageTraining = new KTouchPrefTrainingLayout(0, "Training"); + dialog->addPage(m_pageTraining, i18n("Training Options"), "kalarm"); + m_pageKeyboard = new KTouchPrefKeyboardLayout(0, "Keyboard"); + dialog->addPage(m_pageKeyboard, i18n("Keyboard Settings"), "keyboard_layout"); + m_pageColors = new KTouchPrefColorsLayout(0, "Colors"); + dialog->addPage(m_pageColors, i18n("Color Settings"), "package_graphics"); + connect(dialog, SIGNAL(settingsChanged()), this, SLOT(applyPreferences())); + // TODO : Connect some other buttons/check boxes of the dialog + connect(m_pageGeneral->kcfg_OverrideLectureFont, SIGNAL(toggled(bool)), + this, SLOT(configOverrideLectureFontToggled(bool))); + connect(m_pageKeyboard->kcfg_OverrideKeyboardFont, SIGNAL(toggled(bool)), + this, SLOT(configOverrideKeyboardFontToggled(bool))); + connect(m_pageTraining->kcfg_AutoLevelChange, SIGNAL(toggled(bool)), + this, SLOT(configAutoLevelChangeToggled(bool))); + connect(m_pageColors->kcfg_CommonTypingLineColors, SIGNAL(toggled(bool)), + this, SLOT(configCommonColorsToggled(bool))); + // call the functions to enable/disable controls depending on settings + configOverrideLectureFontToggled(Prefs::overrideLectureFont()); + configOverrideKeyboardFontToggled(Prefs::overrideKeyboardFont()); + configAutoLevelChangeToggled(Prefs::autoLevelChange()); + configCommonColorsToggled(Prefs::commonTypingLineColors()); + dialog->show(); +} +// ---------------------------------------------------------------------------- + +void KTouch::changeStatusbarMessage(const QString& text) { + statusBar()->message(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) +{ + statusBar()->changeItem(i18n( "Level: Correct/Total chars: %1/%2 Words: %3") + .arg(level_correct).arg(level_total).arg(level_words), 1); + statusBar()->changeItem(i18n( "Session: Correct/Total chars: %1/%2 Words: %3") + .arg(session_correct).arg(session_total).arg(session_words), 2); +} +// ---------------------------------------------------------------------------- + +void KTouch::changeKeyboard(int num) { + if (static_cast<unsigned int>(num)>=m_keyboardFiles.count()) return; + Prefs::setCurrentKeyboardFile( m_keyboardFiles[num] ); +// kdDebug() << "[KTouch::changeKeyboard] new keyboard layout = " << Prefs::currentKeyboardFile() << endl; + 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 (static_cast<unsigned int>(num)>=KTouchColorScheme::m_colorSchemes.count()) return; + Prefs::setCurrentColorScheme(num); + m_keyboardWidget->applyPreferences(this, false); + m_slideLineWidget->applyPreferences(); +} +// ---------------------------------------------------------------------------- + +void KTouch::changeLecture(int num) { + if (static_cast<unsigned int>(num)>=m_lectureFiles.count()) return; + trainingPause(); + KTouchLecture l; + QString fileName = m_lectureFiles[num]; + if (!l.loadXML(this, KURL::fromPathOrURL(fileName))) { + KMessageBox::sorry(0, i18n("Could not find/open the lecture file '%1'.").arg(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); + } +} +// ---------------------------------------------------------------------------- + + +// ********************************* +// *** Protected member function *** +// ********************************* + +bool KTouch::queryExit() { + // store config data + Prefs::setCurrentTrainingLevel( m_trainer->m_level ); + Prefs::writeConfig(); + // update and save statistics + m_trainer->storeTrainingStatistics(); + KURL stat_file = KGlobal::dirs()->saveLocation("data","ktouch", true) + "statistics.xml"; + //kdDebug() << "[KTouch::queryExit] Writing statistics to file: '" << stat_file << "'" << endl; + m_stats.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); + KMainWindow::resizeEvent(event); +} +// ---------------------------------------------------------------------------- + + +// ******************************* +// *** Private member function *** +// ******************************* + +// Will be called when this app is restored due to session management. +// This function only stored the temperary data of the last session. All permanent +// settings should be handled by the KTouchConfiguration object. +void KTouch::readProperties(KConfig *config) { + kdDebug() << "[KTouch::readProperties] Reading session data..." << endl; + // TODO : Session management rewrite + config->setGroup("TrainingState"); + +/* + // The application is about to be restored due to session management. + // Let's read all the stuff that was set when the application was terminated (during KDE logout). + QString session = config->readEntry("Session"); + if (!session.isEmpty()) + m_trainer->m_session = KTouchTrainingSession(session); + m_trainer->m_level = config->readNumEntry("Level", 0); + m_trainer->m_line = config->readNumEntry("Line", 0); + m_currentLectureFile = config->readPathEntry("Lecture"); + m_trainer->readSessionHistory(); // read session history (excluding currently active session) + // update the trainer object + m_trainer->m_teacherText = m_lecture.level(m_trainer->m_level).line(m_trainer->m_line); + m_trainer->m_studentText = config->readEntry("StudentText"); + m_trainer->continueTraining(); + changeStatusbarMessage( i18n("Restarting training session: Waiting for first keypress...") ); + // update the slide line widget + m_slideLineWidget->setNewText(m_trainer->m_teacherText, m_trainer->m_studentText); + // update all the other widgets + m_trainer->updateWidgets(); + // Read training state + config->setGroup("TrainingState"); + m_currentLectureURL = config->readPathEntry("LectureURL"); + m_trainer->m_level = config->readNumEntry("Level", 0); +*/ +} +// ---------------------------------------------------------------------------- + +// Will be called when the app should save its state for session management purposes. +void KTouch::saveProperties(KConfig *config) { + kdDebug() << "[KTouch::saveProperties] Saving session data..." << endl; + // We are going down because of session management (most likely because of + // KDE logout). Let's save the current status so that we can restore it + // next logon. + + // TODO : Session management rewrite +/* + config->setGroup("TrainingState"); + // first write the current lecture URL and the training position + config->writePathEntry("Lecture", m_currentLectureURL.url()); + config->writeEntry("Level", m_trainer->m_level); + config->writeEntry("Line", m_trainer->m_line); + config->writeEntry("StudentText", m_trainer->m_studentText); + config->writeEntry("Session", m_trainer->m_session.asString() ); + // store the session history so far + m_trainer->writeSessionHistory(); + + config->setGroup("TrainingState"); + config->writePathEntry("LectureURL", m_currentLectureURL.url()); + config->writeEntry("Level", m_trainer->m_level); + // during normal shutdown we finish the session and add it to the session history + m_trainer->m_sessionHistory.append( m_trainer->m_session ); + m_trainer->writeSessionHistory(); +*/ +} +// ---------------------------------------------------------------------------- + +// Initialises the program during a normal startup +void KTouch::init() { + //kdDebug() << "[KTouch::init] populating file lists..." << endl; + updateFileLists(); // create lists with default lecture/keyboard/examination files/colour scheme files + //kdDebug() << "[KTouch::init] " << m_lectureFiles.count() << " lectures available" << endl; + //kdDebug() << "[KTouch::init] " << m_keyboardFiles.count() << " keyboard layouts available" << endl; + //kdDebug() << "[KTouch::init] " << m_examinationFiles.count() << " examination files available" << endl; + + if (Prefs::currentLectureFile() == "default") { + Prefs::setCurrentLectureFile(QString::null); +// /// \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).find(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).find(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() { + //kdDebug() << "[KTouch::initTrainingSession] setting up layouts and widgets for new training session..." << endl; + // 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) + QVBox * mainLayout = new QVBox( this ); + m_statusWidget = new KTouchStatus( mainLayout ); + m_slideLineWidget = new KTouchSlideLine( mainLayout ); + m_slideLineWidget->setSizePolicy( QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding, 0, 1) ); + m_keyboardWidget = new KTouchKeyboardWidget( mainLayout ); + m_keyboardWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding, 0, 3) ); + setCentralWidget(mainLayout); + // apply the settings to the widgets + m_slideLineWidget->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_slideLineWidget, m_keyboardWidget, &m_lecture); + + // Setup status bar + statusBar()->show(); + statusBar()->insertItem("Level", 1, 0, true); + statusBar()->insertItem("Session", 2, 0, true); +} +// ---------------------------------------------------------------------------- + +// Creates the (standard) actions and entries in the menu. +void KTouch::setupActions() { + // *** File menu *** + new KAction(i18n("&Open lecture..."), "open_lecture", 0, + this, SLOT(fileOpenLecture()), actionCollection(), "file_openlecture"); + new KAction(i18n("&Edit lecture..."), "edit_lecture", 0, + this, SLOT(fileEditLecture()), actionCollection(), "file_editlecture"); + new KAction(i18n("&Edit color scheme..."), "edit_colors", 0, + this, SLOT(fileEditColors()), actionCollection(), "file_editcolors"); +// new KAction(i18n("&Edit Keyboard..."), "edit_keyboard", 0, +// this, SLOT(fileEditKeyboard()), actionCollection(), "file_editkeyboard"); + KStdAction::quit(this, SLOT(fileQuit()), actionCollection()); + + // *** Training menu *** + new KAction(i18n("&Start New Session"), "launch", 0, + this, SLOT(trainingNewSession()), actionCollection(), "training_newsession"); + m_trainingPause = new KAction(i18n("&Pause Session"), "player_pause", 0, + this, SLOT(trainingPause()), actionCollection(), "training_pause"); + new KAction(i18n("&Lecture Statistics"), "kalarm", 0, + this, SLOT(trainingStatistics()), actionCollection(), "training_stats"); + + // Setup menu entries for the training lectures + m_defaultLectureAction = new KSelectAction(i18n("Default &Lectures"), 0, this, 0, actionCollection(), "default_lectures"); + m_defaultLectureAction->setMenuAccelsEnabled(false); + m_defaultLectureAction->setItems(m_lectureTitles); + m_defaultLectureAction->setCurrentItem(0); + connect (m_defaultLectureAction, SIGNAL(activated(int)), this, SLOT(changeLecture(int))); + + // *** Settings menu *** + KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection()); + // Setup menu entries for keyboard layouts + m_keyboardLayoutAction= new KSelectAction(i18n("&Keyboard Layouts"), 0, this, 0, actionCollection(), "keyboard_layouts"); + m_keyboardLayoutAction->setMenuAccelsEnabled(false); + m_keyboardLayoutAction->setItems(m_keyboardTitles); + connect (m_keyboardLayoutAction, SIGNAL(activated(int)), this, SLOT(changeKeyboard(int))); + + // Setup menu entries for colour schemes + m_keyboardColorAction = new KSelectAction(i18n("&Color Schemes"), 0, this, 0, actionCollection(), "keyboard_schemes"); + QStringList schemes_list; + for (unsigned int i=0; i<KTouchColorScheme::m_colorSchemes.count(); ++i) + schemes_list.append(KTouchColorScheme::m_colorSchemes[i].m_name); + m_keyboardColorAction->setMenuAccelsEnabled(false); + m_keyboardColorAction->setItems(schemes_list); + if (static_cast<unsigned int>(Prefs::currentColorScheme()) >= schemes_list.count()) + Prefs::setCurrentColorScheme(1); + m_keyboardColorAction->setCurrentItem(Prefs::currentColorScheme()); + connect (m_keyboardColorAction, SIGNAL(activated(int)), this, SLOT(changeColor(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_slideLineWidget->setFont(f); + else if (f.fromString("Monospace")) m_slideLineWidget->setFont(f); + } +} +// ---------------------------------------------------------------------------- + +// This function populates the file lists with the installed training, keyboard and +// examination files. +void KTouch::updateFileLists() { + KStandardDirs *dirs = KGlobal::dirs(); + + // first search for all installed keyboard files + // TODO : search in i18n() directories + m_keyboardFiles = dirs->findAllResources("data","ktouch/*.keyboard"); + + // remove the number layout, since this is the necessary default layout and will be + // added anyway + QStringList::iterator it = m_keyboardFiles.find("number.keyboard"); + if (it!=m_keyboardFiles.end()) m_keyboardFiles.remove(it); + + m_keyboardTitles.clear(); + for (QStringList::const_iterator cit = m_keyboardFiles.constBegin(); + cit != m_keyboardFiles.constEnd(); ++cit) + { + // extract titles from keyboard files and store them in the + // m_keyboardTitles string list + + // get the filename alone + QString fname = KURL(*cit).fileName(); + // get the filename without the .keyboard + fname.truncate(fname.length() - 9); + // get everything in front of the first . + QString lang_iso = fname.section('.',0,0); + // get language description of file names + QString lang_name = KGlobal::locale()->twoAlphaToLanguageName(lang_iso); +// kdDebug() << fname << " | " << lang_iso << " | " << lang_name << endl; + if (lang_name.isEmpty()) + lang_name = KGlobal::locale()->twoAlphaToCountryName(lang_iso); + if (!lang_name.isEmpty()) + lang_name += " (" + fname + ")"; + else + lang_name = fname; + m_keyboardTitles.append( lang_name ); +// kdDebug() << m_keyboardTitles.back() << endl; + } + + // now sort the files and titles accordingly + sort_lists(m_keyboardTitles, m_keyboardFiles); + // and add the number keypad to the front + m_keyboardFiles.push_front("number.keyboard"); + m_keyboardTitles.push_front(i18n("Keypad/Number block")); + + // 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(*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.m_title.isEmpty()) + m_lectureTitles.push_back(i18n("untitled lecture") + " - (" + url.fileName() + ")"); + else + m_lectureTitles.push_back(l.m_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<KTouchColorScheme> +} +// ---------------------------------------------------------------------------- + + +void KTouch::updateLectureActionCheck() { + int num = 0; + QStringList::iterator it = m_lectureFiles.begin(); + QString fname = Prefs::currentLectureFile(); + while (it != m_lectureFiles.end() && (*it).find(fname) == -1) { + ++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).find(fname) == -1) { + ++it; + ++num; + } + if (it == m_keyboardFiles.end()) m_keyboardLayoutAction->setCurrentItem(-1); + else m_keyboardLayoutAction->setCurrentItem(num); +} +// ---------------------------------------------------------------------------- + +/* +void KTouch::imStartEvent(QIMEvent *e) { + kdDebug() << "[KTouch::imStartEvent] text = '" << e->text() << "'" << endl; + e->accept(); +} +// ---------------------------------------------------------------------------- + +void KTouch::imComposeEvent(QIMEvent *e) { + kdDebug() << "[KTouch::imComposeEvent] text = '" << e->text() << "'" << endl; + e->accept(); +} +// ---------------------------------------------------------------------------- + +void KTouch::imEndEvent(QIMEvent *e) { + kdDebug() << "[KTouch::imEndEvent] text = '" << e->text() << "'" << endl; + if (!e->text().isEmpty()) { + if (e->text() == "^") { + QKeyEvent *ev = new QKeyEvent (QEvent::KeyPress, + Qt::Key_AsciiCircum, '^', 0, + QString("^")); + keyPressEvent(ev); + delete ev; + } + } + e->accept(); +} +// ---------------------------------------------------------------------------- +*/ |