You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdeedu/ktouch/src/ktouch.cpp

879 lines
36 KiB

/***************************************************************************
* 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();
}
// ----------------------------------------------------------------------------
*/