pax_global_header00006660000000000000000000000064117376201260014517gustar00rootroot0000000000000052 comment=511dfa22d9be650d853be5954a1d0ed6f112686f nlkt-0.3.2.2/000077500000000000000000000000001173762012600126315ustar00rootroot00000000000000nlkt-0.3.2.2/README000066400000000000000000000047441173762012600135220ustar00rootroot00000000000000This README describes some notes about nlkt. --------------------------- 1. Compiling and installing --------------------------- Before compiling package from sources, check downloads page on sourceforge.net [1] for available packages for your operating system. nlkt depends on: - Qt4 library, [2]; - Qwt6 library, [3]. So, you must have installed development versions of these libraries. If you have not debian-derived OS, then go to src/nlkt.pro file and replace "/usr/include/qwt-qt4" and "-lqwt-qt4" with appropriate qwt includes path and qwt library name in your OS. If you want "install" nlkt only for one user (for you :)), then simply run ./build-local.sh If you want to install nlkt system-wide, run: cd src && qmake && lrelease nlkt.pro && make PATH_CFG=-DNLKT_USE_SYSTEM_PATH release && rm Makefile* && cd ../ cd src && qmake && sudo make INSTALL_ROOT=/ release-install && cd ../ If you has built native package for your system, please write me: [4]. I want to provide as more packages as possible. -------------------- 2. Using the program -------------------- To enable typing in some language, check that fortunes for that language is installed. For example, if you using debian-based system and want to install fortunes for russian language, you have to install fortunes-ru package: aptitude install fortunes-ru Now program has layout files (read "supports") for english, german and russian. If you to add your mother language, just simply write keyboard layout file (see /share/layouts/en for example) and send it to me [4], i will add support for this language in next version. Looking for keyboard hotkeys? Pick mouse cursor for some button and wait for tooltip. If the button has a hotkey, you will see it. --------- 3. Thanks --------- Sergey V. Klimenko aka ReSeT - co-idea Artem V. Koval' aka TurboNOMAD - moral help wfrr (linux.org.ru) - criticism, suggests nickless (forum.vingrad.ru) - criticism, suggests Messing (linux.org.ru) - criticism, suggests alexsaa (linux.org.ru) - criticism, suggests, bugreports adarovsky (linux.org.ru) - criticism, suggests GrayCardinal (forum.vingrad.ru) - criticism Enrico Zini (debian.org) - British layout, bugreports --------------------------------------------------- This project is devoted to my sister Darja Karpova. --------------------------------------------------- --- Links: [1] http://sourceforge.net/project/showfiles.php?group_id=218218 [2] http://trolltech.com/products/qt [3] http://qwt.sourceforge.net/ [4] jackyf.devel@gmail.com nlkt-0.3.2.2/build-local.sh000077500000000000000000000001171173762012600153560ustar00rootroot00000000000000#!/bin/sh cd src && lrelease nlkt.pro && qmake-qt4 && make release && cd ../ nlkt-0.3.2.2/share/000077500000000000000000000000001173762012600137335ustar00rootroot00000000000000nlkt-0.3.2.2/share/default_profiles/000077500000000000000000000000001173762012600172625ustar00rootroot00000000000000nlkt-0.3.2.2/share/default_profiles/de000066400000000000000000000000041173762012600175670ustar00rootroot00000000000000pro nlkt-0.3.2.2/share/default_profiles/en000066400000000000000000000000041173762012600176010ustar00rootroot00000000000000pro nlkt-0.3.2.2/share/default_profiles/en-dvorak000066400000000000000000000000041173762012600210650ustar00rootroot00000000000000pro nlkt-0.3.2.2/share/default_profiles/en-gb000066400000000000000000000000041173762012600201670ustar00rootroot00000000000000pro nlkt-0.3.2.2/share/default_profiles/ru000066400000000000000000000000071173762012600176300ustar00rootroot00000000000000про nlkt-0.3.2.2/share/images/000077500000000000000000000000001173762012600152005ustar00rootroot00000000000000nlkt-0.3.2.2/share/images/keyboard.png000066400000000000000000000071671173762012600175210ustar00rootroot00000000000000PNG  IHDR_%" MiCCPPhotoshop ICC profilexڝSwX>eVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/%ҟ3bKGD pHYs  tIME!74IDATxۻN2QaxT/wa,is`Xyj'`d::::5^uJgM6mڴ'Qnw Sp:/%q18v枏C<톻ۜ~':::::::::::EfxuDݷ6mڴiOL:::Xޒσ6mrձеO=K^Jc:o5m;_sG!snUPGPGPGPGPGPGPGPGPGPGPGPGPGPGPGPG@@@@@@@@@@@`"3"xq6mڴ3*###lmiӦM/wZ ]kd:=VƱ5|TLb? {':::::::::::EfnmG}#5mڴi#&*###8|8ʹiF_ZsN=d:=VƱ5|TLb? ԫIENDB`nlkt-0.3.2.2/share/layouts/000077500000000000000000000000001173762012600154335ustar00rootroot00000000000000nlkt-0.3.2.2/share/layouts/de000066400000000000000000000001631173762012600157460ustar00rootroot00000000000000^1234567890ß'< °!"§$%&/()=?`> qwertzuiopü+ QWERTZUIOPÜ* asdfghjklöä ASDFGHJKLÖÄ yxcvbnm,.- YXCVBNM;:_ de nlkt-0.3.2.2/share/layouts/en000066400000000000000000000001501173762012600157540ustar00rootroot00000000000000`1234567890-=\ ~!@#$%^&*()_+| qwertyuiop[] QWERTYUIOP{} asdfghjkl;' ASDFGHJKL:" zxcvbnm,./ ZXCVBNM<>? nlkt-0.3.2.2/share/layouts/en-dvorak000066400000000000000000000001501173762012600172400ustar00rootroot00000000000000`1234567890[]\ ~!@#$%^&*(){}| ',.pyfgcrl/= "<>PYFGCRL?+ aoeuidhtns- AOEUIDHTNS_ ;qjkxbmwvz :QJKXBMWVZ nlkt-0.3.2.2/share/layouts/en-gb000066400000000000000000000001541173762012600163460ustar00rootroot00000000000000`1234567890-=\ ¬!"£$%^&*()_+| qwertyuiop[] QWERTYUIOP{} asdfghjkl;'# ASDFGHJKL:@~ zxcvbnm,./ ZXCVBNM<>? nlkt-0.3.2.2/share/layouts/ru000066400000000000000000000002561173762012600160070ustar00rootroot00000000000000ё1234567890-=\ Ё!"№;%:?*()_+/ йцукенгшщзхъ ЙЦУКЕНГШЩЗХЪ фывапролджэ ФЫВАПРОЛДЖЭ ячсмитьбю. ЯЧСМИТЬБЮ, ru nlkt-0.3.2.2/share/translations/000077500000000000000000000000001173762012600164545ustar00rootroot00000000000000nlkt-0.3.2.2/share/translations/nlkt_ru.ts000066400000000000000000000453461173762012600205160ustar00rootroot00000000000000 MainWidget Time, sec: Время, сек: Mistakes: Ошибок: of из Speed, symb./sec.: Скорость, симв./сек.: &Start &Начать S&top &Закончить St&ats &Статистика &Quit В&ыход Too many mistakes Слишком много ошибок Too many mistakes in current exercise. Exercise stopped. Слишком много ошибок допущено в текущем упражнении. Упражнение прервано. Your results Ваши результаты Letters count Символов набрано Mistakes Ошибок Time spent (min:sec,millisec) Времени потрачено (мин:сек,миллисек) Average speed, symbols per minute Средняя скорость, символов в минуту Exercise has been successfully finished! Упражнение закончено успешно! Start Начать Stop Закончить Stats Статистика Quit Выход Rhythm Ритм Get relax... Отдохните... ProfileManager Select Выбрать Cancel Отмена Delete Удалить Rename Переименовать Enter name of new profile: Введите имя нового профиля: Select the layout: Выберите раскладку: Existing profile Существующий профиль New profile Новый профиль Select the profile Выберите профиль Cannot use this profile name Не могу использовать этот профиль The profile with name '%1' already exists. Этот профиль по имени '%1' уже существует. Delete profile? Удалить профиль? Do you really want to delete the profile '%1' Вы действительно хотите удалить профиль '%1' Unable to delete the profile Не могу удалить профиль Somewhy cannot delete the profile '%1' :( Почему-то не могу удалить профиль '%1' :( Renaming profile Переименование профиля Enter the new profile for profile '%1' Введите новое имя для профиля '%1' Unable to rename the profile Не могу переименовать профиль Somewhy cannot rename the profile '%1' :( Почему-то не могу переименовать профиль '%1' :( Do you really want to delete the profile '%1'? Вы действительно хотите удалить профиль '%1'? Enter the new profile for profile '%1': Введите новое имя для профиля '%1': Unknown error occured. Произошла неизвестная ошибка. Cannot open default configuration for selected layout. Не могу открыть конфигурацию по-умолчанию для выбранной раскладки. QObject Non-linear keyboard trainer Нелинейный клавиатурный тренажёр non-linear keyboard trainer нелинейный клавиатурный тренажёр StatsLogic all все exercise упражнение day день week неделя month месяц year год StatsLogic::category exercise #%1 упражнение #%1 all все StatsWidget OK ОК Categorize by: Категоризировать по: Summarize by: Суммировать по: Category: Категория: Exercise count Кол-во упражнений Symbol count Кол-во символов Time, sec. Время, сек. Speed average, symb./sec. Средняя скорость, симв./сек. Mistake average Среднее количество ошибок Rhythm average, % Средний ритм, % Index Индекс Table Таблица Plots Графики Statistics Статистика Mistakes Ошибки Combinations Комбинации Mistake Ошибка Count Количество Combination Комбинация Show grids on plots Показывать сетки на графиках Set minimum Y value to 0 Выставить минимальное Y-значение в 0 Scroll down Перейти в низ таблицы StatsWidget::initCagegorizeInfo exercise упражнение day день week неделя month месяц year год all все UserProfile %7Keyboard layout: %1Exercises done: %2Symbols typed: %3Time spent: %4Average mistake count by exercise: %5Average typing speed: %6 %7Раскладка клавиатуры: %1Упражнений выполнено: %2Символов набрано: %3Времени потрачено: %4Среднее количество ошибок за упражнение: %5Средняя скорость набора: %6 main Other instance exists Запущена другая копия приложения You are already running other instance of this program. Вы уже запустили это приложение. nlkt-0.3.2.2/share/translations/nlkt_uk.ts000066400000000000000000000437211173762012600205020ustar00rootroot00000000000000 MainWidget Time, sec: Час, сек: Mistakes: Помилок: of з Speed, symb./sec.: Швидкість, симв./сек.: &Start &Почати S&top &Закінчити St&ats &Статистика &Quit В&ихід Too many mistakes Забагато помилок Too many mistakes in current exercise. Exercise stopped. Забагато помилок у поточній вправі. Вправа зупинена. Your results Ваші результати Letters count Символів надруковано Mistakes Помилок Time spent (min:sec,millisec) Часу затрачено (хв:сек:міллісек) Average speed, symbols per minute Середня швидкість, символів за хвилину Exercise has been successfully finished! Вправа була успішно закінчена! Start Почати Stop Закінчити Stats Статистика Quit Вихід Rhythm Ритм Get relax... Відпочиньте... ProfileManager Select Вибрати Cancel Відміна Delete Видалити Rename Змінити ім'я Enter name of new profile: Введіть ім'я нового профілю: Select the layout: Виберіть розкладку: Existing profile Існуючий профіль New profile Новий профіль Select the profile Виберіть профіль Cannot use this profile name Не можу використати це ім'я профілю The profile with name '%1' already exists. Профіль з ім'ям '%1' вже існує. Delete profile? Видалити профіль? Unable to delete the profile Не можу видалити профіль Somewhy cannot delete the profile '%1' :( Чомусь не можу видалити профіль '%1' :( Renaming profile Зміна імені профілю Unable to rename the profile Не можу змінити ім'я профілю Somewhy cannot rename the profile '%1' :( Чомусь не можу змінити ім'я профілю '%1' :( Do you really want to delete the profile '%1'? Ви впевнені, що хочете видатили профіль '%1'? Enter the new profile for profile '%1': Введіть нове ім'я профілю '%1': Unknown error occured. Виникла незнайома помилка. Cannot open default configuration for selected layout. Не можу відкрити конфігурацію за замовчуванням. QObject Non-linear keyboard trainer Нелінійний клавіатурний тренажер non-linear keyboard trainer нелінійний клавіатурний тренажер StatsLogic all усі exercise вправа day день week тиждень month місяць year рік StatsLogic::category exercise #%1 вправа #%1 all усі StatsWidget OK ОК Categorize by: Категоризувати по: Summarize by: Сумувати по: Category: Категорія: Exercise count К-ть вправ Symbol count К-ть символів Time, sec. Час, сек. Speed average, symb./sec. Середня швидкість, симв./сек. Mistake average Середня кількість помилок Rhythm average, % Середній ритм, % Index Індекс Table Таблиця Plots Графіки Statistics Статистика Mistakes Помилки Combinations Комбінації Mistake Помилка Count Кількість Combination Комбінація Show grids on plots Показувати сітки на графіках Set minimum Y value to 0 Встановити мінімальне Y-значення в 0 Scroll down Перейти до низу таблиці StatsWidget::initCagegorizeInfo exercise вправа day день week тиждень month місяць year рік all усі UserProfile %7Keyboard layout: %1Exercises done: %2Symbols typed: %3Time spent: %4Average mistake count by exercise: %5Average typing speed: %6 %7Розкладка клавіатури: %1Завдань виконано: %2Символів набрано: %3Часу витрачено: %4Середня кількість помилок за вправу: %5Середня швидкість набору: %6 main Other instance exists Ця программа вже запущена You are already running other instance of this program. Ви вже запустили цю программу. nlkt-0.3.2.2/src/000077500000000000000000000000001173762012600134205ustar00rootroot00000000000000nlkt-0.3.2.2/src/FortunesGetter.cpp000066400000000000000000000141271173762012600171110ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include //#include //#include #include #include #include #include #include "FortunesGetter.hpp" #include "UserProfile.hpp" #include "Setup.hpp" using std::vector; bool Fortune::operator<(const Fortune& other) const { return this->phrase < other.phrase; } //----------------------------------------------------------------------------- FortuneCatalog::FortuneCatalog(const QString& path) : path(path) { qDebug("Reading fortune catalog from %s", qPrintable(path)); QFile fin(path); if (!fin.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning("Cannot load the fortune catalog %s", qPrintable(path)); } else { QTextStream in(&fin); in.setCodec("UTF-8"); QString phrase, author; while (!(in.atEnd())) { phrase = in.readLine(); author = in.readLine(); if (!(phrase.isEmpty())) { Fortune tmpFortune = { phrase, author }; fortuneSet.insert(tmpFortune); } } fin.close(); } } void FortuneCatalog::addFortune(const Fortune& fortune) { fortuneSet.insert(fortune); // adding new fortune to file QFile fout(path); if (!fout.open(QIODevice::Append | QIODevice::Text)) { qWarning("Cannot renew the fortune catalog %s", qPrintable(path)); } QTextStream out(&fout); out.setCodec("UTF-8"); out << fortune.phrase << endl << fortune.author << endl; } bool FortuneCatalog::wasSuchFortune(const Fortune& fortune) const { return (fortuneSet.find(fortune) != fortuneSet.end()); } //----------------------------------------------------------------------------- FortunesGetter::FortunesGetter(const UserProfile& profile) : profile(profile), fortuneCatalog(pathToUserFortuneCatalog) {} Fortune FortunesGetter::getFortune(const QString& pattern) { /* QLabel* waitLabel = new QLabel(QCoreApplication::translate("Getting fortune dialog", "Please wait. Selecting fortune...")); waitLabel->setForegroundRole(QPalette::Dark); waitLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter); waitLabel->setFrameStyle(QFrame::StyledPanel); waitLabel->setWindowFlags(waitLabel->windowFlags() | Qt::FramelessWindowHint); waitLabel->setWindowModality(Qt::WindowModal); waitLabel->show(); waitLabel->setFocus(Qt::OtherFocusReason); QProgressDialog progressDialog(QCoreApplication::translate("Getting fortune dialog", "Please wait. Selecting fortune..."), QCoreApplication::translate("Getting fortune dialog", "Hide"), 0, 1); progressDialog.setMinimumDuration(1000); progressDialog.setWindowModality(Qt::WindowModal); QCoreApplication::processEvents(); sleep(3); */ Fortune result; QString fortuneArguments = profile.getFortuneArgumentsLine(); QString fortuneCommand = QString("fortune -n %1 -s %2 -m '%3' 2>/dev/null") .arg(maxSymbolsInFortune) .arg(fortuneArguments) .arg(pattern); if (fortuneArguments.isEmpty()) // english language { // try to workaround fortune bug: // when locale isn't english, i haven't found a correct way to select // only english fortunes // // so supposing that most systems have the default "C" locale fortuneCommand.prepend(QString::fromLatin1("LC_ALL=C ")); } qDebug("Fortune command: %s", qPrintable(fortuneCommand)); vector candidates; Fortune tmp; FILE* pipe = popen(qPrintable(fortuneCommand), "r"); QFile fin; if (!fin.open(pipe, QIODevice::ReadOnly)) { qFatal("Cannot attach to a fortune pipe"); } QTextStream pin(&fin); QString buf; while (!pin.atEnd()) { QCoreApplication::processEvents(); buf = pin.readLine(); if (buf == QString::fromLatin1("%")) { // fortune is finished tmp.phrase = tmp.phrase.simplified(); tmp.author = tmp.author.simplified(); if (!tmp.phrase.isEmpty() && profile.getLayout().isAdmissibleFortune(tmp.phrase) && !fortuneCatalog.wasSuchFortune(tmp)) { candidates.push_back(tmp); } tmp.phrase = ""; tmp.author = ""; } else { int dashesIndex = buf.indexOf(QString::fromLatin1("--")); if (dashesIndex != -1) { /* bla-bla-bla-aaaaaaaaaaaaaaa la-la-la-aaaaaaaaaaaaaa -- B.L. Blabla |||^ */ if (buf.size() > dashesIndex + 3) { tmp.author += buf.mid(dashesIndex + 3); } } else { tmp.phrase += buf + " "; } } } fin.close(); pclose(pipe); if (!candidates.empty()) { result = candidates[ yf::random::rnd_uint32(static_cast(candidates.size())) ]; fortuneCatalog.addFortune(result); } else { if (!pattern.isEmpty()) { // backing to non-pattern query result = this->getFortune(QString()); } else { result.phrase = "No fortunes found :("; qCritical() << "No fortunes found from call '" << qPrintable(fortuneCommand) << "'"; } } /* waitLabel->hide(); delete waitLabel; progressDialog.setValue(1); */ return result; } nlkt-0.3.2.2/src/FortunesGetter.hpp000066400000000000000000000037571173762012600171250ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_FORTUNES_GETTER_HPP_INCLUDED #define yf_FORTUNES_GETTER_HPP_INCLUDED #include #include class UserProfile; using std::set; struct Fortune { QString phrase; QString author; bool operator<(const Fortune& other) const; }; class FortuneCatalog { public: FortuneCatalog(const QString& path); void addFortune(const Fortune& fortune); bool wasSuchFortune(const Fortune& fortune) const; private: const QString path; set fortuneSet; }; class FortunesGetter { public: FortunesGetter(const UserProfile& profile); Fortune getFortune(const QString& pattern); private: const UserProfile& profile; FortuneCatalog fortuneCatalog; }; #endif // yf_FORTUNES_GETTER_HPP_INCLUDED nlkt-0.3.2.2/src/KeyboardWidget.cpp000066400000000000000000000120161173762012600170300ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include "KeyboardWidget.hpp" #include "Setup.hpp" KeyboardWidget::KeyboardWidget(const Layout& layout, QWidget* parent) : QFrame(parent), layout(layout) { symbolToMark = nullChar; // reading the image this->keyboardImage = new QPixmap(pathToKeyboardImage); if (keyboardImage->isNull()) { qCritical() << "Cannot load the keyboard image at" << qPrintable(pathToKeyboardImage); } const int imageMargin = 2; //this->setMargin(imageMargin); this->setFrameStyle(QFrame::StyledPanel); this->setFixedSize(keyboardImage->width() + imageMargin, keyboardImage->height() + imageMargin); this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); this->drawLettersOnPixmap(); } void KeyboardWidget::markSymbol(QChar symbol) { //qDebug() << "Symbol to mark:" << symbol; symbolToMark = symbol; this->update(); } KeyboardWidget::~KeyboardWidget() { delete this->keyboardImage; } // some common constants // --------------------------- const size_t rowCount = 4; const QPoint rowStartPoints[rowCount] = { QPoint(14, 5), QPoint(69, 41), QPoint(81, 77), QPoint(101, 113) }; const size_t cellSpacing = 41; // ---------------------------- void KeyboardWidget::drawLettersOnPixmap() { const int fontSize = 13; const size_t bigCharTopDisplace = 19; const size_t bigCharLeftDisplace = 18; const size_t smallCharTopDisplace = 26; const size_t smallCharLeftDisplace = 5; QPainter painter(this->keyboardImage); painter.setFont(QFont("Monospace", fontSize)); for (size_t row = 0; row < rowCount; ++row) { int indexCount = layout.charsInRow(row); for (int index = 0; index < indexCount; ++index) { int drawX = rowStartPoints[row].x() + cellSpacing*index; int drawY = rowStartPoints[row].y(); painter.drawText(drawX + bigCharLeftDisplace, drawY + bigCharTopDisplace, QString(layout.getBigChar(row, index))); painter.drawText(drawX + smallCharLeftDisplace, drawY + smallCharTopDisplace, QString(layout.getSmallChar(row, index))); } } } void KeyboardWidget::paintEvent(QPaintEvent* event) { const size_t cellSize = 32; const QPen defaultPen = QPen(Qt::black); const QColor bigMarkColor = Qt::red; const QColor smallMarkColor = Qt::blue; const QColor spaceMarkColor = Qt::green; const int penWidth = 3; const QRect spaceRect = QRect(QPoint(162, 151), QSize(244, 25)); QPainter painter(this); painter.drawPixmap(0, 0, *keyboardImage); painter.setBrush(QBrush(QColor(0, 0, 0, 0))); for (size_t row = 0; row < rowCount; ++row) { int indexCount = layout.charsInRow(row); for (int index = 0; index < indexCount; ++index) { int drawX = rowStartPoints[row].x() + cellSpacing*index; int drawY = rowStartPoints[row].y(); /* qDebug() << "symbolToMark:" << symbolToMark << ", big symbol:" << layout.getBigChar(row, index) << ",small symbol:" << layout.getSmallChar(row, index); */ QColor markColor; bool doMarking = false; if (symbolToMark == spaceChar) { QPen markPen(spaceMarkColor); markPen.setWidth(penWidth); painter.setPen(markPen); painter.drawRect(spaceRect); painter.setPen(defaultPen); } else if (symbolToMark == layout.getBigChar(row, index)) { //qDebug("Marking big symbol"); markColor = bigMarkColor; doMarking = true; } else if (symbolToMark == layout.getSmallChar(row, index)) { //qDebug("Marking small symbol"); markColor = smallMarkColor; doMarking = true; } if (doMarking) { QPen markPen(markColor); markPen.setWidth(penWidth); painter.setPen(markPen); painter.drawRect(drawX, drawY, cellSize, cellSize); painter.setPen(defaultPen); } } } painter.end(); QFrame::paintEvent(event); event->accept(); } nlkt-0.3.2.2/src/KeyboardWidget.hpp000066400000000000000000000034511173762012600170400ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_KEYBOARD_WIDGET_HPP_INCLUDED #define yf_KEYBOARD_WIDGET_HPP_INCLUDED #include #include "Layout.hpp" class QPixmap; class KeyboardWidget: public QFrame { Q_OBJECT public: KeyboardWidget(const Layout& layout, QWidget* parent = NULL); ~KeyboardWidget(); public slots: void markSymbol(QChar symbol); private: const Layout layout; QPixmap* keyboardImage; QChar symbolToMark; void drawLettersOnPixmap(); void paintEvent(QPaintEvent* event); }; #endif // yf_KEYBOARD_WIDGET_HPP_INCLUDED nlkt-0.3.2.2/src/Layout.cpp000066400000000000000000000062061173762012600154050ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include "Layout.hpp" void Layout::read(const QString& path) { QFile fin(path); if (!fin.open(QIODevice::ReadOnly | QIODevice::Text)) { qFatal("Cannot open layout file at %s", qPrintable(path)); } QTextStream in(&fin); for (size_t i = 0; i < keyboardRowCount; ++i) { this->smallLetters[i] = in.readLine(); this->bigLetters[i] = in.readLine(); } this->layoutFortuneParam = in.readLine(); fin.close(); this->lastPath = path; } bool Layout::containsKey(QChar key) const { if (key == QChar(' ')) { // it's a space - answer is true :) return true; } for (size_t i = 0; i < keyboardRowCount; ++i) { if (smallLetters[i].contains(key) || bigLetters[i].contains(key)) { return true; } } //qDebug("Layout %s doesn't contain key %s", qPrintable(lastPath), qPrintable(QString(key))); return false; } QChar Layout::getSmallChar(size_t row, int index) const { Q_ASSERT(index < this->charsInRow(row)); return smallLetters[row][index]; } QChar Layout::getBigChar(size_t row, int index) const { Q_ASSERT(index < this->charsInRow(row)); return bigLetters[row][index]; } int Layout::charsInRow(size_t row) const { Q_ASSERT(row < keyboardRowCount); Q_ASSERT(smallLetters[row].size() == bigLetters[row].size()); return smallLetters[row].size(); } bool Layout::isAdmissibleFortune(const QString& text) const { for (int i = 0; i < text.size(); ++i) { if (!this->containsKey(text[i])) { return false; break; } } return true; } QChar Layout::getRandomChar() const { using namespace yf::random; const QString* const& string = (rnd_bool() ? this->smallLetters : this->bigLetters); byte row = rnd_uint16(keyboardRowCount); int pos = rnd_uint16(string[row].size()); return string[row][pos]; } QString Layout::getLayoutFortuneParam() const { return layoutFortuneParam; } nlkt-0.3.2.2/src/Layout.hpp000066400000000000000000000036111173762012600154070ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_LAYOUT_HPP_INCLUDED #define yf_LAYOUT_HPP_INCLUDED #include const size_t keyboardRowCount = 4; class Layout { public: void read(const QString& path); bool containsKey(QChar key) const; int charsInRow(size_t row) const; QChar getSmallChar(size_t row, int index) const; QChar getBigChar(size_t row, int index) const; bool isAdmissibleFortune(const QString& text) const; QString getLayoutFortuneParam() const; QChar getRandomChar() const; private: QString smallLetters[keyboardRowCount]; QString bigLetters[keyboardRowCount]; QString lastPath; QString layoutFortuneParam; }; #endif nlkt-0.3.2.2/src/Logic.cpp000066400000000000000000000153101173762012600151610ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include "FortunesGetter.hpp" #include "Logic.hpp" #include "Setup.hpp" #include "UserProfile.hpp" Logic::Logic(FortunesGetter& fortunesGetter, UserProfile& userProfile) : fortunesGetter(fortunesGetter), userProfile(userProfile) { exerciseState = NoExercise; } QChar Logic::randomFiller() { using namespace yf::random; if (rnd_uint16(3)) { return spaceChar; } else { const Layout& layout = userProfile.getLayout(); return layout.getRandomChar(); } } void Logic::startExercise() { exerciseState = FirstPartOfExercise; mistakes.clear(); currentTextPosition = 0; // preparing training text ExerciseResult prevExerciseResult = userProfile.exercises()[userProfile.exercises().size()-1]; QString trainingText; for (size_t j = 0; j < worseTriLetterTrainingCount - 1; ++j) { trainingText += prevExerciseResult.worseTriLetter + this->randomFiller(); } trainingText += prevExerciseResult.worseTriLetter + spaceChar; for (int i = 0; i < prevExerciseResult.mistakes.size(); ++i) { for (size_t j = 0; j < mistakeTrainingCount - 1; ++j) { trainingText += prevExerciseResult.mistakes[i] + this->randomFiller(); } trainingText += prevExerciseResult.mistakes[i] + spaceChar; } this->typingText = trainingText; this->renewMaxAllowedMistakeCount(); qDebug("typingText length = %d", typingText.size()); emit startTyping(trainingText, ""); this->signalAboutMistakesState(); } void Logic::terminateExercise() { exerciseState = NoExercise; emit endTyping(); } void Logic::typedSymbol() { if (exerciseState == SecondPartOfExercise) { this->touchTimestamp(); } currentTextPosition += 1; //qDebug("currentTextPosition = %d", int(currentTextPosition)); if (static_cast(currentTextPosition) == typingText.size()) { this->typedText(); } } void Logic::errorOnSymbol() { if (this->mistakes.size() == this->maxAllowedMistakeCount) { this->terminateExercise(); emit tooManyMistakes(); } else { mistakes.push_back(currentTextPosition); signalAboutMistakesState(); this->typedSymbol(); } } void Logic::renewMaxAllowedMistakeCount() { using std::min; this->maxAllowedMistakeCount = min(maxAllowedMistakes, this->typingText.size() / lineLength + 1); } void Logic::signalAboutMistakesState() { emit maxMistakeCount(this->maxAllowedMistakeCount); emit mistakeCount(mistakes.size()); } void Logic::typedText() { //qDebug("Logic::typedText"); if (exerciseState == FirstPartOfExercise) { emit endTyping(); exerciseState = SecondPartOfExercise; mistakes.clear(); currentTextPosition = 0; typingTimestamps.clear(); QString previousTriLetter = userProfile.exercises()[userProfile.exercises().size()-1].worseTriLetter; Fortune fortune = fortunesGetter.getFortune(previousTriLetter); typingText = fortune.phrase; this->renewMaxAllowedMistakeCount(); emit startTyping(fortune.phrase, fortune.author); this->signalAboutMistakesState(); } else if (exerciseState == SecondPartOfExercise) { exerciseState = NoExercise; // generating ExerciseResult qDebug("generating exercise result"); ExerciseResult exerciseResult; exerciseResult.symbolCount = typingText.size(); exerciseResult.millisecsSpent = yf::get_milli_time( typingTimestamps[0], typingTimestamps[typingTimestamps.size()-1]) * yf::millisec_in_second; exerciseResult.worseTriLetter = this->getWorseTriLetter(); exerciseResult.rhythmPercent = this->getRhythmPercent(); for (size_t i = 0; i < mistakes.size(); ++i) { if (mistakes[i] == 0) { exerciseResult.mistakes.push_back(typingText.left(2)); exerciseResult.mistakes.push_back(typingText.left(2)); } else if (static_cast(mistakes[i]) == typingText.size()-1) { exerciseResult.mistakes.push_back(typingText.right(2)); exerciseResult.mistakes.push_back(typingText.right(2)); } else { exerciseResult.mistakes.push_back(typingText.mid(mistakes[i]-1, 2)); exerciseResult.mistakes.push_back(typingText.mid(mistakes[i], 2)); } } exerciseResult.timestamp = time(NULL); userProfile.exerciseDone(exerciseResult); this->terminateExercise(); // request user wait emit wait(exerciseResult.millisecsSpent / 10); emit exerciseFinished(exerciseResult); } } void Logic::touchTimestamp() { typingTimestamps.push_back(yf::precise_time()); } QString Logic::getWorseTriLetter() const { size_t worseTriLetterIndex = -1; float maxTime = 0; for (size_t i = 1; i < typingTimestamps.size()-1; ++i) { float curTime = yf::get_milli_time(typingTimestamps[i-1], typingTimestamps[i+1]); if (curTime > maxTime) { maxTime = curTime; worseTriLetterIndex = i; } } return typingText.mid(worseTriLetterIndex - 1, 3); } size_t Logic::getRhythmPercent() const { using std::fabs; std::vector timeDistances; for (size_t i = 1; i < typingTimestamps.size()-1; ++i) { timeDistances.push_back(yf::get_milli_time(typingTimestamps[i], typingTimestamps[i+1])); } float averageTime = std::accumulate(timeDistances.begin(), timeDistances.end(), 0.0) / timeDistances.size(); std::vector timeDivergences; for (size_t i = 0; i < timeDistances.size(); ++i) { timeDivergences.push_back(fabs(averageTime - timeDistances[i])); } float divergence = 0.0; for (size_t i = 0; i < timeDivergences.size(); ++i) { divergence += timeDivergences[i] * timeDivergences[i]; } divergence = sqrt(divergence) / timeDivergences.size(); return 100.0 * (1.0 - divergence/averageTime); } nlkt-0.3.2.2/src/Logic.hpp000066400000000000000000000047071173762012600151760ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include using std::vector; class FortunesGetter; class ExerciseResult; class UserProfile; class Logic: public QObject { Q_OBJECT public: Logic(FortunesGetter& fortunesGetter, UserProfile& userProfile); signals: void startTyping(const QString& text, const QString& author); void endTyping(); void wait(int milliseconds); void tooManyMistakes(); void maxMistakeCount(int maxCount); void mistakeCount(int mistakeCount); void exerciseFinished(const ExerciseResult&); public slots: void typedSymbol(); void errorOnSymbol(); void startExercise(); void terminateExercise(); private: enum ExercisePart {FirstPartOfExercise, SecondPartOfExercise, NoExercise}; ExercisePart exerciseState; vector mistakes; QString typingText; size_t maxAllowedMistakeCount; size_t currentTextPosition; vector typingTimestamps; FortunesGetter& fortunesGetter; UserProfile& userProfile; QChar randomFiller(); void typedText(); void touchTimestamp(); void signalAboutMistakesState(); QString getWorseTriLetter() const; size_t getRhythmPercent() const; void renewMaxAllowedMistakeCount(); }; nlkt-0.3.2.2/src/MainWidget.cpp000066400000000000000000000247471173762012600161720ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MainWidget.hpp" #include "KeyboardWidget.hpp" #include "RichboxWidget.hpp" #include "StatsWidget.hpp" #include "UserProfile.hpp" #include "Setup.hpp" MainWidget::MainWidget(const UserProfile& userProfile, QWidget*) : profile(userProfile) { this->readGuiSettings(); // timer this->timer = new QTimer(this); this->timer->setInterval(100); connect(this->timer, SIGNAL(timeout()), this, SLOT(timerInterrupt())); // time stat QLabel* timeLabel = new QLabel(); timeLabel->setText(tr("Time, sec:")); timeLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); this->timeLCD = new QLCDNumber; this->timeLCD->setNumDigits(4); // mistake stat QLabel* mistakesLabel = new QLabel(); mistakesLabel->setText(tr("Mistakes:")); mistakesLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); QLabel* mistakesDividerLabel = new QLabel(); mistakesDividerLabel->setText(tr("of")); this->mistakesLCD = new QLCDNumber; this->mistakesLCD->setNumDigits(1); this->maxMistakesLCD = new QLCDNumber; this->maxMistakesLCD->setNumDigits(1); // speed stat QLabel* speedLabel = new QLabel(); speedLabel->setText(tr("Speed, symb./sec.:")); speedLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter); this->speedLCD = new QLCDNumber; this->speedLCD->setNumDigits(4); // setting buttons this->startButton = new QPushButton(tr("Start")); this->startButton->setShortcut(QString("Ctrl+N")); connect(this->startButton, SIGNAL(clicked()), this, SIGNAL(startExercise())); this->stopButton = new QPushButton(tr("Stop")); this->stopButton->setShortcut(QString("Ctrl+K")); connect(this->stopButton, SIGNAL(clicked()), this, SIGNAL(terminateExercise())); this->statsButton = new QPushButton(tr("Stats")); this->statsButton->setShortcut(QString("Ctrl+P")); connect(this->statsButton, SIGNAL(clicked()), this, SLOT(showStats())); this->endButton = new QPushButton(tr("Quit")); this->endButton->setShortcut(QString("Ctrl+Q")); connect(this->endButton, SIGNAL(clicked()), qApp, SLOT(quit())); // setting main widgets this->keyboardWidget = new KeyboardWidget(userProfile.getLayout()); this->richBoxWidget = new RichBoxWidget; this->richBoxWidget->setEnabled(false); this->richBoxWidget->document()->setDefaultFont(QFont("Monospace", 12)); // "screer" of the richbox QFrame* hideFrame = new QFrame; hideFrame->setFocusPolicy(Qt::NoFocus); hideFrame->setAutoFillBackground(false); this->setDefaultState(); // layout setting QHBoxLayout* statsLayout = new QHBoxLayout; statsLayout->addStrut(32); statsLayout->addWidget(timeLabel, 1); statsLayout->addWidget(this->timeLCD); statsLayout->addStretch(10); statsLayout->addWidget(speedLabel, 1); statsLayout->addWidget(this->speedLCD); statsLayout->addStretch(10); statsLayout->addWidget(mistakesLabel, 1); statsLayout->addWidget(this->mistakesLCD); statsLayout->addWidget(mistakesDividerLabel, 1); statsLayout->addWidget(this->maxMistakesLCD); QGridLayout* layout = new QGridLayout; QHBoxLayout* bottomLayout = new QHBoxLayout; bottomLayout->addWidget(this->startButton); bottomLayout->addWidget(this->stopButton); bottomLayout->addWidget(this->statsButton); bottomLayout->addWidget(this->endButton); layout->addLayout(statsLayout, 0, 0); layout->addWidget(this->richBoxWidget, 1, 0); layout->addWidget(hideFrame, 1, 0); layout->addWidget(this->keyboardWidget, 2, 0, Qt::AlignHCenter); layout->addLayout(bottomLayout, 3, 0); layout->setSizeConstraint(QLayout::SetFixedSize); this->setLayout(layout); // connecting signals connect(richBoxWidget, SIGNAL(errorOnSymbol()), this, SIGNAL(errorOnSymbol())); connect(richBoxWidget, SIGNAL(typedSymbol()), this, SIGNAL(typedSymbol())); connect(richBoxWidget, SIGNAL(errorOnSymbol()), this, SLOT(onNextSymbol())); connect(richBoxWidget, SIGNAL(typedSymbol()), this, SLOT(onNextSymbol())); connect(richBoxWidget, SIGNAL(markSymbol(QChar)), keyboardWidget, SLOT(markSymbol(QChar))); // for all LCDs foreach(QLCDNumber* lcd, this->findChildren()) { lcd->setSegmentStyle(QLCDNumber::Flat); lcd->setFrameStyle(QFrame::StyledPanel); } // for all buttons foreach(QPushButton* button, this->findChildren()) { button->setFocusPolicy(Qt::NoFocus); button->setToolTip(button->shortcut().toString()); } } void MainWidget::startTyping(const QString& text, const QString& author) { this->startButton->setEnabled(false); this->statsButton->setEnabled(false); this->stopButton->setEnabled(true); this->setFocus(Qt::OtherFocusReason); this->richBoxWidget->startTyping(text, author); } void MainWidget::endTyping() { this->richBoxWidget->endTyping(); this->timer->stop(); this->keyboardWidget->markSymbol(nullChar); this->setDefaultState(); } void MainWidget::tooManyMistakes() { QMessageBox::critical(this, tr("Too many mistakes"), tr("Too many mistakes in current exercise.\nExercise stopped.")); } void MainWidget::exerciseFinished(const ExerciseResult& exerciseResult) { const QString endl = QString::fromLatin1("\n"); QString message; message += tr("Your results") + ":"; message += endl + endl + tr("Letters count") + ": " + QString::number(exerciseResult.symbolCount); message += endl + tr("Mistakes") + ": " + QString::number(exerciseResult.mistakes.size() / 2); // /2 because mistakes combination is twiced message += endl + tr("Time spent (min:sec,millisec)") + (QString(": %1:%2,%3")).arg( static_cast(exerciseResult.millisecsSpent / yf::sec_in_minute / yf::millisec_in_second), 2, 10, QLatin1Char('0')).arg( static_cast(exerciseResult.millisecsSpent / yf::millisec_in_second % yf::sec_in_minute), 2, 10, QLatin1Char('0')).arg( static_cast(exerciseResult.millisecsSpent % yf::millisec_in_second), 3, 10, QLatin1Char('0')); message += endl + tr("Average speed, symbols per minute") + ": " + QString::number( exerciseResult.symbolCount * yf::millisec_in_second * yf::sec_in_minute / exerciseResult.millisecsSpent); message += endl + tr("Rhythm") + ": " + QString::number(exerciseResult.rhythmPercent) + "%"; QMessageBox::information(this, tr("Exercise has been successfully finished!"), message); } void MainWidget::keyPressEvent(QKeyEvent* event) { QChar eventChar = event->text()[0]; if (profile.getLayout().containsKey(eventChar)) { this->richBoxWidget->keyPressed(eventChar); } else { event->ignore(); } } void MainWidget::timerInterrupt() { this->millisecs += this->timer->interval(); this->setTimeLabel(this->millisecs); this->setSpeedLabel(); } void MainWidget::setTimeLabel(uint32 millisecs) { /* this->timeLabel->setText(tr("Time spent: %L1 secs").arg (static_cast(millisecs)/yf::millisec_in_second, 0, 'f', 1)); */ this->timeLCD->display(static_cast(millisecs/yf::millisec_in_second)); } void MainWidget::setSpeedLabel() { QString tmp; if (this->millisecs) { this->speedLCD->display(static_cast(this->symbolsWritten * yf::millisec_in_second * yf::sec_in_minute / this->millisecs)); } else { this->speedLCD->display(spaceChar); } //this->speedLabel->setText(tr("Speed: ") + tmp + tr(" symbols per second")); } void MainWidget::setDefaultState() { this->millisecs = 0; this->symbolsWritten = 0; this->timeLCD->display(spaceChar); this->speedLCD->display(spaceChar); this->mistakesLCD->display(spaceChar); this->maxMistakesLCD->display(spaceChar); this->startButton->setEnabled(true); this->statsButton->setEnabled(true); this->stopButton->setEnabled(false); } void MainWidget::writeGuiSettings() { QSettings settings; settings.beginGroup("MainWidget"); settings.setValue("pos", pos()); settings.endGroup(); } void MainWidget::readGuiSettings() { QSettings settings; settings.beginGroup("MainWidget"); move(settings.value("pos", QPoint(200, 200)).toPoint()); settings.endGroup(); } void MainWidget::closeEvent(QCloseEvent *event) { //qDebug("MainWidget::closeEvent()"); writeGuiSettings(); event->accept(); } void MainWidget::mistakeCount(int mistakeCount) { Q_ASSERT(mistakeCount >= 0 && mistakeCount < 10); this->mistakesLCD->display(mistakeCount); } void MainWidget::maxMistakeCount(int maxCount) { Q_ASSERT(maxCount >= 0 && maxCount < 10); this->maxMistakesLCD->display(maxCount); } void MainWidget::onNextSymbol() { if (!timer->isActive()) { timer->start(); } this->symbolsWritten += 1; } void MainWidget::showStats() { StatsWidget* statsWidget = new StatsWidget(profile); statsWidget->setWindowModality(Qt::ApplicationModal); statsWidget->exec(); delete statsWidget; } void MainWidget::displayWaitMessage(int milliseconds) { qDebug("relaxing for %d milliseconds", milliseconds); QProgressDialog dialog(this); dialog.setMinimumDuration(0); dialog.setMinimum(0); dialog.setMaximum(milliseconds); dialog.setCancelButton(NULL); dialog.setLabelText(tr("Get relax...")); dialog.setFixedSize(dialog.size()); size_t divider = 10; for (size_t i = 0; i < milliseconds/divider; ++i) { yf::wait(divider); dialog.setValue(i*divider); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } dialog.setValue(milliseconds); } nlkt-0.3.2.2/src/MainWidget.hpp000066400000000000000000000054061173762012600161660ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_MAIN_WIDGET_HPP_INCLUDED #define yf_MAIN_WIDGET_HPP_INCLUDED #include #include class QLabel; class QPushButton; class QLCDNumber; class QAction; class KeyboardWidget; class RichBoxWidget; class UserProfile; class Fortune; class ExerciseResult; class MainWidget: public QWidget { Q_OBJECT public: MainWidget(const UserProfile& config, QWidget* parent = NULL); signals: void typedSymbol(); void errorOnSymbol(); void startExercise(); void terminateExercise(); public slots: void displayWaitMessage(int); void startTyping(const QString& text, const QString& author); void endTyping(); void tooManyMistakes(); void maxMistakeCount(int maxCount); void mistakeCount(int mistakesCount); void exerciseFinished(const ExerciseResult& exerciseResult); void writeGuiSettings(); private slots: void timerInterrupt(); void onNextSymbol(); void showStats(); private: const UserProfile& profile; KeyboardWidget* keyboardWidget; RichBoxWidget* richBoxWidget; QPushButton* startButton; QPushButton* stopButton; QPushButton* statsButton; QPushButton* endButton; QLCDNumber* mistakesLCD; QLCDNumber* maxMistakesLCD; QLCDNumber* speedLCD; QLCDNumber* timeLCD; QTimer* timer; size_t millisecs; size_t symbolsWritten; void keyPressEvent(QKeyEvent* event); void closeEvent(QCloseEvent* event); void setTimeLabel(uint32 millisecs); void setSpeedLabel(); void setDefaultState(); void readGuiSettings(); }; #endif // yf_MAIN_WIDGET_HPP_INCLUDED nlkt-0.3.2.2/src/Path.hpp000066400000000000000000000037161173762012600150340ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_PATH_HPP_INCLUDED #define yf_PATH_HPP_INCLUDED #include #ifdef NLKT_USE_SYSTEM_PATH #define SHARE_PREFIX "/usr/share/nlkt" #else #define SHARE_PREFIX "../share" #endif const QString homeDir = QDir::homePath(); const QString programName = "nlkt"; const QString pathToKeyboardImage = SHARE_PREFIX "/images/keyboard.png"; const QString pathToUserProfiles = homeDir + "/.nlkt/profiles/"; const QString pathToDefaultProfiles = SHARE_PREFIX "/default_profiles/"; const QString pathToUserFortuneCatalog = homeDir + "/.nlkt/typed_fortunes"; const QString pathToLayouts = SHARE_PREFIX "/layouts/"; const QString pathToTranslations = SHARE_PREFIX "/translations/"; #endif nlkt-0.3.2.2/src/ProfileManager.cpp000066400000000000000000000255161173762012600170300ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ProfileManager.hpp" #include "Setup.hpp" #include "UserProfile.hpp" const QString profileFileExtension = ".v2"; ProfileManager::ProfileManager(QString& profile) : profile(profile) { readGuiSettings(); // ok & cancel buttons this->okButton = new QPushButton(tr("Select")); this->okButton->setDefault(true); this->okButton->setShortcut(QKeySequence(Qt::Key_Return)); connect(this->okButton, SIGNAL(clicked()), this, SLOT(selectProfile())); this->cancelButton = new QPushButton(tr("Cancel")); this->cancelButton->setShortcut(QKeySequence(Qt::Key_Escape)); connect(this->cancelButton, SIGNAL(clicked()), this, SLOT(quit())); QDialogButtonBox* bottomButtonsBox = new QDialogButtonBox(Qt::Horizontal); bottomButtonsBox->addButton(this->okButton, QDialogButtonBox::AcceptRole); bottomButtonsBox->addButton(this->cancelButton, QDialogButtonBox::RejectRole); // "use existing" part this->existingProfilesList = new QListWidget; this->profileTipWidget = new QTextEdit; this->profileTipWidget->setAcceptRichText(true); this->profileTipWidget->setReadOnly(true); deleteProfileButton = new QPushButton(tr("Delete")); connect(deleteProfileButton, SIGNAL(clicked()), this, SLOT(deleteSelectedProfile())); renameProfileButton = new QPushButton(tr("Rename")); connect(renameProfileButton, SIGNAL(clicked()), this, SLOT(renameSelectedProfile())); QHBoxLayout* useExistingProfileWidgetLeftBottomLayout = new QHBoxLayout; useExistingProfileWidgetLeftBottomLayout->addWidget(renameProfileButton); useExistingProfileWidgetLeftBottomLayout->addWidget(deleteProfileButton); QVBoxLayout* useExistingProfileLeftWidgetLayout = new QVBoxLayout; useExistingProfileLeftWidgetLayout->addWidget(this->existingProfilesList); useExistingProfileLeftWidgetLayout->addLayout(useExistingProfileWidgetLeftBottomLayout); QHBoxLayout* useExistingProfileWidgetLayout = new QHBoxLayout; useExistingProfileWidgetLayout->addLayout(useExistingProfileLeftWidgetLayout, 3); useExistingProfileWidgetLayout->addWidget(this->profileTipWidget, 5); QWidget* useExistingProfileWidget = new QWidget; useExistingProfileWidget->setLayout(useExistingProfileWidgetLayout); // "create new" part QWidget* useNewProfileWidget = new QWidget; this->layoutsCombo = new QComboBox; this->loadLayoutsList(); this->newProfileName = new QLineEdit(); QLabel* newProfileNameLabel = new QLabel(tr("Enter name of new profile:")); newProfileNameLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); QLabel* newProfileSelectLayoutLabel = new QLabel(tr("Select the layout:")); //newProfileSelectLayoutLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop); QGridLayout* useNewProfileWidgetLayout = new QGridLayout; useNewProfileWidgetLayout->addWidget(newProfileNameLabel, 0, 0); useNewProfileWidgetLayout->addWidget(this->newProfileName, 0, 1); useNewProfileWidgetLayout->addWidget(newProfileSelectLayoutLabel, 1, 0); useNewProfileWidgetLayout->addWidget(this->layoutsCombo, 1, 1); useNewProfileWidget->setLayout(useNewProfileWidgetLayout); // misc this->tabs = new QTabWidget; this->tabs->addTab(useExistingProfileWidget, tr("Existing profile")); this->tabs->addTab(useNewProfileWidget, tr("New profile")); this->setWindowTitle(tr("Select the profile")); QVBoxLayout* layout = new QVBoxLayout; layout->addWidget(this->tabs); layout->addWidget(bottomButtonsBox); this->setLayout(layout); this->loadExistingProfilesList(); connect(tabs, SIGNAL(currentChanged(int)), this, SLOT(renewOkButtonEnabled())); connect(this->existingProfilesList, SIGNAL(currentRowChanged(int)), this, SLOT(displayTip(int))); } void ProfileManager::loadExistingProfilesList() { QSettings settings; QDir profileDir = pathToUserProfiles; this->existingProfilesList->clear(); this->profileTips.clear(); QStringList profilesList = profileDir.entryList((QStringList() << ("*" + profileFileExtension)), QDir::Files); foreach (const QString profileName, profilesList) { QString profilePath = pathToUserProfiles + profileName; if (UserProfile::isCorrectProfile(profilePath)) { this->existingProfilesList->addItem(profileName); // building the tip info for profile UserProfile profileInfo(profilePath); this->profileTips.push_back(profileInfo.getGeneralStats()); } else { qWarning("Skipped the profile %s.", qPrintable(profileName)); } } // selecting last used profile if available settings.beginGroup("ProfileManager"); QString lastProfileName = settings.value("last_used_profile", QString::fromLatin1("default")).toString(); settings.endGroup(); if (!this->existingProfilesList->findItems(lastProfileName, Qt::MatchFixedString | Qt::MatchCaseSensitive).empty()) { for (int i = 0; i < this->existingProfilesList->count(); ++i) { if (this->existingProfilesList->item(i)->text() == lastProfileName) { this->existingProfilesList->setCurrentRow(i); } } } else if (this->existingProfilesList->count()) { this->existingProfilesList->setCurrentRow(0); } else { this->renameProfileButton->setEnabled(false); this->deleteProfileButton->setEnabled(false); this->renewOkButtonEnabled(); } this->displayTip(this->existingProfilesList->currentRow()); } void ProfileManager::loadLayoutsList() { QDir layoutsDir = pathToLayouts; QStringList layoutsList = layoutsDir.entryList(QDir::Files); foreach (const QString layoutName, layoutsList) { this->layoutsCombo->addItem(layoutName); } if (this->layoutsCombo->count()) { this->layoutsCombo->setCurrentIndex(0); } else { qFatal("Unable to find any layouts in %s", qPrintable(pathToLayouts)); } } void ProfileManager::selectProfile() { QSettings settings; if (tabs->currentIndex() == 0) // use existing profile tab { profile = this->existingProfilesList->item(this->existingProfilesList->currentRow())->text(); } else // use new profile name { QString newProfileName = this->newProfileName->text() + profileFileExtension; enum UserProfile::ConstructNewProfileResult constructResult = UserProfile::constructNewProfile( newProfileName, this->layoutsCombo->currentText()); switch (constructResult) { case UserProfile::ProfileExists: QMessageBox::critical(this, tr("Cannot use this profile name"), tr("The profile with name '%1' already exists.").arg(newProfileName)); return; case UserProfile::CombinationError: QMessageBox::critical(this, tr("Cannot use this profile name"), tr("Cannot open default configuration for selected layout.")); return; case UserProfile::OtherError: QMessageBox::critical(this, tr("Cannot use this profile name"), tr("Unknown error occured.")); return; case UserProfile::Ok: ; // everything is ok } this->profile = newProfileName; } // saving which profile selected (if selected :)) if (this->profile != QString()) { settings.beginGroup("ProfileManager"); settings.setValue("last_used_profile", this->profile); settings.endGroup(); } this->quit(); } void ProfileManager::writeGuiSettings() { QSettings settings; settings.beginGroup("ProfileManager"); settings.setValue("pos", pos()); settings.setValue("size", size()); settings.endGroup(); } void ProfileManager::readGuiSettings() { QSettings settings; settings.beginGroup("ProfileManager"); resize(settings.value("size", QSize(150, 100)).toSize()); move(settings.value("pos", QPoint(200, 200)).toPoint()); settings.endGroup(); } void ProfileManager::quit() { writeGuiSettings(); qApp->quit(); } void ProfileManager::deleteSelectedProfile() { QString selectedProfile = this->existingProfilesList->item(this->existingProfilesList->currentRow())->text(); QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Delete profile?"), tr("Do you really want to delete the profile '%1'?").arg(selectedProfile), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel); if (answer == QMessageBox::Ok) { bool success = QFile::remove(pathToUserProfiles + selectedProfile); if (!success) { QMessageBox::critical(this, tr("Unable to delete the profile"), tr("Somewhy cannot delete the profile '%1' :(").arg(selectedProfile)); } this->loadExistingProfilesList(); } } void ProfileManager::renameSelectedProfile() { QString selectedProfile = this->existingProfilesList->item(this->existingProfilesList->currentRow())->text(); bool ok; QString newName = QInputDialog::getText(this, tr("Renaming profile"), tr("Enter the new profile for profile '%1':").arg(selectedProfile), QLineEdit::Normal, selectedProfile, &ok); if (ok) { bool success = QFile::rename(pathToUserProfiles + selectedProfile, pathToUserProfiles + newName); if (!success) { QMessageBox::critical(this, tr("Unable to rename the profile"), tr("Somewhy cannot rename the profile '%1' :(").arg(selectedProfile)); } this->loadExistingProfilesList(); } } void ProfileManager::renewOkButtonEnabled() { if (tabs->currentIndex() == 0) { if (!this->existingProfilesList->count()) { this->okButton->setEnabled(false); } else { this->okButton->setEnabled(true); } } else { this->okButton->setEnabled(true); } } void ProfileManager::displayTip(int currentRow) { if (currentRow != -1) // if there is at least one profile { this->profileTipWidget->setHtml(this->profileTips[currentRow]); } else { this->profileTipWidget->setHtml(QString()); } } nlkt-0.3.2.2/src/ProfileManager.hpp000066400000000000000000000043231173762012600170260ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef NLKT_PROFILE_MANAGER_HPP #define NLKT_PROFILE_MANAGER_HPP #include #include using std::vector; class QPushButton; class QListWidget; class QTabWidget; class QLineEdit; class QComboBox; class QTextEdit; class ProfileManager: public QWidget { Q_OBJECT public: ProfileManager(QString& profileName); private slots: void selectProfile(); void quit(); void deleteSelectedProfile(); void renameSelectedProfile(); void renewOkButtonEnabled(); void displayTip(int); private: QString& profile; vector profileTips; QTabWidget* tabs; QListWidget* existingProfilesList; QTextEdit* profileTipWidget; QComboBox* layoutsCombo; QLineEdit* newProfileName; QPushButton* okButton; QPushButton* cancelButton; QPushButton* deleteProfileButton; QPushButton* renameProfileButton; void loadExistingProfilesList(); void loadLayoutsList(); void writeGuiSettings(); void readGuiSettings(); }; #endif nlkt-0.3.2.2/src/RichboxWidget.cpp000066400000000000000000000127551173762012600167000ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include "RichboxWidget.hpp" #include "Setup.hpp" RichBoxWidget::RichBoxWidget(QWidget*) { this->setFixedHeight(richBoxWidgetHeight); this->setAcceptRichText(true); this->setReadOnly(true); this->document()->setDefaultStyleSheet("body { white-space: pre }"); this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); this->setFocusPolicy(Qt::NoFocus); } void RichBoxWidget::startTyping(const QString& text, const QString& author) { this->mistakeIndexes.clear(); this->currentPosition = 0; this->text = text; this->author = author; this->setEnabled(true); QTextEdit::setHtml(renderHtml()); Q_ASSERT(!text.isEmpty()); emit markSymbol(text[0]); } void RichBoxWidget::endTyping() { this->setEnabled(false); } static QString quoteText(const QString& text) { QString result = text; result.replace(QString("&"), QString("&")); result.replace(QString("\""), QString(""")); result.replace(QString("<"), QString("<")); result.replace(QString(">"), QString(">")); return result; } QString RichBoxWidget::renderHtml() const { QString result = ""; for (size_t i = 0; i < mistakeIndexes.size(); ++i) { const uint& mistakeIndex = mistakeIndexes[i]; uint leftIndex = ( (i == 0) ? 0 : (mistakeIndexes[i-1] + 1) ); // adding non-mistake part result += quoteText(text.mid(leftIndex, mistakeIndex-leftIndex)); // adding mistake byte result += QString("%1").arg(quoteText(text[mistakeIndex])); } int lastMistakeIndex = (mistakeIndexes.empty()) ? -1 : mistakeIndexes[mistakeIndexes.size() - 1]; result += quoteText(text.mid(lastMistakeIndex+1, currentPosition-lastMistakeIndex-1)); if (this->isEnabled()) { result += QString("%1").arg(quoteText(text[currentPosition])); if (static_cast(currentPosition) < text.size() - 1) { result += quoteText(text.mid(currentPosition+1)); } } // adding author entry result += QString("

%1

").arg(quoteText(author)); result += ""; //
-ing - dividing text into lines this->insertWraps(result); //qDebug() << "Richbox contains:" << qPrintable(result); return result; } void RichBoxWidget::insertWraps(QString& result) const { bool inTag = false; bool inSpecialSymbol = false; size_t symbolCounter = 0; int probableRawInsertPosition = 0; int probableTextInsertPosition = 0; int lastTextInsertPosition = 0; QString br = "
"; for (int i = 0; i < result.size(); ++i) { if (result[i] == '<') { inTag = true; } else if (result[i] == '>') { inTag = false; } else if (!inTag) { // checking for '&...;"-like symbols if (result[i] == ';') { inSpecialSymbol = false; } else if (result[i] == '&') { inSpecialSymbol = true; } if (!inSpecialSymbol) { ++symbolCounter; if (result[i] == spaceChar) { probableRawInsertPosition = i+1; probableTextInsertPosition = symbolCounter; } if (symbolCounter - lastTextInsertPosition == lineLength) { int lastRawInsertPosition = (probableRawInsertPosition ? probableRawInsertPosition : i+1); result.insert(lastRawInsertPosition, br); i += br.size(); probableRawInsertPosition = 0; lastTextInsertPosition = probableTextInsertPosition; } if (static_cast(symbolCounter) == text.size()) { // main text is end... exiting is our only way break; } } } } } void RichBoxWidget::keyPressed(QChar symbol) { if (this->isEnabled() && symbol.isPrint()) { //* debug */ qDebug() << "keyPressed:" << qPrintable(QString(symbol)); if (symbol == text[currentPosition]) { // all's ok! emit typedSymbol(); } else { // mistake :( mistakeIndexes.push_back(currentPosition); emit errorOnSymbol(); } currentPosition += 1; if (static_cast(currentPosition) == text.size()) { // text is finished this->setEnabled(false); //emit finished(); // now Logic recognizes 'finished' event itself } else { //qDebug("RichBoxWidget::currentPosition = %d", (int)currentPosition); emit markSymbol(text[currentPosition]); } QTextEdit::setHtml(renderHtml()); } } nlkt-0.3.2.2/src/RichboxWidget.hpp000066400000000000000000000037111173762012600166750ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_RICHBOX_WIDGET_HPP_INCLUDED #define yf_RICHBOX_WIDGET_HPP_INCLUDED #include #include using std::vector; class QChar; class RichBoxWidget: public QTextEdit { Q_OBJECT public: RichBoxWidget(QWidget* parent = NULL); public slots: void startTyping(const QString& text, const QString& author); void endTyping(); void keyPressed(QChar symbol); signals: void markSymbol(QChar symbol); void errorOnSymbol(); void typedSymbol(); private: QString text; QString author; vector mistakeIndexes; uint currentPosition; QString renderHtml() const; void insertWraps(QString& result) const; }; #endif // yf_RICHBOX_WIDGET_HPP_INCLUDED nlkt-0.3.2.2/src/Setup.hpp000066400000000000000000000035361173762012600152400ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_SETUP_HPP_INCLUDED #define yf_SETUP_HPP_INCLUDED #include #include #include "Path.hpp" const size_t maxAllowedMistakes = 9; const size_t mistakeTrainingCount = 10; const size_t worseTriLetterTrainingCount = 15; const size_t lineLength = 60; const size_t maxSymbolsInFortune = 360; const QChar spaceChar = QChar::fromLatin1(' '); const QChar nullChar = QChar::fromLatin1('\0'); //const int keyboardImageWidth = 670; //const int keyboardImageWidth = 630; //const int keyboardImageHeight = 180; const int richBoxWidgetHeight = 210; #endif nlkt-0.3.2.2/src/StatsLogic.cpp000066400000000000000000000153221173762012600162030ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include "StatsLogic.hpp" using std::make_pair; StatsLogic::StatsLogic(const UserProfile& profile) : profile(profile) { const vector& exercises = profile.exercises(); Stat stat = Stat(); for (size_t i = 1; i < exercises.size(); ++i) // 0-th exercise is "null" and isn't needed { AddInfo addInfo; addInfo.exerciseNumber = i; addInfo.timestamp = exercises[i].timestamp; stat.exerciseCount = 1; stat.symbolCount = exercises[i].symbolCount; stat.mistakeAverage = exercises[i].mistakes.size() / 2; stat.rhythmAverage = exercises[i].rhythmPercent; stat.speedAverage = exercises[i].millisecsSpent ? ( exercises[i].symbolCount * yf::millisec_in_second * yf::sec_in_minute / exercises[i].millisecsSpent) : 0; stat.time = static_cast(exercises[i].millisecsSpent)/yf::millisec_in_second; stat.combinations.clear(); stat.combinations += exercises[i].worseTriLetter; stat.mistakes.clear(); stat.mistakes += exercises[i].mistakes; this->stats.push_back(make_pair(stat, addInfo)); } initCategorizeInfo(); } StatsLogic::CategorizedStats StatsLogic::categorize(CategorizeType categorizeBy, CategorizeType summarizeBy) { CategorizedStats result; if (stats.empty()) { qWarning("No statistics found..."); } else { QString curCategory = category(stats[0].second, categorizeBy); // first category QString curSummarizeId; vector displayStats; for (size_t i = 0; i < stats.size(); ++i) { DisplayStat displayStat; displayStat.stat = stats[i].first; QString statCategory = category(stats[i].second, categorizeBy); if (statCategory != curCategory) { result.push_back(make_pair(curCategory, displayStats)); displayStats.clear(); curCategory = statCategory; } QString statSummarizeId = category(stats[i].second, summarizeBy); if (statSummarizeId != curSummarizeId) { displayStat.caption = statSummarizeId; displayStats.push_back(displayStat); curSummarizeId = statSummarizeId; } else { statIncrement(displayStats[displayStats.size()-1].stat, displayStat.stat); } } result.push_back(make_pair(curCategory, displayStats)); } return result; } QString myStrFTime(const time_t* timestamp, const char* format) { char dayString[1024]; struct tm time; localtime_r(timestamp, &time); strftime(dayString, sizeof(dayString), format, &time); return QString::fromUtf8(dayString); } QString StatsLogic::category(const AddInfo& addInfo, CategorizeType categorizeType) { QString result; switch (categorizeType) { case byExercise: result = qApp->translate("StatsLogic::category", "exercise #%1").arg(addInfo.exerciseNumber); break; case byDay: result = myStrFTime(&addInfo.timestamp, "%F"); break; case byWeek: result = myStrFTime(&addInfo.timestamp, "%Y,%V"); break; case byMonth: result = myStrFTime(&addInfo.timestamp, "%B %Y"); break; case byYear: result = myStrFTime(&addInfo.timestamp, "%Y"); break; case byAll: result = qApp->translate("StatsLogic::category", "all"); break; } return result; } void StatsLogic::logIncrement(stat_t& stat, size_t newValue) { const float koef = 1.7; stat = (stat * koef + newValue) / (koef + 1); } void StatsLogic::statIncrement(Stat& stat, const Stat& newStat) { stat.exerciseCount += 1; stat.symbolCount += newStat.symbolCount; stat.time += newStat.time; stat.combinations += newStat.combinations; stat.mistakes += newStat.mistakes; logIncrement(stat.mistakeAverage, newStat.mistakeAverage); logIncrement(stat.rhythmAverage, newStat.rhythmAverage); logIncrement(stat.speedAverage, newStat.speedAverage); } StatsLogic::stat_t StatsLogic::Stat::index() const { using std::min; using std::max; const stat_t indexPercent = 10; const stat_t speedIndexMax = indexPercent*40; const stat_t mistakeIndexMax = indexPercent*30; const stat_t rhythmIndexMax = indexPercent*15; const stat_t exerciseCountIndexMax = indexPercent*5; const stat_t symbolCountIndexMax = indexPercent*10; stat_t exerciseCountIndex = (this->exerciseCount) / 10; stat_t symbolCountIndex = (this->symbolCount) / 1000; stat_t speedIndex = (this->speedAverage) / 2; stat_t rhythmIndex = (this->rhythmAverage) / 100 * rhythmIndexMax; stat_t mistakeIndex = (mistakeIndexMax) - this->mistakeAverage*indexPercent*5; stat_t index = 0; index += min(exerciseCountIndex, exerciseCountIndexMax); index += min(symbolCountIndex, symbolCountIndexMax); index += min(speedIndex, speedIndexMax); index += rhythmIndex; index += max(0.0f, mistakeIndex); Q_ASSERT(index > 0.0 && index < 1000.0); return index; } const vector& StatsLogic::categorizeInfo() const { return myCategorizeInfo; } void StatsLogic::initCategorizeInfo() { myCategorizeInfo.push_back(CategorizeInfo(byExercise, qApp->translate("StatsWidget::initCagegorizeInfo", "exercise"))); myCategorizeInfo.push_back(CategorizeInfo(byDay, qApp->translate("StatsWidget::initCagegorizeInfo", "day"))); myCategorizeInfo.push_back(CategorizeInfo(byWeek, qApp->translate("StatsWidget::initCagegorizeInfo", "week"))); myCategorizeInfo.push_back(CategorizeInfo(byMonth, qApp->translate("StatsWidget::initCagegorizeInfo", "month"))); myCategorizeInfo.push_back(CategorizeInfo(byYear, qApp->translate("StatsWidget::initCagegorizeInfo", "year"))); myCategorizeInfo.push_back(CategorizeInfo(byAll, qApp->translate("StatsWidget::initCagegorizeInfo", "all"))); } nlkt-0.3.2.2/src/StatsLogic.hpp000066400000000000000000000052751173762012600162160ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef STATS_LOGIC_HPP #define STATS_LOGIC_HPP #include #include #include "UserProfile.hpp" using std::pair; class StatsLogic { public: StatsLogic(const UserProfile& profile); //typedef int Stat; typedef float stat_t; typedef int plot_caption_t; struct Stat { stat_t exerciseCount; stat_t mistakeAverage; stat_t rhythmAverage; stat_t speedAverage; stat_t symbolCount; stat_t time; QStringList mistakes; QStringList combinations; stat_t index() const; }; struct DisplayStat { Stat stat; QString caption; }; struct AddInfo { time_t timestamp; size_t exerciseNumber; }; enum CategorizeType { byExercise, byDay, byWeek, byMonth, byYear, byAll }; struct CategorizeInfo { CategorizeType type; QString caption; CategorizeInfo(CategorizeType type, const QString& caption) : type(type), caption(caption) {} }; const vector& categorizeInfo() const; typedef vector< pair< QString, vector > > CategorizedStats; CategorizedStats categorize(CategorizeType categorizeBy, CategorizeType summarizeBy); private: void initCategorizeInfo(); QString category(const AddInfo& addInfo, CategorizeType); void logIncrement(stat_t& stat, size_t newValue); void statIncrement(Stat& stat, const Stat& newStat); const UserProfile& profile; vector< pair > stats; vector myCategorizeInfo; }; #endif nlkt-0.3.2.2/src/StatsWidget.cpp000066400000000000000000000442741173762012600164010ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "StatsWidget.hpp" #include "Setup.hpp" StatsWidget::StatsWidget(const UserProfile& profile, QWidget* parent) : QDialog(parent), statsLogic(profile), profilePath(profile.getPath()) { QDialogButtonBox* okButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok); connect(okButtonBox, SIGNAL(accepted()), this, SLOT(accept())); initTable(); initPlots(); QLabel* categorizeByLabel = new QLabel(tr("Categorize by:")); QLabel* summarizeByLabel = new QLabel(tr("Summarize by:")); QLabel* categoryLabel = new QLabel(tr("Category:")); initCombos(); QHBoxLayout* topLayout = new QHBoxLayout; topLayout->addWidget(categorizeByLabel); topLayout->addWidget(this->categorizeByCombo, 1); topLayout->addWidget(summarizeByLabel); topLayout->addWidget(this->summarizeByCombo, 1); topLayout->addWidget(categoryLabel); topLayout->addWidget(this->categoryCombo, 1); QHBoxLayout* checkBoxesLayout = new QHBoxLayout; checkBoxesLayout->addWidget(this->showGridsOnPlotsCheckBox); checkBoxesLayout->addWidget(this->setMinimumYValueOnPlotsToZeroCheckBox); QGridLayout* plotLayout = new QGridLayout; plotLayout->addLayout(checkBoxesLayout, 0, 0, 1, -1); plotLayout->addWidget(this->exerciseCountPlot, 1, 0); plotLayout->addWidget(this->symbolCountPlot, 2, 0); plotLayout->addWidget(this->timePlot, 1, 1); plotLayout->addWidget(this->speedAveragePlot, 2, 1); plotLayout->addWidget(this->mistakeAveragePlot, 1, 2); plotLayout->addWidget(this->rhythmAveragePlot, 2, 2); plotLayout->addWidget(this->indexPlot, 3, 0, 1, -1); plotLayout->setRowStretch(0, 0); plotLayout->setRowStretch(1, 3); plotLayout->setRowStretch(2, 3); plotLayout->setRowStretch(3, 4); QWidget* plotsTabWidget = new QWidget; plotsTabWidget->setLayout(plotLayout); QDialogButtonBox* tableButtonsWidget = new QDialogButtonBox; tableButtonsWidget->addButton(this->scrollDownStatsTableButton, QDialogButtonBox::ActionRole); QVBoxLayout* tableTabLayout = new QVBoxLayout; tableTabLayout->addWidget(this->statsTable); tableTabLayout->addWidget(tableButtonsWidget); QWidget* tableTabWidget = new QWidget; tableTabWidget->setLayout(tableTabLayout); initCombinationsAndMistakesTables(); this->tabs = new QTabWidget; this->tabs->addTab(tableTabWidget, tr("Table")); this->tabs->addTab(plotsTabWidget, tr("Plots")); this->tabs->addTab(this->mistakesTable, tr("Mistakes")); this->tabs->addTab(this->combinationsTable, tr("Combinations")); QVBoxLayout* layout = new QVBoxLayout; layout->addLayout(topLayout); layout->addWidget(tabs); layout->addWidget(okButtonBox); this->setLayout(layout); this->initPlotsFormat(); //this->renewStatsViews(); this->setWindowTitle(tr("Statistics")); this->readGuiSettings(); connect(this, SIGNAL(finished(int)), this, SLOT(writeGuiSettings())); } void StatsWidget::initTable() { this->statsTable = new QTableWidget; this->statsTable->setColumnCount(7); QStringList captions; captions << tr("Exercise count") << tr("Symbol count") << tr("Time, sec.") << tr("Speed average, symb./sec.") << tr("Mistake average") << tr("Rhythm average, %") << tr("Index") ; this->statsTable->setHorizontalHeaderLabels(captions); this->statsTable->resizeColumnsToContents(); this->scrollDownStatsTableButton = new QPushButton(tr("Scroll down")); QString scrollDownKeySequence("Ctrl+J"); this->scrollDownStatsTableButton->setShortcut(QKeySequence(scrollDownKeySequence)); this->scrollDownStatsTableButton->setToolTip(scrollDownKeySequence); connect(this->scrollDownStatsTableButton, SIGNAL(clicked()), this->statsTable, SLOT(scrollToBottom())); } void StatsWidget::initPlots() { this->exerciseCountPlot = new QwtPlot(tr("Exercise count")); this->exerciseCountCurve = new QwtPlotCurve(); this->exerciseCountCurve->setPen(QPen(Qt::yellow)); this->exerciseCountCurve->attach(exerciseCountPlot); this->symbolCountPlot = new QwtPlot(tr("Symbol count")); this->symbolCountCurve = new QwtPlotCurve(); this->symbolCountCurve->setPen(QPen(Qt::blue)); this->symbolCountCurve->attach(symbolCountPlot); this->timePlot = new QwtPlot(tr("Time, sec.")); this->timeCurve = new QwtPlotCurve(); this->timeCurve->setPen(QPen(Qt::cyan)); this->timeCurve->attach(timePlot); this->speedAveragePlot = new QwtPlot(tr("Speed average, symb./sec.")); this->speedAverageCurve = new QwtPlotCurve(); this->speedAverageCurve->setPen(QPen(Qt::red)); this->speedAverageCurve->attach(speedAveragePlot); this->mistakeAveragePlot = new QwtPlot(tr("Mistake average")); this->mistakeAverageCurve = new QwtPlotCurve(); this->mistakeAverageCurve->setPen(QPen(Qt::magenta)); this->mistakeAverageCurve->attach(mistakeAveragePlot); this->rhythmAveragePlot = new QwtPlot(tr("Rhythm average, %")); this->rhythmAverageCurve = new QwtPlotCurve(); this->rhythmAverageCurve->setPen(QPen(Qt::green)); this->rhythmAverageCurve->attach(rhythmAveragePlot); this->indexPlot = new QwtPlot(tr("Index")); this->indexCurve = new QwtPlotCurve(); this->indexCurve->setPen(QPen(Qt::darkCyan)); this->indexCurve->attach(indexPlot); this->showGridsOnPlotsCheckBox = new QCheckBox(tr("Show grids on plots")); connect(this->showGridsOnPlotsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(renewGridsOnPlots())); this->setMinimumYValueOnPlotsToZeroCheckBox = new QCheckBox(tr("Set minimum Y value to 0")); // this slot updates plots as part of its work connect(this->setMinimumYValueOnPlotsToZeroCheckBox, SIGNAL(stateChanged(int)), this, SLOT(renewCategoryView())); } void StatsWidget::initPlotsFormat() { foreach (QwtPlot* plot, this->findChildren()) { plot->setMinimumSize(200, 150); QFont font = plot->titleLabel()->font(); font.setPointSize(10); plot->titleLabel()->setFont(font); plot->enableAxis(QwtPlot::xBottom, false); plot->setAxisAutoScale(QwtPlot::yLeft); plot->setAxisMaxMajor(QwtPlot::yLeft, 6); plot->setAutoReplot(true); QwtPlotGrid* indexGrid = new QwtPlotGrid; QPen indexGridPen; indexGridPen.setColor(QColor(128, 128, 128, 96)); indexGrid->setPen(indexGridPen); indexGrid->enableX(false); indexGrid->attach(plot); this->gridList.append(indexGrid); } QwtPlotCurve* curves[] = { this->exerciseCountCurve, this->symbolCountCurve, this->timeCurve, this->speedAverageCurve, this->mistakeAverageCurve, this->rhythmAverageCurve, this->indexCurve }; for (size_t i = 0; i < sizeof(curves)/sizeof(curves[0]); ++i) { curves[i]->setRenderHint(QwtPlotItem::RenderAntialiased); QPen pen = curves[i]->pen(); pen.setWidth(2); curves[i]->setPen(pen); QColor penColor = pen.color(); QColor brushColor(penColor.red(), penColor.green(), penColor.blue(), 64); curves[i]->setBrush(brushColor); } } void StatsWidget::initCombos() { this->categorizeByCombo = new QComboBox; connect(this->categorizeByCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(renewSummarizeByCombo())); this->summarizeByCombo = new QComboBox; connect(this->summarizeByCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(renewStatsViews())); this->categoryCombo = new QComboBox; connect(this->categoryCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(renewCategoryView())); const vector& categorizeInfo = statsLogic.categorizeInfo(); this->categorizeByCombo->blockSignals(true); for (size_t i = 1; i < categorizeInfo.size(); ++i) // except "by exercise" { this->categorizeByCombo->addItem(categorizeInfo[i].caption); } this->categorizeByCombo->blockSignals(false); } void StatsWidget::initCombinationsAndMistakesTables() { this->mistakesTable = new QTableWidget; this->mistakesTable->setColumnCount(2); QStringList mistakesTableHorizontalHeaders; mistakesTableHorizontalHeaders << tr("Mistake") << tr("Count") ; this->mistakesTable->setHorizontalHeaderLabels(mistakesTableHorizontalHeaders); this->combinationsTable = new QTableWidget; this->combinationsTable->setColumnCount(2); QStringList combinationsTableHorizontalHeaders; combinationsTableHorizontalHeaders << tr("Combination") << tr("Count") ; this->combinationsTable->setHorizontalHeaderLabels(combinationsTableHorizontalHeaders); } void StatsWidget::renewStatsViews() { qDebug("StatsWidget::renewStatsViews()"); StatsLogic::CategorizeType categorizeType = statsLogic.categorizeInfo()[this->categorizeByCombo->currentIndex() + 1].type; StatsLogic::CategorizeType summarizeType = statsLogic.categorizeInfo()[this->summarizeByCombo->currentIndex()].type; this->cachedStats = statsLogic.categorize( categorizeType, summarizeType); if (this->cachedStats.empty()) { this->categoryCombo->setEnabled(false); this->statsTable->setEnabled(false); foreach (QwtPlot* plot, this->findChildren()) { plot->setEnabled(false); } } else { this->categoryCombo->blockSignals(true); this->categoryCombo->setEnabled(true); this->categoryCombo->clear(); for (size_t i = 0; i < cachedStats.size(); ++i) { this->categoryCombo->addItem(cachedStats[i].first); } this->categoryCombo->blockSignals(false); foreach (QwtPlot* plot, this->findChildren()) { plot->setEnabled(true); } this->statsTable->setEnabled(true); this->renewCategoryView(); } } void StatsWidget::renewCategoryView() { int categoryIndex = this->categoryCombo->currentIndex(); qDebug("StatsWidget::renewCategoryView(): categoryIndex=%d", categoryIndex); const vector* categoryStatsPointer = &cachedStats[categoryIndex].second; size_t size = categoryStatsPointer->size(); // updating common table { this->statsTable->setRowCount(size); for (size_t i = 0; i < size; ++i) { const StatsLogic::DisplayStat& displayStat = (*categoryStatsPointer)[i]; this->statsTable->setItem(i, 0, new QTableWidgetItem( QString::number(displayStat.stat.exerciseCount))); this->statsTable->setItem(i, 1, new QTableWidgetItem( QString::number(displayStat.stat.symbolCount))); this->statsTable->setItem(i, 2, new QTableWidgetItem( QString::number(displayStat.stat.time, 'f', 1))); this->statsTable->setItem(i, 3, new QTableWidgetItem( QString::number(displayStat.stat.speedAverage, 'f', 1))); this->statsTable->setItem(i, 4, new QTableWidgetItem( QString::number(displayStat.stat.mistakeAverage, 'f', 1))); this->statsTable->setItem(i, 5, new QTableWidgetItem( QString::number(displayStat.stat.rhythmAverage, 'f', 1))); this->statsTable->setItem(i, 6, new QTableWidgetItem( QString::number(int(displayStat.stat.index())))); this->statsTable->setVerticalHeaderItem(i, new QTableWidgetItem(displayStat.caption)); } // settting items alignment int columnCount = this->statsTable->columnCount(); for (size_t i = 0; i < size; ++i) { for (int j = 0; j < columnCount; ++j) { this->statsTable->item(i, j)->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); } } StatsLogic::CategorizeType summarizeType = statsLogic.categorizeInfo()[this->summarizeByCombo->currentIndex()].type; this->statsTable->setColumnHidden(0, (summarizeType == StatsLogic::byExercise)); } // updating mistakes { QStringList mistakesList; for (size_t i = 0; i < size; ++i) { mistakesList += (*categoryStatsPointer)[i].stat.mistakes; } loadCountedStringsIntoTable(mistakesList, this->mistakesTable); } // updating combinations { QStringList combinationsList; for (size_t i = 0; i < size; ++i) { combinationsList += (*categoryStatsPointer)[i].stat.combinations; } loadCountedStringsIntoTable(combinationsList, this->combinationsTable); } // updating plots { size_t& plotSize = size; double* x = new double[plotSize]; for (size_t i = 0; i < plotSize; ++i) { x[i] = static_cast(i+1); } double* y = new double[plotSize]; #define NLKT_DISPLAY_STAT_EXT(STAT_STRING, STAT_VALUE) \ { \ double y_max = 0.0; \ for (size_t i = 0; i < plotSize; ++i) \ { \ y[i] = static_cast((*categoryStatsPointer)[i].stat. STAT_VALUE ); \ if (y[i] > y_max) \ { \ y_max = y[i]; \ } \ } \ this-> STAT_STRING##Curve->setSamples(x, y, plotSize); \ this-> STAT_STRING##Plot->axisScaleEngine(QwtPlot::yLeft)->setAttribute( \ QwtScaleEngine::IncludeReference, \ this->setMinimumYValueOnPlotsToZeroCheckBox->isChecked()); \ this-> STAT_STRING##Plot->setAxisScale(QwtPlot::xBottom, 1.0, static_cast(plotSize)); \ } #define NLKT_DISPLAY_STAT(STAT_STRING) NLKT_DISPLAY_STAT_EXT(STAT_STRING, STAT_STRING) NLKT_DISPLAY_STAT(exerciseCount) NLKT_DISPLAY_STAT(symbolCount) NLKT_DISPLAY_STAT(time) NLKT_DISPLAY_STAT(speedAverage) NLKT_DISPLAY_STAT(mistakeAverage) NLKT_DISPLAY_STAT(rhythmAverage) NLKT_DISPLAY_STAT_EXT(index, index()) #undef NLKT_DISPLAY_STAT #undef NLKT_DISPLAY_STAT_EXT delete [] x; delete [] y; } } void StatsWidget::renewSummarizeByCombo() { qDebug("StatsWidget::renewSummarizeByCombo"); this->summarizeByCombo->blockSignals(true); this->summarizeByCombo->clear(); const vector& categorizeInfo = statsLogic.categorizeInfo(); for (int i = 0; i <= this->categorizeByCombo->currentIndex(); ++i) { this->summarizeByCombo->addItem(categorizeInfo[i].caption); } this->summarizeByCombo->setCurrentIndex(0); // one item - "by exercise" - exists anyway this->summarizeByCombo->blockSignals(false); this->renewStatsViews(); } void StatsWidget::writeGuiSettings() { QSettings settings; settings.beginGroup("StatsWidget"); settings.setValue("pos", pos()); settings.setValue("size", size()); settings.setValue("show_grids", this->showGridsOnPlotsCheckBox->isChecked()); settings.setValue("set_min_y_zero", this->setMinimumYValueOnPlotsToZeroCheckBox->isChecked()); settings.beginGroup(profilePath); settings.setValue("tab_index", this->tabs->currentIndex()); settings.setValue("categorize_index", this->categorizeByCombo->currentIndex()); settings.setValue("summarize_index", this->summarizeByCombo->currentIndex()); settings.setValue("category_index", this->categoryCombo->currentIndex()); settings.endGroup(); settings.endGroup(); } void StatsWidget::readGuiSettings() { QSettings settings; settings.beginGroup("StatsWidget"); QPoint badPos(-1, -1); QPoint savedPoint = settings.value("pos", badPos).toPoint(); if (savedPoint != badPos) { // this is avanturistic way to provide correct geometry restroing on X11 :( QRect geom = this->geometry(); this->setGeometry(savedPoint.x(), savedPoint.y(), geom.width(), geom.height()); } this->resize(settings.value("size", QSize(760, 560)).toSize()); this->showGridsOnPlotsCheckBox->blockSignals(true); this->showGridsOnPlotsCheckBox->setChecked(settings.value("show_grids").toBool()); this->showGridsOnPlotsCheckBox->blockSignals(false); this->renewGridsOnPlots(); this->setMinimumYValueOnPlotsToZeroCheckBox->blockSignals(true); this->setMinimumYValueOnPlotsToZeroCheckBox->setChecked(settings.value("set_min_y_zero").toBool()); this->setMinimumYValueOnPlotsToZeroCheckBox->blockSignals(false); settings.beginGroup(profilePath); this->tabs->setCurrentIndex(settings.value(("tab_index"), 0).toInt()); int categorizeByIndex = settings.value("categorize_index", this->categorizeByCombo->count() - 1).toInt(); this->categorizeByCombo->blockSignals(true); this->categorizeByCombo->setCurrentIndex(categorizeByIndex); this->categorizeByCombo->blockSignals(false); this->renewSummarizeByCombo(); int summarizeByIndex = settings.value("summarize_index", 0).toInt(); this->summarizeByCombo->setCurrentIndex(summarizeByIndex); int categoryIndex = settings.value("category_index", this->categoryCombo->count() - 1).toInt(); this->categoryCombo->setCurrentIndex(categoryIndex); settings.endGroup(); settings.endGroup(); } void StatsWidget::loadCountedStringsIntoTable(const QStringList& strings, QTableWidget* tableWidget) { QMap stringsMap; foreach (const QString str, strings) { stringsMap[str] += 1; } tableWidget->setRowCount(stringsMap.size()); QMultiMap countedStringsMap; { QMap::const_iterator cit; for (cit = stringsMap.constBegin(); cit != stringsMap.constEnd(); ++cit) { countedStringsMap.insert(cit.value(), cit.key()); } } { int i = tableWidget->rowCount() - 1; QMultiMap::const_iterator cit; for (cit = countedStringsMap.constBegin(); cit != countedStringsMap.constEnd(); ++cit, --i) { tableWidget->setItem(i, 0, new QTableWidgetItem(cit.value())); tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(cit.key()))); } } } void StatsWidget::renewGridsOnPlots() { qDebug("renewGridsOnPlots"); bool visible = this->showGridsOnPlotsCheckBox->isChecked(); foreach (QwtPlotGrid* grid, this->gridList) { grid->setVisible(visible); } } nlkt-0.3.2.2/src/StatsWidget.hpp000066400000000000000000000055731173762012600164050ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include "StatsLogic.hpp" class UserProfile; class QComboBox; class QTableWidget; class QTabWidget; class QCheckBox; class QPushButton; class QwtPlot; class QwtPlotCurve; class QwtPlotGrid; class StatsWidget: public QDialog { Q_OBJECT public: StatsWidget(const UserProfile& profile, QWidget* parent = NULL); private slots: void renewStatsViews(); void renewCategoryView(); void renewSummarizeByCombo(); void renewGridsOnPlots(); void writeGuiSettings(); private: QComboBox* categorizeByCombo; QComboBox* summarizeByCombo; QComboBox* categoryCombo; QTabWidget* tabs; QTableWidget* statsTable; QTableWidget* mistakesTable; QTableWidget* combinationsTable; QwtPlot* exerciseCountPlot; QwtPlot* symbolCountPlot; QwtPlot* timePlot; QwtPlot* speedAveragePlot; QwtPlot* mistakeAveragePlot; QwtPlot* rhythmAveragePlot; QwtPlot* indexPlot; QwtPlotCurve* exerciseCountCurve; QwtPlotCurve* symbolCountCurve; QwtPlotCurve* timeCurve; QwtPlotCurve* speedAverageCurve; QwtPlotCurve* mistakeAverageCurve; QwtPlotCurve* rhythmAverageCurve; QwtPlotCurve* indexCurve; QCheckBox* setMinimumYValueOnPlotsToZeroCheckBox; QCheckBox* showGridsOnPlotsCheckBox; QList gridList; QPushButton* scrollDownStatsTableButton; StatsLogic statsLogic; StatsLogic::CategorizedStats cachedStats; const QString profilePath; void initTable(); void initPlots(); void initPlotsFormat(); void initCombos(); void initCombinationsAndMistakesTables(); void readGuiSettings(); static void loadCountedStringsIntoTable(const QStringList& strings, QTableWidget* tableWidget); }; nlkt-0.3.2.2/src/UserProfile.cpp000066400000000000000000000157221173762012600163720ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include "UserProfile.hpp" #include "Setup.hpp" const QString delimiter = "|"; QString ExerciseResult::toString() const { QString result; result += QString::number(timestamp); result += delimiter + QString::number(symbolCount); result += delimiter + QString::number(millisecsSpent); result += delimiter + worseTriLetter; result += delimiter + QString::number(rhythmPercent); for (int i = 0; i < mistakes.size(); ++i) { result += delimiter; result += mistakes[i]; } return result; } ExerciseResult ExerciseResult::fromString(const QString& dump) { QStringList strings = dump.split(delimiter); ExerciseResult result; int z = 0; result.timestamp = strings.at(z++).toULong(); result.symbolCount = strings.at(z++).toULong(); result.millisecsSpent = strings.at(z++).toULong(); result.worseTriLetter = strings.at(z++); result.rhythmPercent = strings.at(z++).toULong(); for (int i = z; i < strings.size(); ++i) { result.mistakes.push_back(strings.at(i)); } return result; } UserProfile::UserProfile(const QString& profilePath) : path(profilePath) { QFile fin(profilePath); if (!fin.open(QIODevice::ReadOnly | QIODevice::Text)) { qFatal("Cannot load the profile %s", qPrintable(path)); } QTextStream in(&fin); in.setCodec("UTF-8"); this->layoutString = in.readLine(); this->layout.read(pathToLayouts + this->layoutString); QString tmp; while (!(in.atEnd())) { tmp = in.readLine(); if (!(tmp.isEmpty())) { this->exerciseResults.push_back(ExerciseResult::fromString(tmp)); } } fin.close(); } void UserProfile::exerciseDone(const ExerciseResult& exerciseResult) { exerciseResults.push_back(exerciseResult); QFile fout(path); if (!fout.open(QIODevice::Append | QIODevice::Text)) { qFatal("Cannot renew the profile %s", qPrintable(path)); } QTextStream out(&fout); out.setCodec("UTF-8"); out << exerciseResult.toString() << endl; fout.close(); } const vector& UserProfile::exercises() const { return exerciseResults; } QString UserProfile::getFortuneArgumentsLine() const { return layout.getLayoutFortuneParam(); } QString UserProfile::getLayoutString() const { return layoutString; } const Layout& UserProfile::getLayout() const { return layout; } size_t UserProfile::getTotalSecondCount() const { size_t result = 0; for (size_t i = 0; i < exerciseResults.size(); ++i) { result += exerciseResults[i].millisecsSpent; } return result / 1000; } size_t UserProfile::getTotalMistakeCount() const { size_t result = 0; for (size_t i = 0; i < exerciseResults.size(); ++i) { result += exerciseResults[i].mistakes.size(); } return result / 2; // mistakes are stored by pairs } size_t UserProfile::getTotalSymbolCount() const { size_t result = 0; for (size_t i = 0; i < exerciseResults.size(); ++i) { result += exerciseResults[i].symbolCount; } return result; } QString UserProfile::getGeneralStats() const { size_t exerciseCount = this->exercises().size(); float averageMistakes = exerciseCount ? static_cast(this->getTotalMistakeCount()) / exerciseCount : 0; size_t secondCount = this->getTotalSecondCount(); QTime time(0, 0); time = time.addSecs(secondCount); QString timeString = time.toString(QString("hh:mm:ss")); if (size_t days = secondCount/24/60/60) { timeString.prepend(QString("%1d ").arg(days)); } float averageTypingSpeed = secondCount ? static_cast(this->getTotalSymbolCount() * 60 / secondCount) : 0; QString generalTip = QCoreApplication::translate("UserProfile", "%7" "Keyboard layout: %1" "Exercises done: %2" "Symbols typed: %3" "Time spent: %4" "Average mistake count by exercise: %5" "Average typing speed: %6" ) .arg( "%1
", "%2
", "%3
", "%4
", "%L5
", "%6", "
%7

") .arg(this->getLayoutString()) .arg(exerciseCount) .arg(this->getTotalSymbolCount()) .arg(timeString) .arg(averageMistakes, 0, 'f', 2) .arg(averageTypingSpeed) .arg(path.mid(path.lastIndexOf(QChar('/')) + 1)); return generalTip; } enum UserProfile::ConstructNewProfileResult UserProfile::constructNewProfile(const QString& newProfileName, const QString& layout) { qDebug() << "Constructing new profile" << newProfileName << "with layout" << layout; QFile profileFile(pathToUserProfiles + newProfileName); QFile defaultCombinationFile(pathToDefaultProfiles + layout); if (!defaultCombinationFile.open(QIODevice::ReadOnly | QIODevice::Text)) { return CombinationError; } else if (profileFile.open(QIODevice::ReadOnly | QIODevice::Text)) { return ProfileExists; } else { profileFile.open(QIODevice::WriteOnly | QIODevice::Text); QTextStream combinationFileStream(&defaultCombinationFile); QTextStream profileFileStream(&profileFile); QString defaultCombination = combinationFileStream.readLine(); profileFileStream << layout << endl; profileFileStream << QString::number(time(NULL)) << delimiter << "0" << delimiter << "0" << delimiter << defaultCombination << delimiter << "0" << endl; return Ok; } } QString UserProfile::getPath() const { return path; } bool UserProfile::isCorrectProfile(const QString& profilePath) { QFile fin(profilePath); if (!fin.open(QIODevice::ReadOnly | QIODevice::Text)) { qCritical("Failed to read the existing file %s", qPrintable(profilePath)); return false; } QTextStream in(&fin); QString layoutString = in.readLine(); if (QFile::exists(pathToLayouts + layoutString)) { return true; } else { qCritical("Layout %s doesn't exist.", qPrintable(layoutString)); return false; } } nlkt-0.3.2.2/src/UserProfile.hpp000066400000000000000000000050511173762012600163710ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_USER_PROFILE_HPP #define yf_USER_PROFILE_HPP #include #include #include #include "Layout.hpp" using std::vector; struct ExerciseResult { size_t symbolCount; size_t millisecsSpent; QString worseTriLetter; QStringList mistakes; size_t rhythmPercent; time_t timestamp; QString toString() const; static ExerciseResult fromString(const QString& dump); }; class UserProfile { public: UserProfile(const QString& profilePath); QString getPath() const; const Layout& getLayout() const; QString getLayoutString() const; QString getFortuneArgumentsLine() const; const vector& exercises() const; QString getGeneralStats() const; size_t getTotalSecondCount() const; size_t getTotalSymbolCount() const; size_t getTotalMistakeCount() const; void exerciseDone(const ExerciseResult& exerciseResult); enum ConstructNewProfileResult { Ok, ProfileExists, CombinationError, OtherError}; static enum ConstructNewProfileResult constructNewProfile(const QString& newProfileName, const QString& layout); static bool isCorrectProfile(const QString& profilePath); private: vector exerciseResults; Layout layout; QString layoutString; // "ru", "en", "en-dvorak" etc... const QString path; }; #endif nlkt-0.3.2.2/src/main.cpp000066400000000000000000000104031173762012600150460ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include #include #include #include #include #include "MainWidget.hpp" #include "ProfileManager.hpp" #include "FortunesGetter.hpp" #include "UserProfile.hpp" #include "Logic.hpp" #include "Setup.hpp" const int programResultOtherInstance = 1; int main(int argc, char* argv[]) { QApplication app(argc, argv); QCoreApplication::setOrganizationName("jackyf"); QCoreApplication::setApplicationName(programName); QDir::setCurrent(QCoreApplication::applicationDirPath()); // installing translators QTranslator myTranslator; myTranslator.load("nlkt_" + QLocale::system().name(), pathToTranslations); app.installTranslator(&myTranslator); // creating dirs if necessary QString previousPath = QDir::currentPath(); QDir newDir; newDir.mkpath(pathToUserProfiles); QDir::setCurrent(previousPath); // checking for other instances if (!system("test `pgrep -u $(id -u) nlkt | wc -l` -gt 1")) { QMessageBox::critical(NULL, QCoreApplication::translate("main", "Other instance exists"), QCoreApplication::translate("main", "You are already running other instance of this program.")); return programResultOtherInstance; } QString profile; ProfileManager profileManager(profile); profileManager.show(); app.exec(); profileManager.hide(); qDebug("selected profile = %s", qPrintable(profile)); if (profile != QString()) { UserProfile userProfile(pathToUserProfiles + profile); FortunesGetter fortunesGetter(userProfile); Logic logic(fortunesGetter, userProfile); yf::random::rnd_init(); MainWidget window(userProfile); QObject::connect(&window, SIGNAL(startExercise()), &logic, SLOT(startExercise())); QObject::connect(&window, SIGNAL(terminateExercise()), &logic, SLOT(terminateExercise())); QObject::connect(&window, SIGNAL(typedSymbol()), &logic, SLOT(typedSymbol()), Qt::QueuedConnection); QObject::connect(&window, SIGNAL(errorOnSymbol()), &logic, SLOT(errorOnSymbol()), Qt::QueuedConnection); QObject::connect(&logic, SIGNAL(startTyping(const QString&, const QString&)), &window, SLOT(startTyping(const QString&, const QString&))); QObject::connect(&logic, SIGNAL(mistakeCount(int)), &window, SLOT(mistakeCount(int))); QObject::connect(&logic, SIGNAL(maxMistakeCount(int)), &window, SLOT(maxMistakeCount(int))); QObject::connect(&logic, SIGNAL(endTyping()), &window, SLOT(endTyping())); QObject::connect(&logic, SIGNAL(tooManyMistakes()), &window, SLOT(tooManyMistakes())); QObject::connect(&logic, SIGNAL(exerciseFinished(const ExerciseResult&)), &window, SLOT(exerciseFinished(const ExerciseResult&))); QObject::connect(&logic, SIGNAL(wait(int)), &window, SLOT(displayWaitMessage(int))); QObject::connect(qApp, SIGNAL(aboutToQuit()), &window, SLOT(writeGuiSettings())); window.setWindowTitle(QString("nlkt - ") + QObject::tr("non-linear keyboard trainer")); window.show(); return app.exec(); } else { return 255; } } //TODO: implement levels nlkt-0.3.2.2/src/nlkt.pro000066400000000000000000000023421173762012600151130ustar00rootroot00000000000000###################################################################### # Automatically generated by qmake (2.01a) Sun Sep 9 19:56:24 2007 ###################################################################### TEMPLATE = app TARGET = DEPENDPATH += . DEFINES += NDEBUG LIBS += -lqwt INCLUDEPATH += /usr/include/qwt CONFIG += debug_and_release unix { DEFINES += __LINUX } win32 { DEFINES += WIN32 } QMAKE_CXXFLAGS += $(PATH_CFG) QMAKE_CXXFLAGS_RELEASE += -DQT_NO_DEBUG_OUTPUT QMAKE_LFLAGS += -Wl,--as-needed # Input HEADERS += \ KeyboardWidget.hpp \ RichboxWidget.hpp \ MainWidget.hpp \ FortunesGetter.hpp \ Logic.hpp \ Layout.hpp \ UserProfile.hpp \ ProfileManager.hpp \ StatsWidget.hpp \ StatsLogic.hpp \ yf/defs.hpp \ yf/time/time.hpp \ yf/random/random.hpp SOURCES += \ KeyboardWidget.cpp \ RichboxWidget.cpp \ MainWidget.cpp \ FortunesGetter.cpp \ Logic.cpp \ Layout.cpp \ UserProfile.cpp \ ProfileManager.cpp \ StatsWidget.cpp \ StatsLogic.cpp \ main.cpp \ yf/time/time.cpp \ yf/random/random.cpp TRANSLATIONS = \ ../share/translations/nlkt_ru.ts \ ../share/translations/nlkt_uk.ts # install share.path = /usr/share/nlkt share.files = ../share/* INSTALLS += share target.path = /usr/bin INSTALLS += target nlkt-0.3.2.2/src/yf/000077500000000000000000000000001173762012600140365ustar00rootroot00000000000000nlkt-0.3.2.2/src/yf/defs.hpp000066400000000000000000000120431173762012600154700ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #ifndef yf_defsHPP #define yf_defsHPP #define DEPRECATED // label for deprecated code #define EXPERIMENTAL // label for experimental code #define INCOMPLETE // label for incomplete code #ifndef NDEBUG #define YF_ENABLE_CHECKS #endif #if defined(__BORLANDC__) #define OS_WINDOWS #elif defined(WIN32) or defined(__WIN32) or defined(__WIN32__) #define OS_WINDOWS #elif defined(LINUX) or defined(__LINUX) or defined(__LINUX__) #define OS_LINUX #else #error You must specify you OS. Now supported next ones: WIN32, LINUX. #endif /* #if not defined(YF_CODE_32) and not defined(YF_CODE_64) #error You must specify you your system bitness (YF_CODE_32 or YF_CODE_64) #endif */ #ifdef __LP64__ #define YF_CODE_64 #else #define YF_CODE_32 #endif #ifdef OS_WINDOWS #include #endif //------------------------------------------------------------------------------ // define YF_ENABLE_CHECKS if you want to verify exceptions in some classes... // define USE_YFSTRING if you want to use yf::sstring instead of std::string //------------------------------------------------------------------------------ typedef unsigned long ulong; // 4/8 bytes typedef unsigned int uint; // 4 bytes typedef unsigned short ushort; // 2 bytes typedef unsigned char byte; // 1 bytes typedef unsigned long long ullong; // 8 bytes typedef long long llong; // 8 bytes typedef long double ldouble; // 10 bytes typedef byte uint8; #ifdef YF_CODE_64 typedef unsigned short uint16; typedef unsigned int uint32; typedef unsigned long uint64; typedef short sint16; typedef int sint32; typedef long sint64; #else /* YF_CODE_32 */ typedef unsigned short uint16; typedef unsigned long uint32; typedef unsigned long long uint64; typedef short sint16; typedef long sint32; typedef long long sint64; #endif namespace yf { const byte LONG_DEC_LEN = 11; DEPRECATED const byte NAME_LEN = 50; const uint16 millisec_in_second = 1000; const byte sec_in_minute = 60; const byte min_in_hour = 60; const byte hour_in_day = 24; const byte max_byte = 0xFF ; const byte min_byte = 0x00 ; const char max_char = max_byte/2 ; const char min_char = -1 * (max_byte/2) - 1 ; const uint32 max_uint32 = 0xFFFFFFFF ; const uint32 min_uint32 = 0u ; const sint32 max_sint32 = max_uint32/2 ; const sint32 min_sint32 = -1 * (max_uint32/2) - 1 ; const uint16 max_uint16 = 0xFFFF ; const uint16 min_uint16 = 0 ; const sint16 max_sint16 = max_uint16/2 ; const sint16 min_sint16 = -1 * (max_uint16/2) - 1 ; #if (__GNUC__>4) const uint64 max_uint64 = 0xFFFFFFFFFFFFFFFF ; #else const uint64 max_uint64 = (max_uint64)-1; #endif const uint64 min_uint64 = 0 ; //------------------------------------------------------------------------------ const ushort bits_in_byte = 8; DEPRECATED const ushort bits_in_short = bits_in_byte * 2; DEPRECATED const ushort bits_in_long = bits_in_byte * 4; DEPRECATED const ushort bits_in_llong = bits_in_byte * 8; //------------------------------------------------------------------------------ DEPRECATED const ushort byte_size = 1ul; DEPRECATED const ushort short_size = bits_in_short / bits_in_byte; DEPRECATED const ushort long_size = bits_in_long / bits_in_byte; DEPRECATED const ushort llong_size = bits_in_llong / bits_in_byte; //-------------------------------------------------------------- const size_t npos = (size_t)-1; //------------------------------------------------------------------------------ const size_t line_max = 255; //-------------------------------------------------------------- /* some inline auxiliary functions */ /** * @brief Inverts uint32 value to sint32 value * @param value Value to be inverted * @return Inverted value */ inline sint32 inv(uint32 value) { return -( (sint32)value ); } } #endif nlkt-0.3.2.2/src/yf/random/000077500000000000000000000000001173762012600153165ustar00rootroot00000000000000nlkt-0.3.2.2/src/yf/random/random.cpp000066400000000000000000000115231173762012600173040ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #include namespace yf { namespace random { void rnd_init() { #ifdef YF_ENABLE_CHECKS try { #endif std::time_t tmp_time_struct; std::srand((unsigned)std::time(&tmp_time_struct)); #ifdef YF_ENABLE_CHECKS } catch(...) { YF_FUNC_EXCEPTION( init ) } #endif } //------------------------------------------------------------------------------------ bool rnd_bool() { return (std::rand() & 1); } byte rnd_byte() { return std::rand() % yf::max_byte; } //-------------------------------------------------------------- uint16 rnd_uint16(uint16 border) { #ifdef YF_ENABLE_CHECKS if (border == 0) { YF_FUNC_EXCEPTION(domain) } #endif return rnd_uint32(border); } sint16 rnd_sint16(uint16 border) { #ifdef YF_ENABLE_CHECKS if (border > (uint16)max_sint16) { YF_FUNC_EXCEPTION(domain) } #endif return (rnd_bool() ? 1l : -1l) * rnd_uint16(border) ; } uint32 rnd_uint32(uint32 border) { #ifdef YF_ENABLE_CHECKS if (border == 0) { YF_FUNC_EXCEPTION( domain ) } #endif return static_cast(rnd_0_1() * border); } sint32 rnd_sint32(uint32 border) { #ifdef YF_ENABLE_CHECKS if (border > (uint32)max_sint32) { YF_FUNC_EXCEPTION(domain) } #endif return (rnd_bool() ? 1l : -1l) * rnd_uint32(border) ; } //-------------------------------------------------------------- uint16 rnd_uint16() { uint16 retv = rnd_byte(); retv <<= 8; retv += rnd_byte(); return retv; } sint16 rnd_sint16() { uint16 ush = rnd_uint16(); return reinterpret_cast(ush); } uint32 rnd_uint32() { uint32 retv = rnd_uint16(); retv <<= 16; retv += rnd_uint16(); return retv; } sint32 rnd_sint32() { uint32 ul = rnd_uint32(); return reinterpret_cast(ul); } uint64 rnd_uint64() { uint64 retv = rnd_uint32(); retv <<= 32; retv += rnd_uint32(); return retv; } //-------------------------------------------------------------- sint32 rnd_in_range(sint32 start, sint32 stop) { #ifdef YF_ENABLE_CHECKS if (start > stop) { YF_FUNC_MESSAGE_EXCEPTION(domain, "range start is greater than range end") } #endif return start + rnd_uint32(stop-start+1); } //-------------------------------------------------------------- double rnd_0_1() { double f_retv = static_cast(rnd_uint32()); f_retv /= max_uint32; return f_retv; } double rnd_double(double border) { #ifdef YF_ENABLE_CHECKS if (border < 0.0) { YF_FUNC_MESSAGE_EXCEPTION(domain, "border must be positive or 0") } #endif return rnd_0_1() * border; } //-------------------------------------------------------------- void rnd_mem(void* ptr, size_t size) { byte* mov_ptr = static_cast(ptr); for (size_t i = 0; i < size; ++i, ++mov_ptr) { *mov_ptr = rnd_byte(); } } //-------------------------------------------------------------- char rnd_decimal_digit() { return '0' + std::rand() % 10; } char rnd_small_latin_character() { return 'a' + std::rand() % 26; } char rnd_big_lation_character() { return 'A' + std::rand() % 26; } char rnd_latin_character() { return ( rnd_bool() ? rnd_big_lation_character() : rnd_small_latin_character() ); } //-------------------------------------------------------------- } // namespace random } // namespace yf //--------------------------------------------------------------------------- nlkt-0.3.2.2/src/yf/random/random.hpp000066400000000000000000000043441173762012600173140ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_RANDOM_HPP #define yf_RANDOM_HPP //--------------------------------------------------------------------------- #include #ifdef YF_ENABLE_CHECKS #include #endif //------------------------------------------------------------------------------ namespace yf { namespace random { void rnd_init(); bool rnd_bool(); byte rnd_byte(); uint16 rnd_uint16(uint16 border); sint16 rnd_sint16(uint16 border); uint32 rnd_uint32(uint32 border); sint32 rnd_sint32(uint32 border); uint16 rnd_uint16(); sint16 rnd_sint16(); uint32 rnd_uint32(); sint32 rnd_sint32(); uint64 rnd_uint64(); sint64 rnd_sint64(); sint32 rnd_in_range(sint32 start, sint32 stop); double rnd_0_1(); double rnd_double(double border); void rnd_mem(void* ptr, size_t size); char rnd_decimal_digit(); char rnd_small_latin_character(); char rnd_big_lation_character(); char rnd_latin_character(); } } #endif nlkt-0.3.2.2/src/yf/time/000077500000000000000000000000001173762012600147745ustar00rootroot00000000000000nlkt-0.3.2.2/src/yf/time/time.cpp000066400000000000000000000062131173762012600164400ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #include #include #ifdef YF_ENABLE_CHECKS #include #endif #include #include namespace yf { //-------------------------------------------------------------- precise_time_t precise_time() { #ifdef OS_WINDOWS precise_time_t mt; #ifdef YF_ENABLE_CHECKS BOOST_STATIC_ASSERT(sizeof(precise_time_t) == sizeof (LARGE_INTEGER)); #endif QueryPerformanceCounter((LARGE_INTEGER*)&mt); return mt; #elif defined(OS_LINUX) struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); return tv; #else #error yf::micro_time() - Unsupported OS #endif } //-------------------------------------------------------------- double get_micro_time( precise_time_t mt_beg, precise_time_t mt_end ) { #ifdef OS_WINDOWS double time = (double)( mt_end - mt_beg ); precise_time_t mt_freq; QueryPerformanceFrequency((LARGE_INTEGER*)&mt_freq); return time / (precise_time_t)mt_freq; #elif defined(OS_LINUX) ulong time; time = mt_end.tv_sec - mt_beg.tv_sec; time *= microsec_in_second; time += mt_end.tv_usec; time -= mt_beg.tv_usec; return (double)time / microsec_in_second; #else #error yf::get_micro_time() - Unsupported OS #endif } //------------------------------------------------------------------------------ void write_milli_time( precise_time_t mt_beg, precise_time_t mt_end, std::ostream& os ) { float time = get_milli_time( mt_beg, mt_end ); char buf[80]; sprintf( buf, "%2d min %.3f sec\n", (int)(time / sec_in_minute), std::fmod(time, sec_in_minute) ); os << buf; } //-------------------------------------------------------------- void write_micro_time( precise_time_t mt_beg, precise_time_t mt_end, std::ostream& os ) { char buf[80]; sprintf( buf, "%.6f sec\n", get_micro_time( mt_beg, mt_end ) ); os << buf; } } nlkt-0.3.2.2/src/yf/time/time.hpp000066400000000000000000000053621173762012600164510ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2005-2008 by Eugene V. Lyubimkin aka jackyf * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License * * (version 3 or above) as published by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU GPL * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * ***************************************************************************/ #ifndef yf_timeHPP #define yf_timeHPP #include #include #include #ifdef YF_ENABLE_CHECKS #include #endif #ifdef OS_LINUX #include #include #endif namespace yf { /** * @brief Cross-platform analog for sleep */ inline void wait( ulong milliseconds ) { #ifdef OS_LINUX usleep(milliseconds*1000); #else #ifdef OS_WINDOWS Sleep(milliseconds); #else #error yf::wait() - Unsupported OS #endif #endif } //-------------------------------------------------------------- //-------------------------------------------------------------- const ulong microsec_in_second = 1000000ul; #if defined(OS_WINDOWS) typedef ullong precise_time_t; #elif defined(OS_LINUX) typedef struct timeval precise_time_t; #endif //-------------------------------------------------------------- precise_time_t precise_time(); double get_micro_time( precise_time_t mt_beg, precise_time_t mt_end ); inline float get_milli_time( precise_time_t mt_beg, precise_time_t mt_end ) { return (float)get_micro_time(mt_beg, mt_end); } //-------------------------------------------------------------- void write_milli_time( precise_time_t mt_beg, precise_time_t mt_end, std::ostream& os = std::cout ); void write_micro_time( precise_time_t mt_beg, precise_time_t mt_end, std::ostream& os = std::cout ); } //--------------------------------------------------------------------------- #endif