summaryrefslogtreecommitdiffstats
path: root/ktouch/src/ktouch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ktouch/src/ktouch.cpp')
-rw-r--r--ktouch/src/ktouch.cpp878
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();
+}
+// ----------------------------------------------------------------------------
+*/