Import of original sourcecode for afutrainer-3.0

Original source: http://www.oliver-saal.de/software/afutrainer/download/afutrainer-3.0-src.zip
Landing page: http://www.oliver-saal.de/software/afutrainer/download.php
092d114b47e40472238e27ee01a528a58ad2d311ec95280b404bb57c97c9fed6  afutrainer-3.0-src.zip
This commit is contained in:
Sebastian Lohff 2022-06-30 01:04:57 +02:00
commit 9f1d3c81d2
115 changed files with 18511 additions and 0 deletions

3066
APPNOTE.TXT Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
Hinweis: Wenn HTML in Tags erlaubt ist, wird darauf explizit hingewiesen.
HTML wird dann entweder in CDATA-Blöcke (wie <![CDATA[ <b>fette Schrift</b> ]]>) gepackt
oder mit &lt; codiert (<answertext correct="true">42*10&lt;sup>-3&lt;/sup> A.</answertext>).
-->
<!ELEMENT afutrainer (title,publisher,version,valid,contact,comment?,options?,exam*,hint*,chapter+)>
<!-- Version des AFUTrainer-Formats - hier: 3.0 -->
<!ATTLIST afutrainer version (3.0) #REQUIRED>
<!-- Datum, an dem diese XML-Datei erstellt wurde. -->
<!ATTLIST afutrainer created CDATA #REQUIRED>
<!-- Titel (ausführlich/lang) des Fragenkatalogs -->
<!ELEMENT title (#PCDATA)>
<!-- Kurzbezeichnung des Fragenkatalogs -->
<!ATTLIST title short CDATA #IMPLIED>
<!-- unique wird benötigt, um Lernstatistiken unabh. vom Dateinamen
und eindeutig auf dem System abzuspeichern -->
<!ATTLIST title unique CDATA #REQUIRED>
<!-- Angaben zum Original-Fragenkatalog, Urheber: (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT publisher (#PCDATA)>
<!-- Version/Auflage des Original-Fragenkataloges (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT version (#PCDATA)>
<!-- Original-Versions-Datum -->
<!ATTLIST version published CDATA #REQUIRED>
<!-- Gültigkeitszeitraum des Katalogs -->
<!ELEMENT valid EMPTY>
<!ATTLIST valid from CDATA #REQUIRED>
<!ATTLIST valid until CDATA #IMPLIED>
<!-- Ansprechparter für den XML-Fragenkatalog (z.B. bei Fehlern): (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT contact (#PCDATA)>
<!-- Kommentar zum Fragenkatalog (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT comment (#PCDATA)>
<!-- Diverse Optionen -->
<!ELEMENT options EMPTY>
<!-- Wird die Reihenfolge der Antworten beim Abfragen immer durchgetauscht? Default: Ja -->
<!ATTLIST options mixanswers (true|false) "true">
<!-- Definition einer Prüfung -->
<!ELEMENT exam (exam_part+)>
<!-- Eindeutige Kennung (für Prüfungsstatistiken) -->
<!ATTLIST exam id CDATA #REQUIRED>
<!-- Name/Bezeichnung der Prüfung -->
<!ATTLIST exam name CDATA #REQUIRED>
<!-- Dauer der Prüfung in Minuten, 0 für unbegrenzt -->
<!ATTLIST exam duration CDATA #REQUIRED>
<!-- Max. erlaubte Anzahl von Fehlerpunkten zum Bestehen der Prüfung -->
<!ATTLIST exam maxerrorpoints CDATA #REQUIRED>
<!-- Teil einer Prüfung
Enthält regulären Ausdruck nach den Regeln von http://doc.trolltech.com/4.2/qregexp.html#details
Es werden für die Prüfungszusammenstellung 'count' Fragen ausgewählt,
deren 'id' diesem regulären Ausdruck entsprechen.
Bsp: <exam_part count="5">TA\d\d\d</exam_part>
=> Es sind 5 Fragen in der Prüfung, die mit TA beginnen und anschließend 3 Ziffern haben
-->
<!ELEMENT exam_part (#PCDATA)>
<!ATTLIST exam_part count CDATA #REQUIRED>
<!-- Hilfetexte/Bemerkungen zu einzelnen Fragen (Codiertes HTML erlaubt, s.o.)
Es ist möglich, ein Hilfetext mehreren Fragen zuzuordnen und auch einer Frage mehrere Texte zuzuordnen
-->
<!ELEMENT hint (#PCDATA)>
<!-- Zugeordnete Fragen, durch Leerzeichen und/oder Komma und/oder Semikolon getrennt-->
<!ATTLIST hint question CDATA #REQUIRED>
<!-- Autor des Hilfetextes -->
<!ATTLIST hint author CDATA #IMPLIED>
<!-- Datum -->
<!ATTLIST hint date CDATA #IMPLIED>
<!-- Kapitel eines Fragenkatalogs -->
<!ELEMENT chapter (chapter*, question*)>
<!-- Bezeichnung/Name des Kapitels -->
<!ATTLIST chapter name CDATA #REQUIRED>
<!-- Eindeutige ID des Kapitels -->
<!ATTLIST chapter id CDATA #REQUIRED>
<!-- Frage -->
<!ELEMENT question (textquestion, textanswer+, comment?)>
<!-- Eindeutige Kennung der Frage -->
<!ATTLIST question id CDATA #REQUIRED>
<!-- Letze Änderung der Frage -->
<!ATTLIST question changed CDATA #IMPLIED>
<!-- Fehlerpunkte beim falsch beantworten, Default: 1 -->
<!ATTLIST question errorpoints CDATA "1">
<!-- Ist die Frage aktiv bzw. prüfungsrelevant? Default: true -->
<!ATTLIST question active (true|false) "true">
<!-- Fragentext (Codiertes HTML erlaubt, s.o.) -->
<!ELEMENT textquestion (#PCDATA)>
<!-- Antwort auf eine Frage (Codiertes HTML erlaubt, s.o.) -->
<!ELEMENT textanswer (#PCDATA)>
<!-- Ist diese Anwort richtig oder falsch? (Default: false = falsch)-->
<!ATTLIST textanswer correct (true|false) "false">

108
AQDF-Format/aqdf.dtd Normal file
View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
AQDF (Amateur Radio Questionary Data Format) DTD
XML-DTD by Oliver Saal, Junghard Bippes and Dominik Dresel (c) 2003-2007
License: GPL v2 or later
Hinweis: Wenn HTML in Tags erlaubt ist, wird darauf explizit hingewiesen.
HTML wird dann entweder in CDATA-Blöcke (wie <![CDATA[ <b>fette Schrift</b> ]]>) gepackt
oder mit &lt; codiert (<answertext correct="true">42*10&lt;sup>-3&lt;/sup> A.</answertext>).
-->
<!ELEMENT aqdf (title,publisher,version,valid,contact,comment?,options?,exam*,hint*,chapter+)>
<!-- Version des AFUTrainer-Formats - hier: 3.0 -->
<!ATTLIST aqdf version (1.0) #REQUIRED>
<!-- Datum, an dem diese XML-Datei erstellt wurde. -->
<!ATTLIST aqdf created CDATA #REQUIRED>
<!-- Titel (ausführlich/lang) des Fragenkatalogs -->
<!ELEMENT title (#PCDATA)>
<!-- Kurzbezeichnung des Fragenkatalogs -->
<!ATTLIST title short CDATA #IMPLIED>
<!-- unique wird benötigt, um Lernstatistiken unabh. vom Dateinamen
und eindeutig auf dem System abzuspeichern -->
<!ATTLIST title unique CDATA #REQUIRED>
<!-- Angaben zum Original-Fragenkatalog, Urheber: (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT publisher (#PCDATA)>
<!-- Version/Auflage des Original-Fragenkataloges (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT version (#PCDATA)>
<!-- Original-Versions-Datum -->
<!ATTLIST version published CDATA #REQUIRED>
<!-- Gültigkeitszeitraum des Katalogs -->
<!ELEMENT valid EMPTY>
<!ATTLIST valid from CDATA #REQUIRED>
<!ATTLIST valid until CDATA #IMPLIED>
<!-- Ansprechparter für den XML-Fragenkatalog (z.B. bei Fehlern): (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT contact (#PCDATA)>
<!-- Kommentar zum Fragenkatalog (Codiertes HTML erlaubt, s.o.)-->
<!ELEMENT comment (#PCDATA)>
<!-- Diverse Optionen -->
<!ELEMENT options EMPTY>
<!-- Wird die Reihenfolge der Antworten beim Abfragen immer durchgetauscht? Default: Ja -->
<!ATTLIST options mixanswers (true|false) "true">
<!-- Definition einer Prüfung -->
<!ELEMENT exam (exam_part+)>
<!-- Eindeutige Kennung (für Prüfungsstatistiken) -->
<!ATTLIST exam id CDATA #REQUIRED>
<!-- Name/Bezeichnung der Prüfung -->
<!ATTLIST exam name CDATA #REQUIRED>
<!-- Dauer der Prüfung in Minuten, 0 für unbegrenzt -->
<!ATTLIST exam duration CDATA #REQUIRED>
<!-- Max. erlaubte Anzahl von Fehlerpunkten zum Bestehen der Prüfung -->
<!ATTLIST exam maxerrorpoints CDATA #REQUIRED>
<!-- Teil einer Prüfung
Enthält regulären Ausdruck nach den Regeln von http://doc.trolltech.com/4.2/qregexp.html#details
Es werden für die Prüfungszusammenstellung 'count' Fragen ausgewählt,
deren 'id' diesem regulären Ausdruck entsprechen.
Bsp: <exam_part count="5">TA\d\d\d</exam_part>
=> Es sind 5 Fragen in der Prüfung, die mit TA beginnen und anschließend 3 Ziffern haben
-->
<!ELEMENT exam_part (#PCDATA)>
<!ATTLIST exam_part count CDATA #REQUIRED>
<!-- Hilfetexte/Bemerkungen zu einzelnen Fragen (Codiertes HTML erlaubt, s.o.)
Es ist möglich, ein Hilfetext mehreren Fragen zuzuordnen und auch einer Frage mehrere Texte zuzuordnen
-->
<!ELEMENT hint (#PCDATA)>
<!-- Zugeordnete Fragen, durch Leerzeichen und/oder Komma und/oder Semikolon getrennt-->
<!ATTLIST hint question CDATA #REQUIRED>
<!-- Autor des Hilfetextes -->
<!ATTLIST hint author CDATA #IMPLIED>
<!-- Datum -->
<!ATTLIST hint date CDATA #IMPLIED>
<!-- Kapitel eines Fragenkatalogs -->
<!ELEMENT chapter (chapter*, question*)>
<!-- Bezeichnung/Name des Kapitels -->
<!ATTLIST chapter name CDATA #REQUIRED>
<!-- Eindeutige ID des Kapitels -->
<!ATTLIST chapter id CDATA #REQUIRED>
<!-- Frage -->
<!ELEMENT question (textquestion, textanswer+, comment?)>
<!-- Eindeutige Kennung der Frage -->
<!ATTLIST question id CDATA #REQUIRED>
<!-- Letze Änderung der Frage -->
<!ATTLIST question changed CDATA #IMPLIED>
<!-- Fehlerpunkte beim falsch beantworten, Default: 1 -->
<!ATTLIST question errorpoints CDATA "1">
<!-- Ist die Frage aktiv bzw. prüfungsrelevant? Default: true -->
<!ATTLIST question active (true|false) "true">
<!-- Fragentext (Codiertes HTML erlaubt, s.o.) -->
<!ELEMENT textquestion (#PCDATA)>
<!-- Antwort auf eine Frage (Codiertes HTML erlaubt, s.o.) -->
<!ELEMENT textanswer (#PCDATA)>
<!-- Ist diese Anwort richtig oder falsch? (Default: false = falsch)-->
<!ATTLIST textanswer correct (true|false) "false">

75
AQDF-Format/aqdf.xml Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="ISO-8859-15"?>
<!--
AQDF (Amateur Radio Questionary Data Format) XML
by Oliver Saal, Junghard Bippes and Dominik Dresel (c) 2007
License: GPL v2 or later
-->
<!DOCTYPE aqdf SYSTEM "http://www.oliver-saal.de/software/afutrainer/download/aqdf10.dtd">
<aqdf version="1" name="DL Technik Klasse E (ab 02/2007)" created="2007-03-27" >
<!-- Wird benötigt um die Lernstatistiken eindeutig abzuspeichern -
falls sich der Dateiname (z.B. wegen neuer Fragenkatalog-Auflage) ändern
sollte: -->
<unique_name>DL-E-2006</unique_name>
<!-- Titel des Fragenkataloges -->
<title>Prüfungsfragen im Prüfungsteil Technische Kenntnisse bei Prüfungen zum Erwerb von Amateurfunkzeugnissen der Klasse E</title>
<!-- Angaben zum Original-Fragenkatalog, Urheber: -->
<author>Bundesnetzagentur&lt;br>Referat 225&lt;br>Canisiusstraße 21&lt;br>55122 Mainz&lt;br>E-Mail: Poststelle@BNetzA.de&lt;br>Fax: 06131 - 18 5644</author>
<!-- Version des Fragenkataloges -->
<version published="2006-09-01">1. Auflage, September 2006</version>
<!-- Gültigkeitsdauer -->
<valid from="2007-02-01" to="" />
<!-- Wer ist Ansprechparter für den XML-Fragenkatalog (z.B. bei Fehlern): -->
<contact>Oliver Saal, DM1OLI&lt;br>http://www.oliver-saal.de/software/afutrainer/&lt;br>Mail:osaal@gmx.de</contact>
<!-- Kommentar: (z.B: Frage xyz korrigiert...) -->
<comment></comment>
<!-- Diverse Optionen -->
<options mixanswers="1" />
<!-- Fragenauswahl pro Kapitel -->
<exam id="T" name="Technische Kenntnisse Klasse E" duration="60" maxerrorpoints="9">
<exam_part count="1">TA\d\d\d</exam_part>
<...>
</exam>
<!-- Bemerkungen zu den Fragen -->
<hint question="TB103, TB104" author="Oliver Saal (DM1OLI) osaal@gmx.de" date="2004-03-25">Bronze und Messing sind Metalle und damit Leiter. Desweiteren leitet Konstantan und Graphitstaub ebenfalls den elektrischen Strom.</hint>
<hint question="B..." author="Fragenkatalog Bundesnetzagentur">
<![CDATA[
<table>
<tr><th>Zu übermittelnder<br>Buchstabe</th><th>Schlüsselwort</th><th>Aussprache des<br>Schlüsselworts</th></tr>
<tr><td>A</td><td>Alfa</td><td><u>AL</u> FAH</td></tr>
<tr><td>Z</td><td>Zoulou</td><td><u>SUH</u> LUH</td></tr>
</table>
Die zu betonenden Silben sind <u>unterstrichen</u>.
]]>
</hint>
<chapter name="Prüfungsfragen im Prüfungsteil Technische Kenntnisse der Klasse E" id="T" >
<chapter name="Allgemeine mathematische Grundkenntnisse und Größen" id="A" >
<chapter name="Allgemeine mathematische Grundkenntnisse" id="1" >
<question id="TA101" changed="2006-09-23" errorpoints="1" active="true">
<textquestion>0,042 A entspricht</textquestion>
<textanswer correct="true">42*10&lt;sup>-3&lt;/sup> A.</textanswer>
<textanswer correct="false">42*10&lt;sup>3&lt;/sup> A.</textanswer>
<textanswer correct="false">42*10&lt;sup>-2&lt;/sup> A.</textanswer>
<textanswer correct="false">42*10&lt;sup>-1&lt;/sup> A.</textanswer>
<remark>geändert 2006-09-22, 2006-09-23 DF1IAV</remark>
<link>www.dj4uf.de/lehrg/a01/a01.html#Abg_Einheiten</link>
</question>
</chapter>
</chapter>
</chapter>
</aqdf>

BIN
Abfragestrategie.odt Normal file

Binary file not shown.

261
Doxyfile Normal file
View File

@ -0,0 +1,261 @@
# Doxyfile 1.5.1-p1
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = AFUTrainer
PROJECT_NUMBER = 2.2
OUTPUT_DIRECTORY = D:/projekte/Software/afutrainer/afutrainer-2.2/doc/
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
USE_WINDOWS_ENCODING = YES
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH = D:/projekte/Software/afutrainer/afutrainer-2.2/
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 8
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO
BUILTIN_STL_SUPPORT = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = D:/projekte/Software/afutrainer/afutrainer-2.2
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.d \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.idl \
*.odl \
*.cs \
*.php \
*.php3 \
*.inc \
*.m \
*.mm \
*.dox \
*.py
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
USE_HTAGS = NO
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = YES
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = YES
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_SCHEMA =
XML_DTD =
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
MAX_DOT_GRAPH_DEPTH = 1000
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO

BIN
afutrainer.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

61
afutrainer.pro Normal file
View File

@ -0,0 +1,61 @@
win32 {
TEMPLATE = vcapp
}
else {
TEMPLATE = app
}
TARGET = afutrainer
QT += qt gui xml
HEADERS = mainwindow.h \
catalogmodel.h \
questionmodel.h \
dlglearn.h \
dlgviewquestion.h \
question.h \
chapter.h \
catalog.h \
dlglearnassistant.h \
answer.h \
helper.h \
chaptermodel.h \
osziparchive.h \
dlginformation.h \
exam.h \
dlgexam.h \
dlgexamselect.h \
error.h \
tools.h \
dlglearnstatistic.h \
dlgexamstatistic.h \
plotwidget.h \
recentfiles.h
SOURCES = main.cpp \
mainwindow.cpp \
catalogmodel.cpp \
questionmodel.cpp \
dlglearn.cpp \
dlgviewquestion.cpp \
question.cpp \
chapter.cpp \
catalog.cpp \
dlglearnassistant.cpp \
answer.cpp \
helper.cpp \
chaptermodel.cpp \
osziparchive.cpp \
dlginformation.cpp \
exam.cpp \
dlgexam.cpp \
dlgexamselect.cpp \
error.cpp \
tools.cpp \
dlglearnstatistic.cpp \
dlgexamstatistic.cpp \
plotwidget.cpp \
recentfiles.cpp
FORMS = mainwindow.ui dlglearn.ui dlgviewquestion.ui dlglearnassistant.ui dlginformation.ui dlgexamselect.ui dlgexam.ui dlglearnstatistic.ui dlgexamstatistic.ui
RC_FILE = afutrainer.rc
RESOURCES += afutrainer.qrc

36
afutrainer.qrc Normal file
View File

@ -0,0 +1,36 @@
<RCC>
<qresource prefix="/" >
<file>icons/16x16/book1.png</file>
<file>icons/16x16/button_ok.png</file>
<file>icons/16x16/button_cancel.png</file>
<file>icons/16x16/cancel.png</file>
<file>icons/16x16/clock.png</file>
<file>icons/16x16/contexthelp.png</file>
<file>icons/16x16/exit.png</file>
<file>icons/16x16/filenew.png</file>
<file>icons/16x16/fileopen.png</file>
<file>icons/16x16/filesave.png</file>
<file>icons/16x16/filesaveas.png</file>
<file>icons/16x16/finish.png</file>
<file>icons/16x16/folder.png</file>
<file>icons/16x16/idea.png</file>
<file>icons/16x16/idea_gray.png</file>
<file>icons/16x16/idea_info.png</file>
<file>icons/16x16/info.png</file>
<file>icons/16x16/level0.png</file>
<file>icons/16x16/level1.png</file>
<file>icons/16x16/level2.png</file>
<file>icons/16x16/level3.png</file>
<file>icons/16x16/level4.png</file>
<file>icons/16x16/level5.png</file>
<file>icons/16x16/next.png</file>
<file>icons/16x16/previous.png</file>
<file>icons/16x16/start.png</file>
<file>icons/16x16/stats.png</file>
<file>icons/16x16/stop.png</file>
<file>icons/16x16/viewmag.png</file>
<file>icons/32x32/idea.png</file>
<file>icons/32x32/qt.png</file>
<file>translations/qt_de.qm</file>
</qresource>
</RCC>

1
afutrainer.rc Normal file
View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "afutrainer.ico"

119
answer.cpp Normal file
View File

@ -0,0 +1,119 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "answer.h"
#include <qcoreapplication.h>
CAnswer::CAnswer(const QString& strText, const bool bCorrect)
{
m_strText = strText;
m_bIsCorrect = bCorrect;
}
void CAnswer::clear()
{
m_strText.clear();
m_bIsCorrect = false;
}
QString CAnswerClicked::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CAnswerClicked", sourceText, comment);
}
void CAnswerClicked::clear()
{
m_dt = QDateTime::currentDateTime();
m_uAnswer=0;
m_uNeededTime=0;
}
bool CAnswerClicked::operator < (const CAnswerClicked& ac) const
{
return m_dt < ac.m_dt;
}
QString CAnswerClicked::answerText(const unsigned uAnswer)
{
QString strRet;
for (int i=0; i<32; i++)
{
if (uAnswer & (1<<i))
{
if (!strRet.isEmpty())
strRet += ", ";
strRet += QChar('A' + i);
}
}
return strRet;
}
QString CAnswerClicked::answerText() const
{
return answerText(m_uAnswer);
}
QString CAnswerClicked::neededTimeText() const
{
if (m_uNeededTime < 1000)
return tr("&lt; 1 sec");
else if (m_uNeededTime < 60000)
return tr("%1 sec").arg(m_uNeededTime / 1000);
else
return tr("%1:%2 min").arg(m_uNeededTime / 60000).arg((m_uNeededTime / 1000) % 60, 2, 10, QChar('0'));
}
bool CAnswerClicked::isCorrect(const QList<CAnswer>& listAnswer) const
{
unsigned uMask=0;
for (int i=0; i<listAnswer.size(); i++)
{
if (listAnswer.at(i).isCorrect())
uMask |= (1<<i);
}
return (m_uAnswer == uMask);
}
bool CAnswerClicked::load (QDomElement elem)
{
bool bOk=false;
if (elem.tagName() != "answer_clicked") return false;
m_dt = QDateTime::fromString (elem.attribute("datetime"), Qt::ISODate);
if (!m_dt.isValid()) return false;
m_uAnswer = elem.attribute("answer_code").toUInt(&bOk);
if (!bOk) return false;
m_uNeededTime = elem.attribute("needed_time").toUInt(&bOk);
if (!bOk) return false;
return true;
}
void CAnswerClicked::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elem = doc.createElement("answer_clicked");
elem.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elem.setAttribute("answer_code", QString("%1").arg(m_uAnswer));
elem.setAttribute("needed_time", QString("%1").arg(m_uNeededTime));
parent.appendChild(elem);
}

142
answer.h Normal file
View File

@ -0,0 +1,142 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ANSWER_H
#define ANSWER_H
#include <qstring.h>
#include <qdom.h>
#include <qlist.h>
#include <qdatetime.h>
//! Die Klasse CAnswer speichert eine einzelne Antwort auf eine Frage
/*!
Das Schreiben und Lesen von XML-Daten wird von der Klasse CQuestion übernommen
*/
class CAnswer
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswer() { clear(); }
//! Konstruktor inkl. setzen eines Textes und ob die Antwort richtig ist
/*!
\param strText Antworttext
\param bCorrect true: Die Antwort ist korrekt
\sa m_strText, m_bIsCorrect
*/
CAnswer(const QString& strText, const bool bCorrect);
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswer() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Antwort gelöscht. */
void clear();
//! Überprüfen, ob die Klasse eine Antwort enthält
/*! \return true: Die Klasse ist leer und enthält keine Antwort */
inline bool isEmpty() const { return m_strText.isEmpty(); }
//! Auslesen, ob diese Antwort richtig ist
/*! \return true: Die Antwort ist richtig */
inline bool isCorrect() const { return m_bIsCorrect; }
//! Auslesen des Antworttextes
/*! \return Antworttext */
inline QString text() const { return m_strText; }
//! Setzen, ob diese Antwort richtig ist
/*!
\param bCorrect true: Die Antwort ist korrekt
\sa m_bIsCorrect
*/
inline void setCorrect (const bool bCorrect) { m_bIsCorrect = bCorrect; }
//! Setzen des Antworttextes
/*!
\param strText Antworttext
\sa m_strText
*/
inline void setText(const QString& strText) { m_strText = strText; }
//! Anhängen eines Textes an den Antworttext
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
protected:
//! Antworttext
/*!
Der Antworttext darf HTML-Code und HTML-Verweise auf Grafiken/Bilder enthalten. Bei Verweisen ist zu achten, dass kein Verzeichnis angegeben werden darf!
Default: leer
*/
QString m_strText;
//! Richtige oder falsche Antwort
/*! Default: false */
bool m_bIsCorrect;
};
//! Die Klasse CAnswerClicked speichert eine einzelne Beantwortung des Benutzers
/*!
*/
class CAnswerClicked
{
public:
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CAnswerClicked () { clear(); }
CAnswerClicked (const unsigned uAnswer, const unsigned uNeededTime)
{ m_uAnswer = uAnswer; m_dt = QDateTime::currentDateTime(); m_uNeededTime = uNeededTime; }
//! Standard-Destruktor
/*! In der Standard-Implementierung tut der Destruktor nichts. */
~CAnswerClicked () {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten auf Default-Werte zurückgesetzt. */
void clear();
inline QDateTime dateTime() const { return m_dt; }
inline unsigned neededTime() const { return m_uNeededTime; }
inline unsigned answer() const { return m_uAnswer; }
static QString answerText(const unsigned uAnswer);
QString answerText() const;
QString neededTimeText() const;
bool isCorrect(const QList<CAnswer>& listAnswer) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
static QString tr (const char *sourceText, const char *comment=0);
bool operator < (const CAnswerClicked& ac) const;
protected:
QDateTime m_dt; //!< Zeitstempel der Antwort
unsigned m_uAnswer; //!< Antwort-Bitmaske
unsigned m_uNeededTime; //!< Benötigte Zeit in ms
};
#endif

433
catalog.cpp Normal file
View File

@ -0,0 +1,433 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalog.h"
#include "osziparchive.h"
#include "tools.h"
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qvariant.h>
CCatalog::~CCatalog()
{
qDeleteAll(m_listFiles);
}
void CCatalog::clear()
{
CChapter::clear();
m_bMixAnswers = true;
m_bSort = false;
m_strFileName.clear();
m_listHint.clear();
m_strUniqueName.clear();
qDeleteAll(m_listFiles);
m_strPublisher.clear();
m_strContact.clear();
m_dateValidFrom = QDate();
m_dateValidUntil = QDate();
m_dateCreated = QDate();
m_datePublished = QDate();
m_strVersion.clear();
m_listExam.clear();
m_listExamStat.clear();
}
bool CCatalog::isEmpty()
{
return m_strText.isEmpty();
}
bool CCatalog::isValid() const
{
if (m_dateValidFrom.isValid() && QDate::currentDate() < m_dateValidFrom) return false;
if (m_dateValidUntil.isValid() && QDate::currentDate() > m_dateValidUntil) return false;
return true;
}
bool CCatalog::hasHints (const QString& strQuestionId) const
{
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId)) return true;
}
return false;
}
QString CCatalog::hintText (const QString& strQuestionId) const
{
QString str;
if (strQuestionId.isEmpty()) return QString();
for (int i=0; i<m_listHint.size(); i++)
{
if (m_listHint.at(i).hasQuestion(strQuestionId))
str += m_listHint[i].showText();
}
return str;
}
bool CCatalog::load (const QString& strFileName, QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QString str, strXML;
int iErrLine, iErrCol;
double dVersion=0.0;
CChapter *pChapter=0;
if (strFileName.right(3).toLower() != "aqz") return false;
CZipArchive zip;
if (!zip.open(strFileName, CZipArchive::OpenReadOnly))
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n%1").arg(strFileName));
return false;
}
// Fragen entpacken
CZipFile *pzfQuestions = zip.findFile("questions.xml");
if (pzfQuestions == 0)
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Konnte in der Datei '%1' keine Fragen finden.").arg(strFileName));
return false;
}
strXML = QString::fromUtf8(pzfQuestions->deflateToByteArray());
clear();
// Alle Grafiken in temp. Dateien entpacken
// pParent->setCursor(Qt::WaitCursor);
for (int i=0; i<zip.fileCount(); i++)
{
CZipFile *pzf = zip.fileAt(i);
str = pzf->fileName().right(3);
if (str == "png" || str == "jpg" || str == "gif" || str == "bmp")
{ // Datei entpacken und Pfade im XML anpassen
str = QDir::temp().absoluteFilePath(pzf->fileName()+".XXXXXX");
QTemporaryFile *ptf = new QTemporaryFile(str);
ptf->open();
str = ptf->fileName();
pzf->deflateToFile(*ptf);
ptf->close();
m_listFiles.append(ptf);
strXML.replace(pzf->fileName(), str);
//qDebug ("Deflating %s to %s", qPrintable(pzf->fileName()), qPrintable(str));
}
}
// pParent->setCursor(Qt::ArrowCursor);
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Fragenkatalog: ") + strFileName + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
elemRoot = doc.documentElement ();
if (elemRoot.tagName() != "aqdf")
{
QMessageBox::critical(pParent, pParent->tr("Datei-Fehler"), pParent->tr("Unbekanntes XML-Datenformat '%1'.").arg(elemRoot.tagName()));
return false;
}
//m_strText = elemRoot.attribute ("name");
m_dateCreated = QDate::fromString(elemRoot.attribute("created"), Qt::ISODate);
dVersion = elemRoot.attribute("version").toDouble();
if (dVersion != 1.0)
{
QMessageBox::information(pParent, pParent->tr("Information"), pParent->tr("Kann die Dateiversion %1 des Fragenkatalogs '%2' nicht lesen.").arg(dVersion).arg(strFileName));
return false;
}
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("exam"))
{
CExam exam;
if (exam.load(e)) m_listExam.append(exam);
}
else if (e.tagName () == "hint")
{
CHint hint;
if (hint.load (e))
m_listHint.append (hint);
}
else if (e.tagName () == "title")
{
m_strText = e.text();
m_strUniqueName = e.attribute("unique");
}
else if (e.tagName () == "comment")
m_strComment = e.text();
else if (e.tagName () == "contact")
m_strContact = e.text();
else if (e.tagName () == "publisher")
m_strPublisher = e.text();
else if (e.tagName() == "valid")
{
m_dateValidFrom = QDate::fromString(e.attribute("from"), Qt::ISODate);
m_dateValidUntil = QDate::fromString(e.attribute("until"), Qt::ISODate);
}
else if (e.tagName() == "version")
{
m_datePublished = QDate::fromString(e.attribute("published"), Qt::ISODate);
m_strVersion = e.text();
}
else if (e.tagName() == "options")
{
m_bMixAnswers = QVariant(e.attribute("mixanswers", "true")).toBool();
m_bSort = QVariant(e.attribute("sort", "false")).toBool();
}
}
n = n.nextSibling();
}
if (m_strUniqueName.isEmpty())
m_strUniqueName = QDir(strFileName).dirName();
if (m_bSort) sortAll();
loadStatistic (pParent);
updateStatistic();
m_strFileName = strFileName;
return true;
}
bool CCatalog::save (const QString& strFileName, QWidget *pParent)
{
QFile file (strFileName);
if (strFileName.isEmpty()) return false;
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen:\n")+strFileName);
return false;
}
QTextStream out(&file);
QDomDocument doc("afutrainer");
QDomElement elemRoot = doc.createElement("afutrainer");
//elemRoot.setAttribute("name", name());
elemRoot.setAttribute("version", 3.0);
elemRoot.setAttribute("created", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild(elemRoot);
// save unique name
QDomElement elemTitle = createXmlTextElement("title", name(), doc);
elemTitle.setAttribute("unique", m_strUniqueName);
elemRoot.appendChild (elemTitle);
// save comment
if (!m_strComment.isEmpty())
elemRoot.appendChild (createXmlTextElement("comment", m_strComment, doc));
// save contact
if (!m_strContact.isEmpty())
elemRoot.appendChild (createXmlTextElement("contact", m_strContact, doc));
// save publisher
if (!m_strPublisher.isEmpty())
elemRoot.appendChild (createXmlTextElement("publisher", m_strPublisher, doc));
// save version
QDomElement elemVersion = createXmlTextElement("version", m_strVersion, doc);
elemVersion.setAttribute("published", m_datePublished.toString(Qt::ISODate));
elemRoot.appendChild(elemVersion);
// save dates
if (m_dateValidFrom.isValid() || m_dateValidUntil.isValid())
{
QDomElement elemValid = doc.createElement("valid");
elemValid.setAttribute("from", m_dateValidFrom.toString(Qt::ISODate));
elemValid.setAttribute("until", m_dateValidUntil.toString(Qt::ISODate));
elemRoot.appendChild(elemValid);
}
// TODO: save tests
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
m_listChapter[i]->save(elemRoot, doc);
// save helpers
for (int i=0; i<m_listHint.size(); i++)
m_listHint[i].save(elemRoot, doc);
out << doc.toString();
m_strFileName = strFileName;
return true;
}
QString CCatalog::statisticFileName() const
{
QDir dir;
QString str = dir.homePath()+QString("/.afutrainer/") + m_strUniqueName + QString(".stat.xml");
Q_ASSERT(!m_strUniqueName.isEmpty());
return (str);
}
bool CCatalog::loadStatistic(QWidget *pParent)
{
QDomDocument doc;
QDomElement elemRoot, e;
QDomNode n;
QFile file (statisticFileName());
QString strVerzeichnis, str, strXML;
int iErrLine, iErrCol;
if (!file.exists()) return true;
if (!file.open (QIODevice::ReadOnly))
{
QMessageBox::critical(pParent, QString(pParent->tr("Datei-Fehler")), pParent->tr("Konnte folgende Datei nicht zum Lesen öffnen:\n")+statisticFileName());
return false;
}
QTextStream in (&file);
strXML = in.readAll();
if (!doc.setContent(strXML, true, &str, &iErrLine, &iErrCol))
{
QMessageBox::critical(pParent, pParent->tr("XML-Fehler"), pParent->tr("Statistik zum Fragenkatalog: ") + statisticFileName() + "\n" + str + "\n" + QString (pParent->tr("Zeile: %1 Spalte %2")).arg(iErrLine).arg(iErrCol));
return false;
}
file.close ();
elemRoot = doc.documentElement ();
if (doc.doctype().name() != "AFUTrainerStatistics") return false;
if (elemRoot.tagName() != "statistic") return false;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("learning"))
{
loadLearnStatistic(e);
}
else if (e.tagName() == QString("exams"))
loadExamStatistic(e);
}
n = n.nextSibling();
}
return true;
}
bool CCatalog::saveStatistic(QWidget *pParent)
{
QDomDocument doc ("AFUTrainerStatistics");
QString strFileName = statisticFileName();
QFile file (strFileName);
if (m_strUniqueName.isEmpty()) return false;
QDomElement elemRoot = doc.createElement ("statistic");
elemRoot.setAttribute ("name", name());
elemRoot.setAttribute("version", 2);
elemRoot.setAttribute("date", QDate::currentDate().toString(Qt::ISODate));
doc.appendChild (elemRoot);
QDomElement elemLearn = doc.createElement ("learning");
elemRoot.appendChild (elemLearn);
saveLearnStatistic(elemLearn, doc);
QDomElement elemExams = doc.createElement ("exams");
elemRoot.appendChild (elemExams);
saveExamStatistic(elemExams, doc);
if (!file.open (QIODevice::WriteOnly))
{
QMessageBox::critical (pParent, pParent->tr("Fehler"), pParent->tr("Konnte folgende Datei nicht zum Schreiben öffnen.\n")+strFileName);
return false;
}
QTextStream out(&file);
out << doc.toString ();
return true;
}
bool CCatalog::loadExamStatistic (QDomElement& elemRoot)
{
QDomNode n;
QDomElement e;
n = elemRoot.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
e = n.toElement ();
if (e.tagName() == QString ("exam"))
{
CExamStat es;
if (es.load(e)) m_listExamStat.append(es);
}
}
n = n.nextSibling();
}
return true;
}
void CCatalog::saveExamStatistic (QDomElement& parent, QDomDocument& doc)
{
for (int i=0; i<m_listExamStat.size(); i++)
{
m_listExamStat.at(i).save (parent, doc);
}
}
QList<CChapter*> CCatalog::chapters()
{
QList<CChapter*> list;
list.append(this);
list << subChapters();
return list;
}
CExam CCatalog::examById(const QString& strId) const
{
for (int i=0; i<m_listExam.size(); i++)
{
if (m_listExam.at(i).id() == strId)
return m_listExam.at(i);
}
return CExam();
}

120
catalog.h Normal file
View File

@ -0,0 +1,120 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CATALOG_H
#define CATALOG_H
#include "chapter.h"
#include "exam.h"
#include <qlist.h>
#include <qtemporaryfile.h>
class CCatalog : public CChapter
{
public:
CCatalog() : CChapter() { clear(); }
~CCatalog();
void clear();
bool isEmpty();
inline QString name() const { return m_strText; }
inline void setName(const QString& strName) { m_strText = strName; }
inline QString contact() const { return m_strContact; }
inline void setContact(const QString& strContact) { m_strContact = strContact; }
inline QString publisher() const { return m_strPublisher; }
inline void setPublisher(const QString& strPublisher) { m_strPublisher = strPublisher; }
// Validation
inline QDate validFrom() const { return m_dateValidFrom; }
inline void setValidFrom(const QDate& date) { m_dateValidFrom = date; }
inline QDate validUntil() const { return m_dateValidUntil; }
inline void setValidUntil(const QDate& date) { m_dateValidUntil = date; }
bool isValid() const;
inline QDate created() const { return m_dateCreated; }
inline void setCreated(const QDate& date) { m_dateCreated = date; }
inline QDate published() const { return m_datePublished; }
inline void setPublished(const QDate& date) { m_datePublished = date; }
inline QString versionText() const { return m_strVersion; }
inline void setVersionText(const QString& str) { m_strVersion = str; }
// file operations
inline QString fileName() const { return m_strFileName; }
bool load (const QString& strFileName, QWidget *pParent);
bool save (const QString& strFileName, QWidget *pParent);
bool loadStatistic(QWidget *pParent);
bool saveStatistic(QWidget *pParent);
// hints
inline int countHint() const { return m_listHint.size(); }
inline const CHint& hintAt(int i) const { return m_listHint.at(i); }
inline CHint& hintAt(int i) { return m_listHint[i]; }
inline void appendHint(const CHint& a) { m_listHint.append(a); }
bool hasHints (const QString& strQuestionId) const;
QString hintText (const QString& strQuestionId) const;
// exams
inline int countExam() const { return m_listExam.size(); }
inline const CExam& examAt(int i) const { return m_listExam.at(i); }
inline CExam& examAt(int i) { return m_listExam[i]; }
inline void appendExam(const CExam& a) { m_listExam.append(a); }
CExam examById(const QString& strId) const;
inline void appendExamStat(const CExamStat& a) { m_listExamStat.append(a); }
inline int countExamStat() const { return m_listExamStat.size(); }
inline const CExamStat& examStatAt(int i) const { return m_listExamStat.at(i); }
// options
inline bool useMixedAnswers() const { return m_bMixAnswers; }
// others
QList<CChapter*> chapters();
protected:
QString statisticFileName() const;
bool loadExamStatistic (QDomElement& elemRoot);
void saveExamStatistic (QDomElement& parent, QDomDocument& doc);
protected:
QString m_strFileName;
QString m_strUniqueName;
QList<QTemporaryFile*> m_listFiles;
QList<CHint> m_listHint;
QString m_strContact;
QString m_strPublisher;
QDate m_dateValidFrom;
QDate m_dateValidUntil;
QDate m_dateCreated;
QDate m_datePublished;
QString m_strVersion;
QList<CExam> m_listExam;
QList<CExamStat> m_listExamStat;
// Optionen
bool m_bMixAnswers;
bool m_bSort;
};
#endif

205
catalogmodel.cpp Normal file
View File

@ -0,0 +1,205 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalogmodel.h"
#include "catalog.h"
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CCatalogModel::CCatalogModel (QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CCatalogModel::~CCatalogModel()
{
}
void CCatalogModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CCatalogModel::setModelData (CCatalog *pCatalog)
{
reset();
m_pCatalog = pCatalog;
reset();
}
int CCatalogModel::columnCount (const QModelIndex& parent) const
{
Q_UNUSED(parent);
return 4;
}
QVariant CCatalogModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QVariant CCatalogModel::data (const QModelIndex& index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->id() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
}
}
return QVariant();
}
bool CCatalogModel::hasChildren (const QModelIndex& parent) const
{
CChapter *p = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0) return false;
if (parent.isValid() && p)
return (p->countChapter() > 0);
else // root item
return true;
}
QModelIndex CCatalogModel::index (int row, int column, const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (!parent.isValid())
{ // root item
return createIndex (row, column, (void*) m_pCatalog);
}
else
{
// take entry from parent item
if (row > pParent->countChapter())
return QModelIndex();
return createIndex (row, column, (void*)pParent->chapterAt(row));
}
return QModelIndex();
}
QModelIndex CCatalogModel::parent (const QModelIndex& index) const
{
CChapter *pIndex = (CChapter*) index.internalPointer();
int iRow=0;
if (pIndex == 0 || pIndex->parentChapter() == 0) // root item
return QModelIndex(); // has no parent
CChapter *pParent = pIndex->parentChapter();
if (pParent->parentChapter())
iRow = pParent->parentChapter()->indexOfChapter(pParent);
else // parent is the root item (parent of the parent doesn't exist)
iRow = 0;
return createIndex (iRow, 0 /*index.column()*/, pParent);
}
int CCatalogModel::rowCount (const QModelIndex& parent) const
{
CChapter *pParent = (CChapter*) parent.internalPointer();
if (m_pCatalog == 0 || m_pCatalog->isEmpty()) return 0;
if (!parent.isValid()) // root item
return 1;
return pParent->countChapter();
}

55
catalogmodel.h Normal file
View File

@ -0,0 +1,55 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CATALOGMODEL_H
#define CATALOGMODEL_H
#include <qabstractitemmodel.h>
class CCatalog;
class CCatalogModel : public QAbstractItemModel
{
Q_OBJECT
public:
CCatalogModel (QObject *pParent=0);
~CCatalogModel();
void setModelData (CCatalog *pCatalog);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
CCatalog *m_pCatalog;
};
#endif

808
chapter.cpp Normal file
View File

@ -0,0 +1,808 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalog.h"
#include <qcoreapplication.h>
QString CChapter::tr (const char *sourceText, const char *comment)
{
return QCoreApplication::translate("CChapter", sourceText, comment);
}
void CChapter::clear()
{
m_pParentChapter=0;
m_strId.clear();
m_strText.clear();
m_strComment.clear();
m_recom = RecommendationNone;
m_recom2 = RecommendationNone;
qDeleteAll(m_listChapter);
qDeleteAll(m_listQuestion);
m_bHasLearningNew = false;
m_bHasKnownQuestions = false;
m_bHasKnownQuestionsRepeatToday = false;
m_uNeverAskedCount = 0;
for (int i=0; i<=LEVEL_MAX; i++) m_uLevelCount[i] = 0;
for (int i=0; i<=RecommendationMax; i++) m_uRecomCount[i] = 0;
// m_mapExam.clear();
}
int CChapter::countSubQuestion() const
{
int i=0, iRet=0;
for (i=0; i<m_listChapter.size(); i++)
iRet += m_listChapter.at(i)->countSubQuestion();
return (iRet + m_listQuestion.size());
}
bool CChapter::load (QDomElement elem)
{
CChapter *pChapter=0;
if (elem.tagName () != QString ("chapter")) return false;
if (!elem.hasAttribute ("name")) return false;
// if (pParent != NULL && !elem.hasAttribute ("id")) return false;
m_strId = elem.attribute ("id");
m_strText = elem.attribute ("name");
QDomNode n = elem.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
QDomElement e = n.toElement ();
if (e.tagName() == "comment")
m_strComment = e.text();
else if (e.tagName() == QString ("chapter"))
{
pChapter = new CChapter();
if (pChapter->load (e))
appendChapter(pChapter);
else
delete pChapter;
}
else if (e.tagName() == QString ("question"))
{
CQuestion *pQuestion = new CQuestion();
if (pQuestion->load (e))
appendQuestion(pQuestion);
else
delete pQuestion;
}
}
n = n.nextSibling();
}
updateStatistic();
return true;
}
void CChapter::save (QDomElement& parent, QDomDocument& doc)
{
QDomElement elem = doc.createElement("chapter");
elem.setAttribute("name", text());
elem.setAttribute("id", id());
if (!m_strComment.isEmpty())
{
QDomElement elemComment = doc.createElement("comment");
QDomText textComment = doc.createTextNode(text());
elemComment.appendChild(textComment);
elem.appendChild(elemComment);
}
parent.appendChild(elem);
// save exams
/* QStringList strl = m_mapExam.keys();
for (int i=0; i<strl.size(); i++)
{
QDomElement e = doc.createElement("exam");
e.setAttribute("id", strl.at(i));
e.setAttribute("questions", QString("%1").arg(m_mapExam[strl.at(i)]));
elem.appendChild(e);
}
*/
// save chapters
for (int i=0; i<m_listChapter.size(); i++)
{
m_listChapter[i]->save(elem, doc);
}
// save questions
for (int i=0; i<m_listQuestion.size(); i++)
{
m_listQuestion[i]->save(elem, doc);
}
}
bool CChapter::loadLearnStatistic (QDomElement elem)
{
QList<CQuestion*> listQuestionPool = questionPool();
if (elem.tagName () != QString ("learning")) return false;
QDomNode n = elem.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
QDomElement e = n.toElement ();
if (e.tagName() == QString ("question"))
{
QString strId = e.attribute("id");
for (int i=0; i<listQuestionPool.size(); i++)
{
if (listQuestionPool.at(i)->id() == strId)
listQuestionPool[i]->loadLearnStatistic(e);
}
}
}
n = n.nextSibling();
}
updateRecommendation();
return true;
}
bool CChapter::saveLearnStatistic (QDomElement& parent, QDomDocument& doc)
{
// questions from sub-chapters
for (int i=0; i<m_listChapter.size(); i++)
{
m_listChapter[i]->saveLearnStatistic(parent, doc);
}
// save questions
for (int i=0; i<m_listQuestion.size(); i++)
{
m_listQuestion[i]->saveLearnStatistic(parent, doc);
}
return true;
}
QString CChapter::checkForErrors() const
{
QString str;
// check chapters
for (int i=0; i<m_listChapter.size(); i++)
{
str += m_listChapter[i]->checkForErrors();
}
// check questions
for (int i=0; i<m_listQuestion.size(); i++)
{
str += m_listQuestion[i]->checkForErrors();
}
return str;
}
QList<CChapter*> CChapter::subChapters() const
{
QList<CChapter*> list;
for (int i=0; i<m_listChapter.size(); i++)
{
list << m_listChapter.at(i);
list << m_listChapter[i]->subChapters();
}
return list;
}
QList<CQuestion*> CChapter::questionPool() const
{
QList<CQuestion*> list;
for (int i=0; i<m_listChapter.size(); i++)
{
list << m_listChapter[i]->questionPool();
}
list << m_listQuestion;
return list;
}
QList<CQuestion*> CChapter::questionPoolLevel(const unsigned uLevel) const
{
QList<CQuestion*> list;
int i;
for (i=0; i<m_listChapter.size(); i++)
list << m_listChapter[i]->questionPoolLevel(uLevel);
for (i=0; i<m_listQuestion.size(); i++)
{
if (m_listQuestion.at(i)->level() == uLevel)
list.append (m_listQuestion.at(i));
}
return list;
}
QList<CQuestion*> CChapter::questionPoolDeepen() const
{
QList<CQuestion*> list;
int i;
for (i=0; i<m_listChapter.size(); i++)
list << m_listChapter[i]->questionPoolDeepen();
for (i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
if (q->level() == LEVEL_VERYOFTEN && !q->isNeverAsked())
list.append (q);
}
return list;
}
QList<CQuestion*> CChapter::questionPoolRepeat(const QDate d) const
{
QList<CQuestion*> list;
int i;
for (i=0; i<m_listChapter.size(); i++)
list << m_listChapter[i]->questionPoolRepeat(d);
for (i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
if (q->repeatDate() <= d)
list.append (q);
}
return list;
}
void CChapter::updateStatisticCount()
{
/* for (int i=0; i<m_listQuestion.size(); i++)
if (m_listQuestion.at(i)->isLearningNew()) return true;
for (int i=0; i<m_listChapter.size(); i++)
if (m_listChapter.at(i)->isLearningNew()) return true;
return false;
*/
// Alle Statistiken zurücksetzen
m_uNeverAskedCount = 0;
m_bHasLearningNew = false;
m_bHasKnownQuestions = false;
m_bHasKnownQuestionsRepeatToday = false;
for (int i=0; i<=LEVEL_MAX; i++) m_uLevelCount[i] = 0;
// Zuerst Statistiken für Unterkapitel berechnen und integrieren
for (int i=0; i<m_listChapter.size(); i++)
{
CChapter *p = m_listChapter.at(i);
p->updateStatisticCount();
for (int j=0; j<=LEVEL_MAX; j++)
m_uLevelCount[j] += p->m_uLevelCount[j];
m_uNeverAskedCount += p->m_uNeverAskedCount;
if (p->hasLearningNewQuestions()) m_bHasLearningNew = true;
if (p->hasKnownQuestions()) m_bHasKnownQuestions = true;
if (p->hasKnownQuestionsRepeatToday()) m_bHasKnownQuestionsRepeatToday = true;
}
// Anschließend Statistiken für eigene Fragen neu berechnen und hinzufügen
for (int i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
if (q->isNeverAsked()) m_uNeverAskedCount++;
m_uLevelCount[q->level()]++;
if (q->isLearningNew()) m_bHasLearningNew = true;
if (q->isKnownQuestion()) m_bHasKnownQuestions = true;
if (q->isKnownQuestion() && q->isRepeatToday()) m_bHasKnownQuestionsRepeatToday = true;
}
}
void CChapter::updateRecommendationStatistic()
{
for (int i=0; i<RecommendationMax; i++) m_uRecomCount[i] = 0;
m_uRecomCount[recommendation()]=1;
for (int i=0; i<m_listChapter.size(); i++)
{
CChapter *p = m_listChapter.at(i);
p->updateRecommendationStatistic();
for (int j=0; j<RecommendationMax; j++)
m_uRecomCount[j] += p->m_uRecomCount[j];
}
}
/*
Berechnet die Statistik für das Kapitel inkl. aller Unterkapitel neu.
*/
void CChapter::updateStatistic()
{
updateStatisticCount();
updateRecommendation();
updateRecommendationStatistic();
}
/*
CRecommendation CChapter::recommendation() const
{
CRecommendation r;
r.create(this);
return r;
}
*/
/*
CRecommendationStatistic CChapter::recommendationStatistic() const
{
CRecommendationStatistic rs;
for (int i=0; i<m_listChapter.size(); i++)
{
rs.append(m_listChapter.at(i)->recommendationStatistic());
}
//TODO
// rs.append(recommendation());
return rs;
}
*/
QString CChapter::idWithParents() const
{
CChapter *pParent=m_pParentChapter;
QString str;
str = id();
while (pParent != 0)
{
str = pParent->id() + str;
pParent = pParent->m_pParentChapter;
}
return str;
}
/*!
Das empfohlene Wiederholdatum eines Kapitels das frühestete Datum,
an dem eine Frage des Kapitels oder Unterkapitels wiederholt werden sollte.
\return Datum, wann das Kapitel wiederholt werden soll.
Gibt es kein solches Datum, so wird ein ungültiges Datum (QDate::isValid()) zurückgegeben.
Hinweis: Das Datum kann auch in der Vergangenheit liegen!
*/
QDate CChapter::repeatDate() const
{
QDate d;
QList<CQuestion*> list = questionPool();
for (int i=0; i<list.size(); i++)
{
QDate dq = list.at(i)->repeatDate();
if (!dq.isValid()) continue;
if (!d.isValid() || dq < d) d = dq;
}
return d;
}
/*!
Die Variable m_recomRepeatDate muss up to date sein!
\return Lernempfehlung dieses Kapitels ohne Berücksichtigung evt. vorhandener ünter- oder übergeordneter Kapitel.
\sa m_recomRepeatDate
*/
CChapter::Recommendation CChapter::recommendationIndividual() const
{
if (!m_recomRepeatDate.isValid())
return RecommendationLearnNew;
else if (m_recomRepeatDate <= QDate::currentDate())
{
if (hasLearningNewQuestions() && !hasKnownQuestionsRepeatToday())
return RecommendationLearnNew;
else
return RecommendationRepeatToday;
}
else
{
if (countNeverAsked() > 0)
return RecommendationLearnNew;
else
return RecommendationRepeatLater;
}
}
/*!
Aktualisiert die Lernempfehlung für dieses Kapitel und alle Unterkapitel
\sa m_recom
*/
void CChapter::updateRecommendation()
{
m_recom = RecommendationNone;
m_recom2 = RecommendationNone;
m_recomRepeatDate = repeatDate(); /*QDate();*/
if (m_listChapter.isEmpty() && m_listQuestion.isEmpty()) return;
if (m_pParentChapter && m_pParentChapter->recommendation() != RecommendationSubChapter)
m_recom = RecommendationParentChapter;
else
{
if (countSubQuestion() > 20)
{ // Nur wenn in den Unterkapiteln zusammen mehr als x Fragen sind, zuerst die Unterkapitel einzeln lernen lassen
for (int i=0; i<m_listChapter.size(); i++)
{
CChapter *p = m_listChapter.at(i);
if (p->levelAvg() < LEVEL_NORMAL || p->countNeverAsked() > 0)
m_recom = RecommendationSubChapter;
}
}
if (m_recom == RecommendationNone)
{
//m_recomRepeatDate = repeatDate();
m_recom = recommendationIndividual();
}
}
// Alternative Empfehlung
if (m_recom == RecommendationParentChapter || m_recom == RecommendationSubChapter)
{
m_recom2 = recommendationIndividual();
if (m_recom2 != RecommendationLearnNew && m_recom2 != RecommendationRepeatToday)
m_recom2 = RecommendationNone;
}
// find recommended questions
m_listQuestionRecommended.clear();
QList<CQuestion*> list = questionPool();
for (int i=0; i<list.size(); i++)
{
CQuestion *q = list.at(i);
if (m_recom == RecommendationLearnNew || m_recom2 == RecommendationLearnNew)
{
if (q->isNeverAsked() || q->isLearningNew())
m_listQuestionRecommended.append(q);
}
else if (m_recom == RecommendationRepeatToday || m_recom2 == RecommendationRepeatToday)
{
if (q->isRepeatToday())
m_listQuestionRecommended.append(q);
}
}
// update child chapters
for (int i=0; i<m_listChapter.size(); i++)
{
CChapter *p = m_listChapter.at(i);
p->updateRecommendation();
//m_listQuestionRecommended << p->m_listQuestionRecommended;
}
}
/*
bool CChapter::hasRecommendedQuestions() const
{
return (m_recom == RecommendationLearnNew || m_recom == RecommendationRepeatToday);
}
QList<CQuestion*> CChapter::recommendedQuestions() const
{
QList<CQuestion*> listRet, list = questionPool();
if (m_recom != RecommendationLearnNew && m_recom != RecommendationRepeatToday) return listRet;
for (int i=0; i<list.size(); i++)
{
CQuestion *q = list.at(i);
switch (m_recom)
{
case RecommendationLearnNew:
if (q->isNeverAsked() || q->isLearningNew())
listRet.append(q);
break;
case RecommendationRepeatToday:
if (q->isRepeatToday())
listRet.append(q);
break;
}
}
return listRet;
}
*/
QString CChapter::recommendationText(const Recommendation r, const QDate dRepeat)
{
unsigned uDays=0;
switch (r)
{
default:
case RecommendationNone:
return tr("Keine Lernempfehlung");
case RecommendationSubChapter:
return tr("Zuerst Unterkapitel lernen");
case RecommendationParentChapter:
return tr("Übergeordnetes Kapitel lernen");
case RecommendationLearnNew:
return tr("Neue Fragen lernen");
case RecommendationRepeatToday:
return tr("Heute wiederholen");
case RecommendationRepeatLater:
uDays = QDate::currentDate().daysTo(dRepeat);
if (uDays == 1)
return tr("Morgen wiederholen");
else
return tr("In %1 Tagen wiederholen").arg(uDays);
}
return QString();
}
QString CChapter::recommendationText() const
{
return recommendationText(m_recom, m_recomRepeatDate);
}
QString CChapter::recommendationToolTip() const
{
QString str = recommendationText();
unsigned uCount = recommendedQuestionCount();
if (hasRecommendedQuestions() && m_recom2 == RecommendationNone)
{
str += " ";
if (uCount == 1)
str += tr("(1 Frage)");
else
str += tr("(%1 Fragen)").arg(uCount);
}
if (m_recom2 != RecommendationNone)
{
str += "\n" + tr("Alternativ: ");
if (m_recom2 == RecommendationLearnNew)
{
if (uCount == 1)
str += tr("1 neue Frage lernen");
else
str += tr("%1 neue Fragen lernen").arg(uCount);
}
else if (m_recom2 == RecommendationRepeatToday)
{
if (uCount == 1)
str += tr("1 Frage wiederholen");
else
str += tr("%1 Fragen wiederholen").arg(uCount);
}
else
str += recommendationText (m_recom2, m_recomRepeatDate);
}
return str;
}
QString CChapter::recommendationTextExtended(const CCatalog *pCatalog) const
{
unsigned uDays=0;
QString str;
switch (m_recom)
{
default:
case RecommendationNone:
str = tr("Keine Lernempfehlung");
break;
case RecommendationSubChapter:
str = tr("Dieses Kapitel enthält Unterkapitel, dessen Fragen Sie noch nicht ausreichend gelernt haben.\nEs wird empohlen in kleinen Etappen zu lernen und damit zuerst die Unterkapitel zu vertiefen.");
break;
case RecommendationParentChapter:
if (levelAvgRounded() >= LEVEL_NORMAL)
str = tr("Sie können die Fragen dieses Kapitels gut beantworten.\n");
str += tr("Es wird empfohlen, alle Fragen des übergeordneten Kapitels gemischt zusammen zu lernen.");
break;
case RecommendationLearnNew:
if (!isRecommendedNow(pCatalog))
str = tr("Es gibt andere Kapitel, deren Fragen heute wiederholt werden sollten. Bitte lernen Sie diese Kapitel zuerst.");
else
str = tr("Bitte beantworten Sie alle neuen Fragen mindestens einmal richtig.");
break;
case RecommendationRepeatToday:
str = tr("Bitte lernen Sie alle heute zu wiederholenden Fragen, bis sie eine Lernfortschritts-Stufe höher eingestuft sind.");
break;
case RecommendationRepeatLater:
uDays = QDate::currentDate().daysTo(m_recomRepeatDate);
if (uDays > 1)
str = tr("Die Wiederholung dieses Kapitels ist erst in %1 Tagen geplant.\n").arg(uDays);
else
str = tr("Die Wiederholung dieses Kapitels ist erst für morgen geplant.\n");
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
str += tr("Es gibt andere Kapitel, deren Fragen heute wiederholt werden müssen. Bitte lernen Sie diese Kapitel zuerst.");
else if (pCatalog->m_uRecomCount[RecommendationLearnNew] > 0)
str += tr("Bitte lernen Sie zuerst Kapitel mit neuen Fragen.");
break;
}
if (hasRecommendedQuestions() && isRecommendedNow(pCatalog))
str += tr("<p>Dafür sind noch %1 Fragen zu lernen.").arg(recommendedQuestionCount());
return str;
}
QString CChapter::recommendationTextExtended2(const CCatalog *pCatalog) const
{
QString str;
if (m_recom2 == RecommendationLearnNew || (m_recom == RecommendationLearnNew && !isRecommendedNow(pCatalog)))
{
//str = tr("Bitte beantworten Sie alle neuen Fragen mindestens einmal richtig.");
str = tr("Alternativ können Sie jetzt die neuen Fragen dieses Kapitels lernen (%1 Fragen).").arg(recommendedQuestionCount());
}
else if (m_recom2 == RecommendationRepeatToday)
{
if (m_recom == RecommendationSubChapter)
str = tr("Bitte lernen Sie alle heute zu wiederholenden Fragen, bis sie eine Lernfortschritts-Stufe höher eingestuft sind (%1 Fragen).").arg(recommendedQuestionCount());
else
str = tr("Alternativ können Sie jetzt die heute zu wiederholenden Fragen dieses Kapitels lernen (%1 Fragen).").arg(recommendedQuestionCount());
}
return str;
}
QString CChapter::recommendationIconName(const Recommendation r, const CCatalog *pCatalog)
{
switch (r)
{
case RecommendationSubChapter:
return QString(":/icons/16x16/button_cancel.png");
case RecommendationParentChapter:
return QString(":/icons/16x16/button_ok.png");
case RecommendationLearnNew:
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
return QString(":/icons/16x16/idea_gray.png");
else
return QString(":/icons/16x16/idea.png");
case RecommendationRepeatToday:
return QString(":/icons/16x16/idea.png");
case RecommendationRepeatLater:
return QString(":/icons/16x16/idea_gray.png");
default:
return QString();
}
}
QString CChapter::recommendationIconName(const CCatalog *pCatalog) const
{
return recommendationIconName(m_recom, pCatalog);
}
/*!
\return true: Kapitel kann jetzt gelernt werden,
false: Kapitel sollte überhaupt nicht oder erst später gelernt werden
*/
bool CChapter::isRecommendedNow(const CCatalog *pCatalog) const
{
switch (m_recom)
{
case RecommendationSubChapter:
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] > 0)
return true;
break;
case RecommendationRepeatToday:
return true;
case RecommendationLearnNew:
if (pCatalog->m_uRecomCount[RecommendationRepeatToday] == 0)
return true;
break;
default:
break;
}
return false;
}
/*
\return true: Das Kapitel enthält noch neue Fragen, die gerade (="heute") gelernt werden
bool CChapter::isLearningNew() const
{
for (int i=0; i<m_listQuestion.size(); i++)
if (m_listQuestion.at(i)->isLearningNew()) return true;
for (int i=0; i<m_listChapter.size(); i++)
if (m_listChapter.at(i)->isLearningNew()) return true;
return false;
}
*/
CDayStatistic CChapter::dayStatistic (const QDate& date) const
{
CDayStatistic dsRet, ds;
QList<CQuestion*> listPool = questionPool();
for (int i=0; i<listPool.size(); i++)
{
ds = listPool.at(i)->dayStatistic(date);
dsRet += ds;
}
if (listPool.size() != 0) dsRet.m_dLevel /= listPool.size();
return dsRet;
}
CDayStatistic CChapter::completeStatistic() const
{
return dayStatistic(QDate());
}
QDateTime CChapter::firstAnswerClicked() const
{
QList<CQuestion*> listPool = questionPool();
QDateTime dtRet, dt;
for (int i=0; i<listPool.size(); i++)
{
dt = listPool.at(i)->firstClicked();
if (dt.isNull()) continue;
if (dtRet.isNull() || dt < dtRet) dtRet = dt;
}
return dtRet;
}
double CChapter::levelAvg() const
{
double d=0.0;
double dCount=0.0;
for (int i=0; i<=LEVEL_MAX; i++)
{
d += m_uLevelCount[i] * i;
dCount += m_uLevelCount[i];
}
if (dCount != 0.0) d /= dCount;
return d;
}
unsigned CChapter::levelAvgRounded() const
{
return ((unsigned) (levelAvg()+0.5));
}
QString CChapter::levelAvgText() const
{
return QString("%1").arg(CQuestion::levelText(levelAvgRounded()));
}
QIcon CChapter::levelAvgIcon() const
{
return QIcon(CQuestion::levelIconName(levelAvgRounded()));
}
QPixmap CChapter::levelAvgPixmap() const
{
return QPixmap(CQuestion::levelIconName(levelAvgRounded()));
}
static bool chapterLessThan(const CChapter *c1, const CChapter *c2)
{
return c1->id() < c2->id();
}
void CChapter::sortSubChapters(bool bSortQuestions)
{
if (bSortQuestions) sortQuestions();
qSort (m_listChapter.begin(), m_listChapter.end(), chapterLessThan);
for (int i=0; i<m_listChapter.size(); i++)
{
m_listChapter.at(i)->sortSubChapters(bSortQuestions);
}
}
static bool questionLessThan(const CQuestion *q1, const CQuestion *q2)
{
return q1->id() < q2->id();
}
void CChapter::sortQuestions()
{
qSort (m_listQuestion.begin(), m_listQuestion.end(), questionLessThan);
}

242
chapter.h Normal file
View File

@ -0,0 +1,242 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CHAPTER_H
#define CHAPTER_H
#include "question.h"
//#include "recommendation.h"
//#include "chapterstatistic.h"
#include <qmap.h>
//! Die Klasse CChapter speichert ein Kapitel mit allen Unterkapiteln und Fragen
/*!
*/
class CChapter
{
public:
//! Empfehlung für Kapitel
enum Recommendation
{
RecommendationNone=0, //!< Keine Emfehlung
RecommendationSubChapter=1, //!< Untergeordnetes Kapitel lernen
RecommendationParentChapter=2, //!< Übergeordnetes Kapitel lernen
RecommendationRepeatToday=3, //!< Kapitel heute wiederholen
RecommendationLearnNew=4, //!< Neue Fragen lernen
RecommendationRepeatLater=5, //!< Kapitel später wiederholen
RecommendationMax=6 //!< Für for-Schleifen, etc.
};
//! Standard-Konstruktor
/*! Initialisiert die Klasse, indem die Funktion clear() aufgerufen wird. */
CChapter() { clear(); }
//! Standard-Destruktor
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht. */
~CChapter() { qDeleteAll(m_listChapter); qDeleteAll(m_listQuestion); }
//! Zurücksetzen aller Werte
/*! Es werden alle Unterkapitel und Fragen dieses Kapitels aus dem Speicher gelöscht und alle andere Daten auf die Default-Werte zurückgesetzt. */
void clear();
//! Elternkapitel auslesen
/*!
\return Elternkapitel m_pParentChapter
\sa setParentChapter(), m_pParentChapter
*/
inline CChapter* parentChapter() const { return m_pParentChapter; }
//! Elternkapitel setzen
/*!
Durch diese Funktion wird lediglich die Variable m_pParentChapter gesetzt, jedoch nicht die Statistiken
des Eltern-Kapitels aktualisiert.
\param pChapter Das zu setzende Elternkapitel dieses Kapitels
\sa parentChapter(), m_pParentChapter
*/
inline void setParentChapter(CChapter *pChapter) { m_pParentChapter = pChapter; }
//! ID dieses Kapitels auslesen
inline QString id() const { return m_strId; }
//! ID dieses Kapitels zusammengesetzt mit allen IDs der Eltern-Kapitel auslesen
QString idWithParents() const;
//! Kapitelbeschreibung auslesen
inline QString text() const { return m_strText; }
//! Kommentar
inline QString comment() const { return m_strComment; }
//! ID setzen
inline void setId (const QString& strId) { m_strId = strId; }
//! Kapitelbeschreibung setzen
inline void setText (const QString& strText) { m_strText = strText; }
//! Kommentar setzen
inline void setComment (const QString& strComment) { m_strComment = strComment; }
//! Anhängen eines Textes an die Kapitelbeschreibung
/*!
\param strText Anzuhängender Text
\sa m_strText
*/
inline void appendText(const QString& strText) { m_strText += strText; }
//! Anzahl der Unterkapitel ermitteln
/*! \return Anzahl der Unterkapitel */
inline int countChapter() const { return m_listChapter.size(); }
inline const CChapter* chapterAt(int i) const { return m_listChapter.at(i); }
inline int indexOfChapter(CChapter* c) const { return m_listChapter.indexOf(c); }
inline void appendChapter(CChapter* c) { m_listChapter.append(c); c->setParentChapter(this); }
// inline void removeChapter(int i) { delete m_listChapter.takeAt(i); }
QList<CChapter*> subChapters() const;
inline void sortAll() { sortSubChapters(true); sortQuestions(); }
void sortSubChapters(bool bSortQuestions);
void sortQuestions();
//! Anzahl der Fragen dieses Kapitels und aller Unterkapitel ermitteln
/*! \return Anzahl der Fragen */
int countSubQuestion() const;
//! Anzahl der Fragen dieses Kapitels (ohne Unterkapitel) ermitteln
/*! \return Anzahl der Fragen */
inline int countQuestion() const { return m_listQuestion.size(); }
inline const CQuestion* questionAt(int i) const { return m_listQuestion.at(i); }
inline CQuestion* questionAt(int i) { return m_listQuestion.at(i); }
inline void appendQuestion(CQuestion* q) { m_listQuestion.append(q); q->setParentChapter(this); }
QList<CQuestion*> questionPool() const;
QList<CQuestion*> questionPoolLevel(const unsigned uLevel) const;
QList<CQuestion*> questionPoolDeepen() const;
QList<CQuestion*> questionPoolRepeat(const QDate d=QDate::currentDate()) const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
bool loadLearnStatistic (QDomElement elem);
bool saveLearnStatistic (QDomElement& parent, QDomDocument& doc);
QString checkForErrors() const;
// Kapitelstatistik auslesen
/*
\return Kapitelstatistik (Variable m_cs)
\sa m_cs
*/
// inline CChapterStatistic statistic() const { return m_cs; }
//! @name Funktionen zur Statistik
//@{
void updateStatistic(); //!< Kapitelstatistik aktualisieren
//! Anzahl der Fragen einer bestimmten Abfragehäufigkeit
inline unsigned countQuestion(const unsigned uLevel) const { return m_uLevelCount[uLevel]; }
double levelAvg() const; //!< Durchschnittlicher Lernfortschritt des Kapitels
unsigned levelAvgRounded() const; //!< Durchschnittlicher, gerundeter Lernfortschritt des Kapitels
QString levelAvgText() const; //!< Durchschnittlicher Lernfortschritt als Text
QIcon levelAvgIcon() const; //!< Icon zum durchschnittlichen Lernfortschritt
QPixmap levelAvgPixmap() const; //!< Pixmap zum durchschnittlichen Lernfortschritt
//! Anzahl der noch nie abgefragen Fragen
inline unsigned countNeverAsked() const { return m_uNeverAskedCount; }
//!< Kapitel inkl. Unterkapitel enthalten Fragen, die gerade gelernt werden
inline bool hasLearningNewQuestions() const { return m_bHasLearningNew; }
inline bool hasKnownQuestions() const { return m_bHasKnownQuestions; }
inline bool hasKnownQuestionsRepeatToday() const { return m_bHasKnownQuestionsRepeatToday; }
CDayStatistic dayStatistic (const QDate& date) const; //<! Statistik eines Tages
CDayStatistic completeStatistic() const; //<! Statistik des kompletten Zeitraums
QDateTime firstAnswerClicked() const; //<! Datum, zu dem zum allerersten Mal eine Frage beantwortet wurde
//@}
//! @name Funktionen zur Lernempfehlung
//@{
QDate repeatDate() const; //!< Wiederhol-Datum des Kapitels
//! Lernempfehlung für das Kapitel
/*! \return Lernempfehlung (Variable m_recom) \sa m_recom */
inline Recommendation recommendation() const { return m_recom; }
QString recommendationIconName(const CCatalog *pCatalog) const; //!< Name des Icons zur Lernempfehlung ermitteln
//! Ermittelt Icon zur Lernempfehlung
inline QIcon recommendationIcon (const CCatalog *pCatalog) const { return QIcon (recommendationIconName(pCatalog)); }
QString recommendationText() const; //!< Lernempfehlungstext (kurz)
QString recommendationTextExtended(const CCatalog *pCatalog) const; //!< Lernempfehlungstext (ausführlich)
QString recommendationToolTip() const; //!< Lernempfehlungstext für Tooltip
bool isRecommendedNow(const CCatalog *pCatalog) const; //!< Kapitel sollte jetzt gelernt werden
//! Anzahl der Unterkapitel mit einer bestimmten Lernempfehlung
inline unsigned recommendationCount(const Recommendation r) const { return m_uRecomCount[r]; }
//! Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline QList<CQuestion*> recommendedQuestions() const { return m_listQuestionRecommended; }
//! Kapitel hat Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline bool hasRecommendedQuestions() const { return m_listQuestionRecommended.size() > 0; }
//! Anzahl der Fragen, die beantwortet müssen, um die Lernempfehlung zu erfüllen
inline int recommendedQuestionCount() const { return m_listQuestionRecommended.size(); }
//! Alternative Lernempfehlung für das Kapitel
inline Recommendation recommendation2() const { return m_recom2; }
QString recommendationTextExtended2(const CCatalog *pCatalog) const; //!< Alternativer Lernempfehlungstext (ausführlich)
//@}
//! @name Funktionen zu Prüfungen
//@{
// inline void setExam(const QString& strId, const unsigned uQuestionCount) { m_mapExam.insert(strId, uQuestionCount); }
// inline unsigned examQuestionCount(const QString& strId) const { return m_mapExam[strId]; }
//@}
// static
static QString tr (const char *sourceText, const char *comment=0);
static QString recommendationText(const Recommendation r, const QDate dRepeat);
static QString recommendationIconName(const Recommendation r, const CCatalog *pCatalog);
protected:
void updateStatisticCount(); //!< Zählt alle Fragen des Kapitels (inkl. Unterkapitel) für die Statistik
void updateRecommendation(); //!< Lernempfehlung für das Kapitel (inkl. Unterkapitel) aktualisieren
void updateRecommendationStatistic(); //!< Statistik über Lernempfehlungen für das Kapitel (inkl. Unterkapitel) aktualisieren
Recommendation recommendationIndividual() const; //!< Empfehlung nur für dieses Kapitel, Unterkapitel und Elternkapitel werden ignoriert
protected:
CChapter *m_pParentChapter; //!< Übergeordnetes Kapitel
QString m_strId; //!< ID des Kapitels
QString m_strText; //!< Name des Kapitels
QString m_strComment; //!< Kommentar
QList<CChapter*> m_listChapter; //!< Liste mit Unterkapiteln
QList<CQuestion*> m_listQuestion; //!< Liste mit Fragen
// Statistik
unsigned m_uLevelCount[LEVEL_MAX+1]; //!< Anzahl der Fragen einer bestimmten Abfragehäufigkeit
unsigned m_uNeverAskedCount; //!< Anzahl der Fragen, die noch nie abgefragt wurden
unsigned m_uRecomCount[RecommendationMax]; //!< Anzahl der Unterkapitel (inkl. selbst) mit bestimmter Lernempfehlung
bool m_bHasLearningNew; //!< Kapitel enthält Fragen, die gerade neu gelernt werden
bool m_bHasKnownQuestions; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind
bool m_bHasKnownQuestionsRepeatToday; //!< Kapitel enthält Fragen, die seit mind. gestern bekannt sind und heute wiederholt werden sollten
Recommendation m_recom; //!< Lernempfehlung
Recommendation m_recom2; //!< Alternative Lernempfehlung
//! Empfohlenes Datum zur Wiederholung der Fragen
/*! Diese Variable wird mit der Funktion updateRecommendation() aktualisiert */
QDate m_recomRepeatDate;
//! Liste mit Fragen zum Erfüllen der Lernempfehlung
/*! Diese Liste wird mit der Funktion updateRecommendation() aktualisiert */
QList<CQuestion*> m_listQuestionRecommended;
};
#endif

184
chaptermodel.cpp Normal file
View File

@ -0,0 +1,184 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "chaptermodel.h"
#include "catalog.h"
#include <qtextdocument.h>
#define COL_CHAPTER 0
#define COL_QUESTION 1
#define COL_ASSIST 2
#define COL_AVG 3
CChapterModel::CChapterModel(QObject *pParent) : QAbstractItemModel (pParent)
{
m_pCatalog = 0;
}
CChapterModel::~CChapterModel()
{
}
void CChapterModel::onLanguageChanged()
{
headerDataChanged(Qt::Horizontal, 0, columnCount()-1);
}
void CChapterModel::clear()
{
m_listChapter.clear();
m_pCatalog = 0;
reset();
}
void CChapterModel::setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter)
{
m_listChapter = listChapter;
m_pCatalog = pCatalog;
reset();
}
int CChapterModel::columnCount (const QModelIndex & parent) const
{
Q_UNUSED(parent)
return 4;
}
QVariant CChapterModel::data (const QModelIndex & index, int role) const
{
CChapter *p = (CChapter*) index.internalPointer();
if (m_pCatalog == 0 || !index.isValid()) return QVariant();
if (role == Qt::TextAlignmentRole && index.column() == COL_QUESTION) return Qt::AlignRight;
if (p == 0) return QVariant();
if (role == Qt::DisplayRole)
{
if (index.column() == COL_CHAPTER)
{
if (p->id().isEmpty())
return p->text();
else
return p->idWithParents() + " - " + p->text();
}
else if (index.column() == COL_QUESTION)
return QString("%1").arg(p->countSubQuestion());
else if (index.column() == COL_ASSIST)
{
return p->recommendationText();
/* CRecommendation r(p);
return r.textShort();
*/
}
}
else if (role == Qt::DecorationRole)
{
if (index.column() == COL_CHAPTER)
return QIcon(":/icons/16x16/folder.png");
else if (index.column() == COL_AVG)
{
return p->levelAvgIcon();
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationIcon(m_pCatalog);
//TODO return p->recommendation().icon(m_pCatalog);
}
}
else if (role == Qt::ToolTipRole)
{
if (index.column() == COL_AVG)
{
return QString ("%1 - Kennzahl: %2").arg(p->/*statistic().*/levelAvgText()).arg(p->/*statistic().*/levelAvg(), 4, 'f', 2);
}
else if (index.column() == COL_ASSIST)
{
return p->recommendationToolTip();
//TODO return p->recommendation().recommendationText(m_pCatalog);
}
}
return QVariant();
}
bool CChapterModel::hasChildren (const QModelIndex & parent) const
{
if (parent.isValid()) return false;
return (!m_listChapter.isEmpty());
}
QVariant CChapterModel::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) return QVariant();
if (role == Qt::DisplayRole)
{
if (section == COL_CHAPTER)
return tr("Kapitel");
else if (section == COL_QUESTION)
return tr("Fragen");
else if (section == COL_AVG)
return tr("Ø");
else if (section == COL_ASSIST)
return tr("Lernassistent");
}
else if (role == Qt::ToolTipRole)
{
if (section == COL_CHAPTER)
return tr("Kapitelname\nBitte markieren Sie das Kapitel, das Sie lernen möchten.");
else if (section == COL_QUESTION)
return tr("Anzahl d. Fragen inkl. Unterkapitel");
else if (section == COL_AVG)
return tr("Durchschnittlicher Lernfortschritt");
else if (section == COL_ASSIST)
return tr("Empfehlung des Lernassistentes");
}
else if (role == Qt::WhatsThisRole)
{
}
return QVariant();
}
QModelIndex CChapterModel::index (int row, int column, const QModelIndex & parent) const
{
CChapter *p=0;
if (parent.isValid() || row >= m_listChapter.size()) return QModelIndex();
p = m_listChapter.at (row);
return createIndex (row, column, (void*)p);
}
QModelIndex CChapterModel::parent (const QModelIndex & index) const
{
Q_UNUSED(index);
return QModelIndex();
}
int CChapterModel::rowCount (const QModelIndex & parent) const
{
if (parent.isValid()) return 0;
return m_listChapter.size();
}

60
chaptermodel.h Normal file
View File

@ -0,0 +1,60 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef CHAPTERMODEL_H
#define CHAPTERMODEL_H
#include <qabstractitemmodel.h>
class CChapter;
class CCatalog;
class CChapterModel : public QAbstractItemModel
{
Q_OBJECT
public:
CChapterModel(QObject *pParent=0);
~CChapterModel();
void clear();
void setModelData (CCatalog *pCatalog, QList<CChapter*> listChapter);
public:
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;
virtual bool hasChildren (const QModelIndex & parent = QModelIndex()) const;
virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
virtual QModelIndex index (int row, int column, const QModelIndex & parent = QModelIndex()) const;
virtual QModelIndex parent ( const QModelIndex & index ) const;
virtual int rowCount ( const QModelIndex & parent = QModelIndex() ) const;
public slots:
void onLanguageChanged();
protected:
void recalcColumn();
protected:
CCatalog *m_pCatalog;
QList<CChapter*> m_listChapter;
};
#endif // CHAPTERMODEL_H

300
dlgexam.cpp Normal file
View File

@ -0,0 +1,300 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlgexam.h"
#include "question.h"
#include "error.h"
#include "catalog.h"
#include <qmessagebox.h>
CDlgExam::CDlgExam (CCatalog *pCatalog, QWidget *pParent) : QDialog (pParent, Qt::WindowMaximizeButtonHint)
{
m_pCatalog = pCatalog;
m_iCurrentQuestion = -1;
m_bIsFinished = false;
m_bTimeout = false;
setupUi(this);
connect (&m_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
}
CDlgExam::~CDlgExam ()
{
}
bool CDlgExam::setup (const CExam& exam)
{
m_exam = exam;
labHeader->setText(exam.name());
try
{
m_listQuestion = exam.createQuestionPool(m_pCatalog->questionPool());
}
catch (CError e)
{
QMessageBox::critical(this, tr("Fehler"), e.toHtml());
return false;
}
m_listAnswerMask.clear();
while (m_listAnswerMask.size() < m_listQuestion.size())
m_listAnswerMask.append(0);
// Antworten bei Bedarf durchmischen
if (m_pCatalog->useMixedAnswers())
{
for (int i=0; i<m_listQuestion.size(); i++)
m_listQuestion.at(i)->mixAnswers();
}
init();
return true;
}
void CDlgExam::init()
{
// Zeitbalken & Zeitüberwachung
m_timer.setInterval(1000);
m_timer.start();
m_dtStart = QDateTime::currentDateTime();
pgTime->setMaximum (m_exam.duration() * 60);
// Sonstiges
pgQuestions->setMaximum (m_listQuestion.size());
m_bIsFinished = false;
m_bTimeout = false;
labMaxWrong->setText(QString("%1").arg(m_exam.maxErrorPoints()));
// Navigation
spinBox->setRange (1, m_listQuestion.size());
spinBox->setValue(1);
m_iCurrentQuestion = 1;
// Alles updaten
updateNavi();
showQuestion();
updateProgressTimer();
updateProgressQuestion();
}
void CDlgExam::onTimer()
{
updateProgressTimer();
}
void CDlgExam::updateNavi()
{
pbFirst->setEnabled (spinBox->value() > spinBox->minimum());
pbPrev->setEnabled (spinBox->value() > spinBox->minimum());
pbNext->setEnabled (spinBox->value() < spinBox->maximum());
pbLast->setEnabled (spinBox->value() < spinBox->maximum());
}
unsigned CDlgExam::answeredQuestionCount()
{
unsigned u=0;
for (int i=0; i<m_listAnswerMask.size(); i++)
{
if (m_listAnswerMask.at(i) != 0) u++;
}
return u;
}
void CDlgExam::updateProgressQuestion()
{
unsigned uAnswered = answeredQuestionCount();
labProgressQuestions->setText(tr("%1 von %2").arg(uAnswered).arg(m_listAnswerMask.size()));
pgQuestions->setValue(uAnswered);
}
void CDlgExam::updateProgressTimer()
{
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
labProgessTime->setText(tr("Abgelaufene Zeit: %1:%2 min von %3:00 min")
.arg(uSecs / 60)
.arg(uSecs % 60, 2, 10, QChar('0'))
.arg(m_exam.duration()));
pgTime->setValue (uSecs);
if (uSecs > m_exam.duration()*60)
{
m_bTimeout = true;
m_timer.stop();
QMessageBox::information(this, tr("Information"), tr("Die Zeit ist abgelaufen.\nDie Prüfung wird deswegen beendet."));
on_pbFinish_clicked();
}
}
void CDlgExam::on_pbFirst_clicked()
{
spinBox->setValue(1);
}
void CDlgExam::on_pbPrev_clicked()
{
int iNew = spinBox->value() - 1;
if (iNew < 1) iNew = 1;
spinBox->setValue(iNew);
}
void CDlgExam::on_pbNext_clicked()
{
int iNew = spinBox->value() + 1;
if (iNew > m_listQuestion.size()) iNew = m_listQuestion.size();
spinBox->setValue(iNew);
}
void CDlgExam::on_pbLast_clicked()
{
spinBox->setValue(m_listQuestion.size());
}
void CDlgExam::on_spinBox_valueChanged(int i)
{
Q_UNUSED(i);
onQuestionChanged();
}
void CDlgExam::saveCurrentAnswer()
{
unsigned uAnswerMask=0;
if (m_iCurrentQuestion >= 0)
{ // Antwort zur aktuellen Frage abspeichern
if (rbA->isChecked()) uAnswerMask |= 1;
if (rbB->isChecked()) uAnswerMask |= 2;
if (rbC->isChecked()) uAnswerMask |= 4;
if (rbD->isChecked()) uAnswerMask |= 8;
m_listAnswerMask[m_iCurrentQuestion] = uAnswerMask;
}
}
void CDlgExam::onQuestionChanged()
{
saveCurrentAnswer();
updateNavi();
updateProgressQuestion();
showQuestion(); // neue Frage anzeigen
}
void CDlgExam::showQuestion()
{
CQuestion *q=0;
unsigned uAnswerMask;
QString str;
m_iCurrentQuestion = spinBox->value()-1;
q = m_listQuestion.at(m_iCurrentQuestion);
uAnswerMask = m_listAnswerMask.at(m_iCurrentQuestion);
str = q->learnText(m_pCatalog, m_bIsFinished, false);
if (m_bIsFinished)
{
str += "<hr><p><b>";
if (!q->isCorrectAnswer(uAnswerMask))
str += "<font color='red'>";
else
str += "<font color='green'>";
str += q->correctionText(uAnswerMask) + "</font></p>";
}
textBrowser->setHtml(str);
rbA->setChecked(uAnswerMask & 1);
rbB->setChecked(uAnswerMask & 2);
rbC->setChecked(uAnswerMask & 4);
rbD->setChecked(uAnswerMask & 8);
rbNoIdea->setChecked(uAnswerMask == 0);
}
void CDlgExam::on_pbFinish_clicked()
{
unsigned uCorrect=0, uWrong=0, uAnsweredCount = answeredQuestionCount(), uErrorPoints=0;
bool bSaveStat=true, bPassed=false;
QDateTime dt = QDateTime::currentDateTime();
unsigned uSecs = m_dtStart.secsTo(dt);
saveCurrentAnswer();
if (uAnsweredCount < (unsigned)m_listQuestion.size() && !m_bTimeout)
{
if (QMessageBox::question (this,
tr("Sicherheitsabfrage"),
tr("Sie haben noch nicht alle Fragen beantwortet.\nWirklich abgeben?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::No) return;
}
m_timer.stop();
pbFinish->setEnabled(false);
rbA->setEnabled(false);
rbB->setEnabled(false);
rbC->setEnabled(false);
rbD->setEnabled(false);
rbNoIdea->setEnabled(false);
pbCancel->setText(tr("Beenden"));
m_bIsFinished = true;
showQuestion();
for (int i=0; i<m_listQuestion.size(); i++)
{
CQuestion *q = m_listQuestion.at(i);
unsigned uAnswerMask = m_listAnswerMask.at(i);
if (q->isCorrectAnswer(uAnswerMask))
uCorrect++;
else
{
uWrong++;
uErrorPoints+=q->errorPoints();
}
}
labCorrect->setText(QString("%1").arg(uCorrect));
labWrong->setText(QString("%1").arg(uWrong));
if (uAnsweredCount < (unsigned)m_listQuestion.size()/2)
{
bPassed = false;
bSaveStat = false;
labResult->setText(tr("Ohne Wertung\n(Nicht bestanden)"));
QMessageBox::information(this, tr("Information"), tr("Sie haben weniger als die Hälfte aller Fragen beantwortet.\nDiese Prüfung wird deswegen nicht gewertet."));
}
else if (uErrorPoints > m_exam.maxErrorPoints())
{
bPassed = false;
labResult->setText(tr("<font color='red'>Nicht bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("Sie haben die Prüfung leider nicht bestanden."));
}
else
{
bPassed = true;
labResult->setText(tr("<font color='green'>Bestanden</font>"));
QMessageBox::information(this, tr("Ergebnis"), tr("<b>Herzlichen Glückwunsch!</b><p>Sie haben die Prüfung bestanden!"));
}
if (bSaveStat)
{ // Prüfungsstatistik speichern
CExamStat es(m_exam);
es.setSecs(uSecs);
es.setQuestions(m_listQuestion, m_listAnswerMask);
es.setResult(uCorrect, uWrong, uErrorPoints, bPassed);
m_pCatalog->appendExamStat(es);
m_pCatalog->saveStatistic(this);
}
}

81
dlgexam.h Normal file
View File

@ -0,0 +1,81 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#pragma once
#include "exam.h"
#include "ui_dlgexam.h"
#include <qdialog.h>
#include <qtimer.h>
#include <qdatetime.h>
class CCatalog;
class CQuestion;
class CDlgExam : public QDialog, Ui::DlgExam
{
Q_OBJECT
public:
CDlgExam (CCatalog *pCatalog, QWidget *pParent=0);
~CDlgExam ();
bool setup (const CExam& exam);
protected:
void init();
void updateNavi();
void updateProgressQuestion();
void updateProgressTimer();
void showQuestion();
void onQuestionChanged();
unsigned answeredQuestionCount();
void saveCurrentAnswer();
protected slots:
void onTimer();
void on_pbFirst_clicked();
void on_pbPrev_clicked();
void on_pbNext_clicked();
void on_pbLast_clicked();
void on_spinBox_valueChanged(int i);
void on_pbFinish_clicked();
inline void on_rbA_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbB_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbC_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbD_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
inline void on_rbNoIdea_toggled(bool bChecked) { Q_UNUSED(bChecked); saveCurrentAnswer(); updateProgressQuestion(); }
protected:
CCatalog *m_pCatalog;
CExam m_exam;
QList<CQuestion*> m_listQuestion;
QList<unsigned> m_listAnswerMask;
QTimer m_timer;
QDateTime m_dtStart;
QDateTime m_dtStop;
int m_iCurrentQuestion;
bool m_bIsFinished;
bool m_bTimeout;
};

529
dlgexam.ui Normal file
View File

@ -0,0 +1,529 @@
<ui version="4.0" >
<class>DlgExam</class>
<widget class="QDialog" name="DlgExam" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>607</width>
<height>507</height>
</rect>
</property>
<property name="windowTitle" >
<string>Prüfungssimulation</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="labHeader" >
<property name="font" >
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Bezeichnung</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Frage</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QTextBrowser" name="textBrowser" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>300</width>
<height>300</height>
</size>
</property>
<property name="font" >
<font>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Ihre Antwort</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="rbA" >
<property name="text" >
<string>&amp;A</string>
</property>
<property name="shortcut" >
<string>A</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbB" >
<property name="text" >
<string>&amp;B</string>
</property>
<property name="shortcut" >
<string>B</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbC" >
<property name="text" >
<string>&amp;C</string>
</property>
<property name="shortcut" >
<string>C</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbD" >
<property name="text" >
<string>&amp;D</string>
</property>
<property name="shortcut" >
<string>D</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbNoIdea" >
<property name="text" >
<string>&amp;Keine Ahnung</string>
</property>
<property name="shortcut" >
<string/>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3" >
<property name="title" >
<string>Navigation</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pbFirst" >
<property name="maximumSize" >
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>&lt;&lt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbPrev" >
<property name="maximumSize" >
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>&lt;</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinBox" />
</item>
<item>
<widget class="QPushButton" name="pbNext" >
<property name="maximumSize" >
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>></string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbLast" >
<property name="maximumSize" >
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string>>></string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="maximumSize" >
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="title" >
<string>Zeit</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="labProgessTime" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="pgTime" >
<property name="value" >
<number>24</number>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_5" >
<property name="maximumSize" >
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="title" >
<string>Beantwortete Fragen</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="labProgressQuestions" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="pgQuestions" >
<property name="value" >
<number>24</number>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6" >
<property name="maximumSize" >
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
<property name="title" >
<string>Auswertung</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Richtige Antworten:</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Falsche Antworten:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labWrong" >
<property name="text" >
<string>?</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="labCorrect" >
<property name="text" >
<string>?</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>max. erlaubte falsche Antworten:</string>
</property>
<property name="indent" >
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="labMaxWrong" >
<property name="text" >
<string>10</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="labResult" >
<property name="font" >
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string/>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>31</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="pbFinish" >
<property name="minimumSize" >
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>Abgeben &amp;&amp; auswerten</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="pbCancel" >
<property name="minimumSize" >
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>Abbrechen</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>pbCancel</sender>
<signal>clicked()</signal>
<receiver>DlgExam</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>468</x>
<y>482</y>
</hint>
<hint type="destinationlabel" >
<x>514</x>
<y>501</y>
</hint>
</hints>
</connection>
</connections>
</ui>

93
dlgexamselect.cpp Normal file
View File

@ -0,0 +1,93 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlgexamselect.h"
#include <qmessagebox.h>
#include <qheaderview.h>
#include "catalog.h"
CDlgExamSelect::CDlgExamSelect (QWidget *pParent) : QDialog (pParent)
{
m_pCatalog = 0;
m_iSelectedExam = -1;
setupUi(this);
twList->headerItem()->setText(0, tr("Name"));
twList->headerItem()->setText(1, tr("Dauer (min)"));
//twList->header()->setStretchLastSection(false);
twList->header()->resizeSection(0, 370);
//twList->header()->resizeSection(1, 70);
}
CDlgExamSelect::~CDlgExamSelect ()
{
}
void CDlgExamSelect::setup (const CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
for (int i=0; i<m_pCatalog->countExam(); i++)
{
CExam exam = m_pCatalog->examAt(i);
QTreeWidgetItem *pItem = new QTreeWidgetItem (twList);
pItem->setText(0, exam.name());
pItem->setText(1, QString("%1 min").arg(exam.duration()));
pItem->setTextAlignment(1, Qt::AlignRight);
pItem->setData(0, Qt::UserRole, i);
}
}
void CDlgExamSelect::on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
Q_UNUSED(previous);
if (current)
{
m_iSelectedExam = current->data(0, Qt::UserRole).toInt();
CExam exam = m_pCatalog->examAt(m_iSelectedExam);
labName->setText(exam.name());
labComment->setText(exam.comment());
labDuration->setText(QString("%1 min").arg(exam.duration()));
labQuestions->setText(QString("%1").arg(exam.questionCount()));
labError->setText(QString("%1").arg(exam.maxErrorPoints()));
}
else
{
m_iSelectedExam = -1;
labName->clear();
labComment->clear();
labDuration->clear();
labQuestions->clear();
labError->clear();
}
}
void CDlgExamSelect::on_buttonBox_accepted()
{
if (m_iSelectedExam == -1)
{
QMessageBox::information(this, tr("Information"), tr("Bitte eine Prüfung auswählen!"));
return;
}
accept();
}

46
dlgexamselect.h Normal file
View File

@ -0,0 +1,46 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#pragma once
#include "ui_dlgexamselect.h"
#include <qdialog.h>
class CCatalog;
class CDlgExamSelect : public QDialog, Ui::DlgExamSelect
{
Q_OBJECT
public:
CDlgExamSelect (QWidget *pParent=0);
~CDlgExamSelect ();
void setup (const CCatalog *pCatalog);
inline int selectedExam() const { return m_iSelectedExam; }
protected slots:
void on_buttonBox_accepted();
void on_twList_currentItemChanged (QTreeWidgetItem *current, QTreeWidgetItem *previous);
protected:
const CCatalog *m_pCatalog;
int m_iSelectedExam;
};

178
dlgexamselect.ui Normal file
View File

@ -0,0 +1,178 @@
<ui version="4.0" >
<class>DlgExamSelect</class>
<widget class="QDialog" name="DlgExamSelect" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>491</width>
<height>418</height>
</rect>
</property>
<property name="windowTitle" >
<string>Prüfung auswählen</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Verfügbare Prüfungen</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QTreeWidget" name="twList" >
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Detailinformation</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="0" column="1" >
<widget class="QLabel" name="labName" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labComment" >
<property name="text" >
<string/>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="labDuration" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLabel" name="labQuestions" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLabel" name="labError" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Max. erlaubte Fehler:</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Anzahl Fragen:</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Dauer:</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Hinweise:</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Bezeichnung:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>twList</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgExamSelect</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>291</x>
<y>384</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

109
dlgexamstatistic.cpp Normal file
View File

@ -0,0 +1,109 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlgexamstatistic.h"
#include "catalog.h"
#include <qmessagebox.h>
#include <qheaderview.h>
CDlgExamStatistic::CDlgExamStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pCatalog = 0;
setupUi(this);
twExamStat->headerItem()->setText(0, "Datum/Uhrzeit");
twExamStat->headerItem()->setText(1, "Ergebnis");
twExamStat->headerItem()->setText(2, "Fehler");
twExamStat->headerItem()->setText(3, "Dauer");
twExamStat->headerItem()->setText(4, "Ø pro Frage");
twExamStat->header()->resizeSection(0, 130);
twExamStat->header()->resizeSection(2, 50);
twExamStat->header()->resizeSection(3, 75);
}
void CDlgExamStatistic::go (CCatalog *pCatalog)
{
m_pCatalog = pCatalog;
if (pCatalog->countExamStat() == 0)
{
QMessageBox::information(parentWidget(), tr("Information"), tr("Es wurden bisher noch keine Prüfungen durchgeführt."));
return;
}
cbExam->clear();
for (int i=0; i<pCatalog->countExam(); i++)
{
cbExam->addItem(pCatalog->examAt(i).name(), pCatalog->examAt(i).id());
}
exec();
}
void CDlgExamStatistic::on_cbExam_currentIndexChanged (int index)
{
QString strExamId = cbExam->itemData(index).toString();
CExam exam = m_pCatalog->examById(strExamId);
unsigned uExamCount=0, uPassedCount=0, uFailedCount=0, uErrorCount=0, uDuration=0, uQuestions=0;
QTreeWidgetItem *pItem=0;
twExamStat->clear();
labExamQCount->setText(QString::number(exam.questionCount()));
labExamTime->setText(QString("%1 min").arg(exam.duration()));
labExamWrong->setText(QString::number(exam.maxErrorPoints()));
for (int i=0; i<m_pCatalog->countExamStat(); i++)
{
CExamStat es = m_pCatalog->examStatAt(i);
if (es.id() != strExamId) continue;
uExamCount++;
if (es.passed()) uPassedCount++; else uFailedCount++;
uErrorCount += es.errorPoints();
uDuration += es.duration();
uQuestions += es.correctAnswers() + es.wrongAnswers();
pItem = new QTreeWidgetItem (twExamStat);
pItem->setText(0, es.datetime().toString(Qt::LocalDate));
pItem->setText(1, es.passed() ? tr("Bestanden") : tr("Nicht bestanden"));
pItem->setText(2, QString::number(es.errorPoints()));
pItem->setTextAlignment(2, Qt::AlignRight);
pItem->setText(3, QString("%1 m %2 s").arg(es.duration() / 60).arg(es.duration() % 60, 2, 10, QChar('0')));
pItem->setTextAlignment(3, Qt::AlignRight);
unsigned uQuestionCount = es.correctAnswers() + es.wrongAnswers();
if (uQuestionCount != 0)
pItem->setText(4, QString("%1 m %2 s").arg(es.duration() / uQuestionCount / 60).arg(es.duration() / uQuestionCount % 60, 2, 10, QChar('0')));
else
pItem->setText(4, "--");
pItem->setTextAlignment(4, Qt::AlignRight);
}
labExamCount->setText(QString::number(uExamCount));
labExamPassed->setText(uExamCount != 0 ? QString::number(uPassedCount) : "--");
labExamFailed->setText(uExamCount != 0 ? QString::number(uFailedCount) : "--");
labExamPassedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uPassedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labExamFailedP->setText(uExamCount != 0 ? QString("%1 %").arg((double)uFailedCount / uExamCount * 100.0, 0, 'f', 1) : "--");
labAvgWrong->setText(uExamCount != 0 ? QString::number(uErrorCount / uExamCount) : "--");
labTimeExam->setText(uExamCount != 0 ? QString("%1 m %2 s").arg(uDuration / uExamCount / 60).arg(uDuration / uExamCount % 60, 2, 10, QChar('0')) : "--");
labTimeQuestion->setText(uQuestions != 0 ? QString("%1 m %2 s").arg(uDuration / uQuestions / 60).arg(uDuration / uQuestions % 60, 2, 10, QChar('0')) : "--");
}

43
dlgexamstatistic.h Normal file
View File

@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlgexamstatistic.h"
class CCatalog;
class CDlgExamStatistic : public QDialog, Ui::DlgExamStatistic
{
Q_OBJECT
public:
CDlgExamStatistic(QWidget *pParent=0);
~CDlgExamStatistic() {}
void go (CCatalog *pCatalog);
protected slots:
void on_cbExam_currentIndexChanged (int index);
protected:
CCatalog *m_pCatalog;
};

367
dlgexamstatistic.ui Normal file
View File

@ -0,0 +1,367 @@
<ui version="4.0" >
<class>DlgExamStatistic</class>
<widget class="QDialog" name="DlgExamStatistic" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>452</width>
<height>433</height>
</rect>
</property>
<property name="windowTitle" >
<string>Prüfungs-Statistik</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label" >
<property name="text" >
<string>Prüfung:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbExam" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_11" >
<property name="font" >
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Prüfungs-Rahmenbedinungen</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="1" >
<widget class="QLabel" name="labExamWrong" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="labExamQCount" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_13" >
<property name="text" >
<string>Verfügbare Zeit:</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_14" >
<property name="text" >
<string>Max. erlaubte Anzahl falscher Fragen:</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_12" >
<property name="text" >
<string>Anzahl der Fragen:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labExamTime" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_18" >
<property name="font" >
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Statistik</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="3" column="1" >
<widget class="QLabel" name="labAvgWrong" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labExamPassed" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="labExamFailed" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>davon bestanden:</string>
</property>
<property name="indent" >
<number>10</number>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_10" >
<property name="text" >
<string>Durchschn. Anzahl falscher Fragen:</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>davon nicht bestanden:</string>
</property>
<property name="indent" >
<number>10</number>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="labExamCount" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLabel" name="labExamPassedP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QLabel" name="labExamFailedP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Anzahl Prüfungen durchgeführt:</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Durchschn. benötigte Zeit pro Prüfung / pro Frage:</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLabel" name="labTimeExam" >
<property name="text" >
<string>0 m 0 s</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="2" >
<widget class="QLabel" name="labTimeQuestion" >
<property name="text" >
<string>0 m 0 s</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_19" >
<property name="font" >
<font>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Liste durchgeführter Prüfungen</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="twExamStat" >
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>cbExam</tabstop>
<tabstop>twExamStat</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DlgExamStatistic</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgExamStatistic</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

51
dlginformation.cpp Normal file
View File

@ -0,0 +1,51 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlginformation.h"
#include <qmessagebox.h>
#include "catalog.h"
CDlgInformation::CDlgInformation (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
}
bool CDlgInformation::setup(CCatalog *pCatalog)
{
labName->setText(pCatalog->name());
labVersion->setText(pCatalog->versionText());
labPublished->setText(pCatalog->published().toString(Qt::LocalDate));
labStatQuestion->setText(QString("%1").arg(pCatalog->countSubQuestion()));
labStatChapter->setText(QString("%1").arg(pCatalog->subChapters().size()));
labValidFrom->setText(pCatalog->validFrom().toString(Qt::LocalDate));
labValidUntil->setText(pCatalog->validUntil().toString(Qt::LocalDate));
labDate->setText(pCatalog->created().toString(Qt::LocalDate));
labComment->setText(pCatalog->comment());
labPublisher->setText(pCatalog->publisher());
labContact->setText(pCatalog->contact());
return true;
}

47
dlginformation.h Normal file
View File

@ -0,0 +1,47 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DLGINFORMATION_H
#define DLGINFORMATION_H
#include <qdialog.h>
#include "ui_dlginformation.h"
class CCatalog;
class CDlgInformation : public QDialog, Ui::DlgInformation
{
Q_OBJECT
public:
CDlgInformation (QWidget *pParent=0);
~CDlgInformation () {}
bool setup(CCatalog *pCatalog);
protected slots:
protected:
CCatalog *m_pCatalog;
};
#endif

304
dlginformation.ui Normal file
View File

@ -0,0 +1,304 @@
<ui version="4.0" >
<class>DlgInformation</class>
<widget class="QDialog" name="DlgInformation" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>366</width>
<height>331</height>
</rect>
</property>
<property name="windowTitle" >
<string>Datei-Information</string>
</property>
<property name="windowIcon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/info.png</iconset>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_5" >
<property name="title" >
<string>Original-Fragenkatalog</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="7" column="1" >
<widget class="QLabel" name="labPublisher" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="6" column="1" >
<widget class="QLabel" name="labStatChapter" >
<property name="minimumSize" >
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>0</string>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="QLabel" name="labStatQuestion" >
<property name="minimumSize" >
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>0</string>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLabel" name="labValidUntil" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="labName" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labVersion" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="labPublished" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLabel" name="labValidFrom" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="7" column="0" >
<widget class="QLabel" name="label_7" >
<property name="text" >
<string>Herausgeber:</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="6" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Anzahl der Kapitel:</string>
</property>
</widget>
</item>
<item row="5" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Anzahl der Fragen:</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Gültig bis:</string>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Gültig ab:</string>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_9" >
<property name="text" >
<string>Name:</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_11" >
<property name="text" >
<string>Version:</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_12" >
<property name="text" >
<string>Datum:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4" >
<property name="title" >
<string>AFUTrainer-Fragenkatalog</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="1" >
<widget class="QLabel" name="labContact" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_13" >
<property name="text" >
<string>Erstellt von:</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labComment" >
<property name="text" >
<string>TextLabel</string>
</property>
<property name="wordWrap" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="labDate" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_6" >
<property name="text" >
<string>Kommentar:</string>
</property>
<property name="alignment" >
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label_5" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Erstellt am:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="afutrainer.qrc" />
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DlgInformation</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgInformation</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

435
dlglearn.cpp Normal file
View File

@ -0,0 +1,435 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "catalog.h"
#include "dlglearn.h"
#include "dlgviewquestion.h"
#include "dlglearnassistant.h"
#include "tools.h"
#include <qmessagebox.h>
CDlgLearn::CDlgLearn (QWidget *pParent) : QDialog (pParent, Qt::WindowMaximizeButtonHint)
{
m_pCatalog = 0;
m_pChapter = 0;
m_pQuestion=0;
m_pLastQuestion=0;
m_uLastAnswerMask=0;
m_bHintsUsed=false;
m_uElapsedBeforeBreak=0;
#ifdef _DEBUG
m_bCheatEnable=true;
#else
m_bCheatEnable=false;
#endif
m_bAssistantEnable=true;
setupUi(this);
if (!m_bAssistantEnable)
gbAssistant->hide();
}
CDlgLearn::~CDlgLearn()
{
}
void CDlgLearn::go (CCatalog *pCatalog, CChapter *pChapter)
{
Q_ASSERT (pChapter != 0);
m_pCatalog = pCatalog;
setNewChapter(pChapter);
m_ds = pCatalog->dayStatistic(QDate::currentDate());
onUpdateDS();
exec();
}
void CDlgLearn::setNewChapter(CChapter *pChapter)
{
m_pQuestion=0;
m_bHintsUsed=false;
m_pChapter = pChapter;
m_listQuestion = m_pChapter->questionPool();
nextQuestion();
}
void CDlgLearn::updateStatistic()
{
const int w=60, h=16;
// CHAPTER STATISTICS
labChapter->setText (m_pChapter->text());
labChapterCount->setText(QString("%1").arg(m_listQuestion.size()));
labChapterVeryOften->setText(QString("%1").arg(m_pChapter->countQuestion(0)));
labChapterOften->setText(QString("%1").arg(m_pChapter->countQuestion(1)));
labChapterNormal->setText(QString("%1").arg(m_pChapter->countQuestion(2)));
labChapterRare->setText(QString("%1").arg(m_pChapter->countQuestion(3)));
labChapterVeryRare->setText(QString("%1").arg(m_pChapter->countQuestion(4)));
labChapterExtremeRare->setText(QString("%1").arg(m_pChapter->countQuestion(5)));
labChapterAvgText->setText(m_pChapter->levelAvgText());
labChapterAvgIcon->setPixmap(m_pChapter->levelAvgPixmap());
labChapterAvgIcon->setToolTip(QString("Kennzahl: %1").arg(m_pChapter->levelAvg(), 4, 'g', 2));
double dQuestionCount = m_listQuestion.size(), dPercent;
// dPercent = (double)m_listQuestion.size()/(double)m_pCatalog->countSubQuestion();
// labChapterCountBar->setPixmap(createProgressBar(w, h, dPercent));
// labChapterCountBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(0)/dQuestionCount;
labChapterVeryOftenBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterVeryOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(1)/dQuestionCount;
labChapterOftenBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(2)/dQuestionCount;
labChapterNormalBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterNormalBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(3)/dQuestionCount;
labChapterRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(4)/dQuestionCount;
labChapterVeryRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterVeryRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(5)/dQuestionCount;
labChapterExtremeRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterExtremeRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
// QUESTION STATISTICS
labQuestion->setText (tr("Frage %1").arg(m_pQuestion->id()));
labQuestionLevelIcon->setPixmap(m_pQuestion->levelPixmap());
labQuestionLevelText->setText(m_pQuestion->levelText());
if (m_pQuestion->clickedCorrectSuccessive() != 0)
labQuestionSuccessive->setText(tr("%1x richtig").arg(m_pQuestion->clickedCorrectSuccessive()));
else if (m_pQuestion->clickedWrongSuccessive() != 0)
labQuestionSuccessive->setText(tr("%1x falsch").arg(m_pQuestion->clickedWrongSuccessive()));
else
labQuestionSuccessive->setText(tr("--"));
labQuestionCount->setText(QString("%1").arg(m_pQuestion->clickedCount()));
labQuestionCorrect->setText(QString("%1").arg(m_pQuestion->clickedCorrect()));
labQuestionWrong->setText(QString("%1").arg(m_pQuestion->clickedWrong()));
QDateTime dtLastClicked = m_pQuestion->lastClicked();
if (!dtLastClicked.isValid())
labQuestionDate->setText("--");
else
{
labQuestionDate->setText(m_pQuestion->lastClickedText());
}
onUpdateDS();
}
void CDlgLearn::updateLearnAssistant()
{
QString strRecom1, strRecom2, str;
QPixmap pixRecom1, pixRecom2, pix;
// first recommendation
strRecom1 = m_pChapter->recommendationTextExtended(m_pCatalog);
if (m_pChapter->isRecommendedNow(m_pCatalog))
strRecom1 = "<font color='green'>" + strRecom1 + "</font>";
else
strRecom1 = "<font color='red'>" + strRecom1 + "</font>";
pixRecom1 = QPixmap (m_pChapter->recommendationIconName (m_pCatalog));
// second recommendation
strRecom2 = m_pChapter->recommendationTextExtended2(m_pCatalog);
pixRecom2 = QPixmap (m_pChapter->recommendationIconName (m_pChapter->recommendation2(), m_pCatalog));
if (m_pChapter->recommendation() == CChapter::RecommendationSubChapter && m_pChapter->recommendation2() == CChapter::RecommendationRepeatToday)
{
labRecommendationIcon->setPixmap (pixRecom2);
labRecommendation->setText("<font color='green'>" + strRecom2 + "</font>");
}
else
{
str = strRecom1;
if (!strRecom2.isEmpty())
str += "<p><font color='green'>" + strRecom2 + "</font>";
labRecommendationIcon->setPixmap (pixRecom1);
labRecommendation->setText(str);
}
}
CQuestion *CDlgLearn::findNextQuestion()
{
CQuestion *p = 0;
if (m_bAssistantEnable && m_pChapter->hasRecommendedQuestions())
{
// if (afu_random (0, 99) >= 0) // hier kann ggf. das Verhältnis zwischen RecommendedQuestion und Zufalls-Question ausgewählt werden
// {
p = findNextTargetQuestion();
// Wichtig: p kann hier immernoch 0 sein! Dies bedeutet, dass keine passende Frage im TargetPool gefunden wurde.
// }
}
if (p == 0)
p = findNextPoolQuestion();
return p;
}
CQuestion *CDlgLearn::findNextTargetQuestion()
{
CQuestion *pQuestion=0;
QList<CQuestion*> list = m_pChapter->recommendedQuestions();
int iSize = list.size();
unsigned uRnd=0;
if (iSize == 0) return 0;
if (iSize == 1)
{
if (list.at(0) == m_pQuestion)
// Regel: Niemals die gleiche Frage mehrfach hintereinander
// -> kann hier nicht erfüllt werden -> 0 zurückgeben -> hole Frage aus allg. Pool (siehe findNextQuestion)
return 0;
else
return list.at(0);
}
do
{
uRnd = afu_random (0, iSize-1);
pQuestion = list.at(uRnd);
}
while (m_pQuestion == pQuestion);
return pQuestion;
}
CQuestion *CDlgLearn::findNextPoolQuestion()
{
CQuestion *pQuestion=0;
unsigned uCountQuestion[LEVEL_MAX+1];
unsigned uRnd=0, uLevel=0;
int i=0;
unsigned uGewichtung[LEVEL_MAX+1], uEdge[LEVEL_MAX+1];
unsigned uRndMax = 0;
memset (uCountQuestion, 0, sizeof(unsigned)*(LEVEL_MAX+1));
for (i=0;i<m_listQuestion.size(); i++)
{
uLevel = m_listQuestion[i]->level();
Q_ASSERT(uLevel < LEVEL_MAX+1);
if (uLevel > LEVEL_MAX) continue;
uCountQuestion[uLevel]++;
}
uGewichtung[LEVEL_MAX] = 1;
uRndMax = 1;
for (i=LEVEL_MAX-1; i>=0; i--)
{
uRndMax += uGewichtung[i+1];
uGewichtung[i] = uRndMax;
}
for (i=0; i<=LEVEL_MAX; i++)
uGewichtung[i] *= uCountQuestion[i];
uRndMax=0;
for (i=0; i<=LEVEL_MAX; i++)
{
uLevel = LEVEL_MAX-i;
uRndMax += uGewichtung[uLevel];
uEdge[uLevel] = uRndMax;
}
do /* diese Schleife verhindert, dass eine Frage zweimal hintereinander kommt */
{
do /* diese Schleife wählt die Abfragehäufigkeit aus */
{
uRnd = afu_random (1, uRndMax);
uLevel = LEVEL_MAX;
while (uLevel != LEVEL_VERYOFTEN && uRnd > uEdge[uLevel])
uLevel--;
Q_ASSERT(uCountQuestion[uLevel] != 0); // Wenn hier assertion failed => algorithmus falsch
}
while (uCountQuestion[uLevel] == 0);
// Zufällige Frage bestimmen
uRnd = afu_random (1, uCountQuestion[uLevel]);
for (i=0; i<m_listQuestion.size()-1; i++)
if (m_listQuestion[i]->level() == uLevel && --uRnd == 0) break;
}
while (m_pQuestion == m_listQuestion[i] && m_listQuestion.size() > 1);
pQuestion = m_listQuestion[i];
return pQuestion;
}
void CDlgLearn::nextQuestion()
{
QString str, strCheat;
if (m_listQuestion.size() == 0)
{
QMessageBox::critical (this, "Fehler", "Es gibt keine Fragen, die gelernt werden könnten!");
accept();
return;
}
if (m_pQuestion)
{ // Save current question as new last question
pbLastQuestion->setEnabled(true);
m_pLastQuestion = m_pQuestion;
}
m_pQuestion = findNextQuestion();
// show answer
m_pQuestion->mixAnswers();
str = m_pQuestion->learnText(m_pCatalog, true, false);
if (m_bCheatEnable)
{
strCheat = "<p><font size=-1><i><b>Schummel-Modus</b><br>Richtige Antwort: " + CAnswerClicked::answerText (m_pQuestion->correctAnswerMask()) + "</i>";
strCheat += "<br>Empfohlene Wiederholung: " + m_pQuestion->repeatDateText();
strCheat += QString("<br>isLearningNew(): %1").arg(m_pQuestion->isLearningNew());
strCheat += "</font><p>";
}
teQuestion->setHtml(strCheat + str);
pbShowHelper->setEnabled (m_pCatalog->hasHints(m_pQuestion->id()));
m_bHintsUsed = false;
m_timeElapsed.restart();
updateStatistic();
updateLearnAssistant();
}
void CDlgLearn::on_pbAnswerA_clicked()
{
handleAnswer(0);
}
void CDlgLearn::on_pbAnswerB_clicked()
{
handleAnswer(1);
}
void CDlgLearn::on_pbAnswerC_clicked()
{
handleAnswer(2);
}
void CDlgLearn::on_pbAnswerD_clicked()
{
handleAnswer(3);
}
void CDlgLearn::handleAnswer(const int i)
{
unsigned uAnswerMask = 1<<i;
if (!m_pQuestion->isCorrectAnswer(uAnswerMask))
{
QMessageBox::information(this, tr("Hinweis"), m_pQuestion->correctionText(uAnswerMask));
}
m_uLastAnswerMask=uAnswerMask;
if (!m_bHintsUsed)
{
m_pQuestion->registerAnswerClicked(uAnswerMask, m_timeElapsed.elapsed() + m_uElapsedBeforeBreak);
bool bIsRecommendedOld = m_pChapter->isRecommendedNow(m_pCatalog) ;
m_pCatalog->updateStatistic();
m_ds = m_pCatalog->dayStatistic(QDate::currentDate());
if (bIsRecommendedOld && !m_pChapter->isRecommendedNow(m_pCatalog))
{
QMessageBox msgBox(this);
QPushButton *pbAssistant = msgBox.addButton(tr("Assistent"), QMessageBox::AcceptRole);
QPushButton *pbIgnore = msgBox.addButton(QMessageBox::Ignore);
QPushButton *pbExit = msgBox.addButton(QMessageBox::Cancel);
pbAssistant->setIcon(QIcon(":/icons/16x16/idea_info.png"));
pbAssistant->setToolTip(tr("Lern-Assistent aufrufen"));
pbIgnore->setToolTip(tr("Meldung ignorieren, dieses Kapitel weiterlernen"));
pbExit->setToolTip(tr("Lernmodus beenden"));
msgBox.setText(tr("<b>Herzlichen Glückwunsch!</b><p>Sie haben das heutige Lernziel für dieses Kapitel erreicht.<br>Bitte folgen Sie den weiteren Empfehlungen des Lernassistents."));
msgBox.setWindowTitle(tr("Ziel erreicht"));
msgBox.exec();
if (msgBox.clickedButton() == pbExit)
{
reject();
return;
}
else if (msgBox.clickedButton() == pbAssistant)
{
on_pbLearnAssistant_clicked();
return;
}
}
}
nextQuestion();
}
void CDlgLearn::on_pbShowHelper_clicked()
{
m_bHintsUsed = true;
QString str = m_pQuestion->learnText(m_pCatalog, true, true);
teQuestion->setHtml(str);
}
void CDlgLearn::on_pbLastQuestion_clicked()
{
CDlgViewQuestion dlg(this);
dlg.go(m_pCatalog, m_pLastQuestion, m_uLastAnswerMask);
}
void CDlgLearn::on_pbSkip_clicked()
{
m_uLastAnswerMask=0;
nextQuestion();
}
void CDlgLearn::on_pbQuit_clicked()
{
m_pCatalog->updateStatistic();
accept();
}
void CDlgLearn::on_pbLearnAssistant_clicked()
{
CDlgLearnAssistant dlg(this);
CChapter *pChapter=0;
if (!dlg.setup(m_pCatalog))
{
QMessageBox::information(this, tr("Information"), tr("Derzeit gibt es keine Empfehlung des Lernassistentes."));
return;
}
if (dlg.exec() != QDialog::Accepted) return;
pChapter = dlg.selectedChapter();
if (pChapter == 0) return;
setNewChapter(pChapter);
}
void CDlgLearn::onUpdateDS()
{
labDSTime->setText(QString("%1 h %2 m").arg(m_ds.timeExpediture()/1000/3600).arg(m_ds.timeExpediture()/1000/60 % 60, 2, 10, QChar('0')));
labDSCount->setText(QString::number(m_ds.clickedCount()));
labDSCorrect->setText(QString::number(m_ds.clickedCorrect()));
labDSWrong->setText(QString::number(m_ds.clickedWrong()));
}

84
dlglearn.h Normal file
View File

@ -0,0 +1,84 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DLGLEARN_H
#define DLGLEARN_H
#include <qdialog.h>
#include <qlist.h>
#include <qdatetime.h>
#include "question.h"
#include "ui_dlglearn.h"
class CChapter;
class CCatalog;
class CDlgLearn : public QDialog, Ui::DlgLearn
{
Q_OBJECT
public:
CDlgLearn (QWidget *pParent=0);
~CDlgLearn();
void go (CCatalog *pCatalog, CChapter *pChapter);
protected:
void setNewChapter(CChapter *pChapter);
void updateStatistic();
void updateLearnAssistant();
void nextQuestion();
CQuestion *findNextQuestion();
CQuestion *findNextPoolQuestion();
CQuestion *findNextTargetQuestion();
void handleAnswer(const int i);
protected slots:
void on_pbAnswerA_clicked();
void on_pbAnswerB_clicked();
void on_pbAnswerC_clicked();
void on_pbAnswerD_clicked();
void on_pbShowHelper_clicked();
void on_pbSkip_clicked();
void on_pbLastQuestion_clicked();
void on_pbQuit_clicked();
void on_pbLearnAssistant_clicked();
void onUpdateDS();
protected:
CCatalog *m_pCatalog;
CChapter *m_pChapter;
QList<CQuestion*> m_listQuestion;
CQuestion *m_pQuestion;
CQuestion *m_pLastQuestion;
unsigned m_uLastAnswerMask;
bool m_bHintsUsed;
QTime m_timeElapsed;
unsigned m_uElapsedBeforeBreak; // if the user makes a break
bool m_bMsgBoxTargetReachedShowed;
CDayStatistic m_ds;
bool m_bAssistantEnable;
bool m_bCheatEnable;
};
#endif

1139
dlglearn.ui Normal file

File diff suppressed because it is too large Load Diff

117
dlglearnassistant.cpp Normal file
View File

@ -0,0 +1,117 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlglearnassistant.h"
#include <qheaderview.h>
#include <qmessagebox.h>
#include "catalog.h"
CDlgLearnAssistant::CDlgLearnAssistant (QWidget *pParent) : QDialog(pParent)
{
m_pCatalog=0;
setupUi(this);
tvChapters->setModel (&m_modelChapter);
tvChapters->header()->setStretchLastSection(false);
tvChapters->header()->setResizeMode (0, QHeaderView::Stretch);
tvChapters->header()->setResizeMode (1, QHeaderView::Interactive);
tvChapters->header()->setResizeMode (3, QHeaderView::Interactive);
tvChapters->header()->resizeSection(1, 50);
tvChapters->header()->resizeSection(2, 140);
tvChapters->header()->resizeSection(3, 20);
}
bool CDlgLearnAssistant::setup(CCatalog *pCatalog)
{
bool bEnableRepeat;
QList<CChapter*> listAll, listNow, listToday, listSelected;
CChapter *c;
m_pCatalog = pCatalog;
if (pCatalog->recommendationCount (CChapter::RecommendationRepeatToday) > 0)
{
bEnableRepeat = true;
labRepeat->setText(tr("Es sind %1 Fragen vorhanden").arg(pCatalog->recommendedQuestions().count()));
rbRepeat->setChecked(true);
}
else
{
bEnableRepeat = false;
labRepeat->setText(tr("Keine Fragen vorhanden."));
rbList->setChecked(true);
}
rbRepeat->setEnabled(bEnableRepeat);
labRepeat->setEnabled(bEnableRepeat);
// update list
listAll = pCatalog->chapters();
for (int i=0; i<listAll.size(); i++)
{
c = listAll.at(i);
if (c->isRecommendedNow(pCatalog))
listNow << c;
else if (c->recommendation() == CChapter::RecommendationLearnNew)
listToday << c;
}
listSelected << listNow << listToday;
m_modelChapter.setModelData (pCatalog, listSelected);
if (!bEnableRepeat && listSelected.isEmpty()) return false;
updateEnable();
return true;
}
void CDlgLearnAssistant::updateEnable()
{
labRepeat->setEnabled(rbRepeat->isChecked());
tvChapters->setEnabled(rbList->isChecked());
}
void CDlgLearnAssistant::on_buttonBox_accepted()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbList->isChecked() && list.isEmpty())
{
QMessageBox::information(this, tr("Information"), tr("Bitte markieren Sie in der Liste ein Kapitel, das Sie lernen möchten!"));
return;
}
accept();
}
CChapter* CDlgLearnAssistant::selectedChapter()
{
QModelIndexList list = tvChapters->selectionModel()->selectedIndexes();
if (rbRepeat->isChecked())
return m_pCatalog;
if (rbList->isChecked())
{
if (list.isEmpty()) return 0;
return (CChapter*)list.first().internalPointer();
}
return 0;
}

56
dlglearnassistant.h Normal file
View File

@ -0,0 +1,56 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DLGLEARNASSISTANT_H
#define DLGLEARNASSISTANT_H
#include <qdialog.h>
#include "ui_dlglearnassistant.h"
#include "chaptermodel.h"
class CDlgLearnAssistant : public QDialog, Ui::DlgLearnAssistant
{
Q_OBJECT
public:
CDlgLearnAssistant (QWidget *pParent=0);
~CDlgLearnAssistant () {}
bool setup(CCatalog *pCatalog);
CChapter* selectedChapter();
protected slots:
void on_buttonBox_accepted();
inline void on_rbList_toggled() { updateEnable(); }
inline void on_rbRepeat_toggled() { updateEnable(); }
protected:
void updateEnable();
protected:
CCatalog *m_pCatalog;
CChapterModel m_modelChapter;
// CRecommendation m_recomDeepen;
// CRecommendation m_recomRepeat;
};
#endif

112
dlglearnassistant.ui Normal file
View File

@ -0,0 +1,112 @@
<ui version="4.0" >
<class>DlgLearnAssistant</class>
<widget class="QDialog" name="DlgLearnAssistant" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>493</width>
<height>422</height>
</rect>
</property>
<property name="windowTitle" >
<string>Lern-Assistent</string>
</property>
<property name="windowIcon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/idea_info.png</iconset>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Vorschläge des Lern-Assistents</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QRadioButton" name="rbRepeat" >
<property name="text" >
<string>Alle heute zu wiederholenden Fragen lernen</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labRepeat" >
<property name="text" >
<string>TextLabel</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbList" >
<property name="text" >
<string>Kapitel aus folgender Liste lernen</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="tvChapters" >
<property name="rootIsDecorated" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>rbRepeat</tabstop>
<tabstop>rbList</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources>
<include location="afutrainer.qrc" />
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgLearnAssistant</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>293</x>
<y>397</y>
</hint>
<hint type="destinationlabel" >
<x>416</x>
<y>418</y>
</hint>
</hints>
</connection>
</connections>
</ui>

417
dlglearnstatistic.cpp Normal file
View File

@ -0,0 +1,417 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlglearnstatistic.h"
#include "chapter.h"
#include "tools.h"
#include "plotwidget.h"
#include <qdatetime.h>
CDlgLearnStatistic::CDlgLearnStatistic(QWidget *pParent) : QDialog(pParent)
{
m_pChapter = 0;
setupUi(this);
cbPeriod->addItem(tr("2 Wochen"), 14);
cbPeriod->addItem(tr("1 Monat"), 30);
cbPeriod->addItem(tr("3 Monate"), 90);
cbPeriod->addItem(tr("6 Monate"), 30*6);
cbPeriod->addItem(tr("1 Jahr"), 365);
cbPeriod->setCurrentIndex(0);
m_pPlotLevel = new CPlotWidget(groupLevel);
m_pPlotLevel->setFrameShape(QFrame::Panel);
m_pPlotLevel->setFrameShadow(QFrame::Sunken);
groupLevel->layout()->addWidget(m_pPlotLevel);
m_pPlotLevel->setBorderDistance(25, 5, 5, 25);
m_pPlotLevel->setLimitY(0.0, 5.5);
m_pPlotLevel->setBorderPen(QPen(Qt::black));
m_pPlotLevel->setBorder(CPlotWidget::BorderLeft | CPlotWidget::BorderBottom);
m_pPlotLevel->setTicY(1.0);
QList<CPlotWidgetTic> listTics;
for (int i=0; i<=LEVEL_MAX; i++)
{
CPlotWidgetTic tic (i, QPixmap(CQuestion::levelIconName(i)));
listTics.append(tic);
}
m_pPlotLevel->setTicListY(listTics);
m_pPlotClicked = new CPlotWidget(groupClicked);
m_pPlotClicked->setFrameShape(QFrame::Panel);
m_pPlotClicked->setFrameShadow(QFrame::Sunken);
groupClicked->layout()->addWidget(m_pPlotClicked);
m_pPlotClicked->setType(CPlotWidget::PlotBarsSum);
m_pPlotClicked->setBarOffset(-0.5);
m_pPlotClicked->setBorderDistance(25, 5, 5, 25);
// Zeitaufwand
cbPeriod2->addItem(tr("2 Wochen"), 14);
cbPeriod2->addItem(tr("1 Monat"), 30);
cbPeriod2->addItem(tr("3 Monate"), 90);
cbPeriod2->addItem(tr("6 Monate"), 30*6);
cbPeriod2->addItem(tr("1 Jahr"), 365);
cbPeriod2->setCurrentIndex(0);
m_pPlotTime = new CPlotWidget(groupTimeExpediture);
m_pPlotTime->setFrameShape(QFrame::Panel);
m_pPlotTime->setFrameShadow(QFrame::Sunken);
groupTimeExpediture->layout()->addWidget(m_pPlotTime);
m_pPlotTime->setType(CPlotWidget::PlotBarsSum);
m_pPlotTime->setBarOffset(-0.5);
m_pPlotTime->setBorderDistance(25, 5, 5, 25);
/*
m_pPlotTimePerQuestion = new CPlotWidget(groupTimeExpediturePerQuestion);
m_pPlotTimePerQuestion->setFrameShape(QFrame::Panel);
m_pPlotTimePerQuestion->setFrameShadow(QFrame::Sunken);
groupTimeExpediturePerQuestion->layout()->addWidget(m_pPlotTimePerQuestion);
m_pPlotTimePerQuestion->setType(CPlotWidget::PlotLines);
m_pPlotTimePerQuestion->setBorderDistance(25, 5, 5, 25);
*/
}
void CDlgLearnStatistic::go(CChapter *pChapter)
{
m_pChapter = pChapter;
updateTable();
updateHistory();
updateTimeExpediture();
exec();
}
void CDlgLearnStatistic::updateTable()
{
const int w=60, h=16;
QList<CQuestion*> listQuestion = m_pChapter->questionPool();
CDayStatistic ds;
// CHAPTER STATISTICS
labChapter->setText (m_pChapter->text());
labChapterCount->setText(QString("%1").arg(listQuestion.size()));
labChapterVeryOften->setText(QString("%1").arg(m_pChapter->countQuestion(0)));
labChapterOften->setText(QString("%1").arg(m_pChapter->countQuestion(1)));
labChapterNormal->setText(QString("%1").arg(m_pChapter->countQuestion(2)));
labChapterRare->setText(QString("%1").arg(m_pChapter->countQuestion(3)));
labChapterVeryRare->setText(QString("%1").arg(m_pChapter->countQuestion(4)));
labChapterExtremeRare->setText(QString("%1").arg(m_pChapter->countQuestion(5)));
labChapterAvgText->setText(m_pChapter->levelAvgText());
labChapterAvgIcon->setPixmap(m_pChapter->levelAvgPixmap());
labChapterAvgIcon->setToolTip(QString("Kennzahl: %1").arg(m_pChapter->levelAvg(), 4, 'g', 2));
double dQuestionCount = listQuestion.size(), dPercent=0.0;
dPercent = (double)m_pChapter->countQuestion(0)/dQuestionCount;
labChapterVeryOftenBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterVeryOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(1)/dQuestionCount;
labChapterOftenBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterOftenBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(2)/dQuestionCount;
labChapterNormalBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterNormalBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(3)/dQuestionCount;
labChapterRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(4)/dQuestionCount;
labChapterVeryRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterVeryRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
dPercent = (double)m_pChapter->countQuestion(5)/dQuestionCount;
labChapterExtremeRareBar->setPixmap(createProgressBar(w, h, dPercent));
labChapterExtremeRareBar->setToolTip(QString("%1 %").arg(dPercent * 100, 0, 'f', 1));
ds = m_pChapter->dayStatistic(QDate());
labClickCount->setText(QString::number(ds.clickedCount()));
labClickCorrect->setText(QString::number(ds.clickedCorrect()));
labClickWrong->setText(QString::number(ds.clickedWrong()));
labClickCorrectP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedCorrect() / ds.clickedCount(), 0, 'f', 1) : "--");
labClickWrongP->setText(ds.clickedCount() != 0 ? QString("%1 %").arg(100.0 * ds.clickedWrong() / ds.clickedCount(), 0, 'f', 1) : "--");
labTimeExpediture->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpediture() / 3600000).arg(ds.timeExpediture() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpediture()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrect->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureCorrect() / 3600000).arg(ds.timeExpeditureCorrect() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureCorrect()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureWrong->setText(QString("%1 h %2 m %3 s").arg(ds.timeExpeditureWrong() / 3600000).arg(ds.timeExpeditureWrong() / 60000 % 60, 2, 10, QChar('0')).arg(ds.timeExpeditureWrong()/1000 % 60, 2, 10, QChar('0')));
labTimeExpeditureCorrectP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureCorrect() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimeExpeditureWrongP->setText(ds.timeExpediture() != 0 ? QString("%1 %").arg(100.0 * ds.timeExpeditureWrong() / ds.timeExpediture(), 0, 'f', 1) : "--");
labTimePerQuestion->setText(ds.clickedCount() != 0 ? QString("%2 m %3 s").arg(ds.timeExpediture() / ds.clickedCount() / 60000).arg(ds.timeExpediture() / 1000 / ds.clickedCount() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionCorrect->setText(ds.clickedCorrect() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureCorrect() / ds.clickedCorrect() / 60000).arg(ds.timeExpeditureCorrect() / 1000 / ds.clickedCorrect() % 60, 2, 10, QChar('0')) : "--");
labTimePerQuestionWrong->setText(ds.clickedWrong() != 0 ? QString("%2 m %3 s").arg(ds.timeExpeditureWrong() / ds.clickedWrong() / 60000).arg(ds.timeExpeditureWrong() / 1000 / ds.clickedWrong() % 60, 2, 10, QChar('0')) : "--");
}
void CDlgLearnStatistic::on_cbPeriod_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateHistory();
}
void CDlgLearnStatistic::updateHistory()
{
int iDays = cbPeriod->itemData(cbPeriod->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveLevel, curveClickedCorrect, curveClickedWrong;
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxClicked=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveLevel.append(CPlotWidgetPoint(idx, ds.level()));
curveClickedCorrect.append(CPlotWidgetPoint((double)idx, ds.clickedCorrect()));
curveClickedWrong.append(CPlotWidgetPoint((double)idx, ds.clickedWrong()));
if (ds.clickedCount() > uMaxClicked) uMaxClicked = ds.clickedCount();
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotLevel->setTicListX(listTics);
m_pPlotClicked->setTicListX(listTics);
curveLevel.setPen(QPen(Qt::darkBlue));
curveClickedCorrect.setPen(QPen(Qt::green));
curveClickedCorrect.setBrush(QBrush(Qt::green));
curveClickedWrong.setPen(QPen(Qt::red));
curveClickedWrong.setBrush(QBrush(Qt::red));
m_pPlotLevel->clearCurves();
m_pPlotLevel->appendCurve(curveLevel);
m_pPlotLevel->update();
m_pPlotClicked->clearCurves();
m_pPlotClicked->appendCurve(curveClickedCorrect);
m_pPlotClicked->appendCurve(curveClickedWrong);
m_pPlotClicked->update();
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxClicked / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotClicked->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotClicked->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}
void CDlgLearnStatistic::on_cbPeriod2_currentIndexChanged(int index)
{
Q_UNUSED(index);
updateTimeExpediture();
}
void CDlgLearnStatistic::updateTimeExpediture()
{
int iDays = cbPeriod2->itemData(cbPeriod2->currentIndex()).toInt(), idx=0;
CPlotWidgetCurve curveTimeWrong, curveTimeCorrect,curveTimePQWrong, curveTimePQCorrect; // PQ=per question
QDate date = QDate::currentDate();
CDayStatistic ds;
QList<CPlotWidgetTic> listTics;
CPlotWidgetTic tic;
bool bAddTic=false;
unsigned uMaxTime=0;
if (m_pChapter == 0) return;
setCursor(Qt::WaitCursor);
date = date.addDays(-iDays);
tic.setLineType(CPlotWidgetTic::LineNone);
tic.setFillType(CPlotWidgetTic::FillAll);
tic.setPen(QPen(Qt::darkGray));
while (date <= QDate::currentDate())
{
if (bAddTic)
{
bAddTic=false;
tic.setPos(idx-1);
if (listTics.size() % 2)
tic.setBrush(QBrush(Qt::white));
else
tic.setBrush(QBrush(QColor(232,232,232)));
listTics.append(tic);
}
ds = m_pChapter->dayStatistic(date);
curveTimeWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0));
curveTimeCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0));
/* if (ds.clickedWrong() > 0)
curveTimePQWrong.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureWrong()/1000.0/60.0/(double)ds.clickedWrong()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));
if (ds.clickedCorrect() > 0)
curveTimePQCorrect.append(CPlotWidgetPoint(idx, (double)ds.timeExpeditureCorrect()/1000.0/60.0/(double)ds.clickedCorrect()));
else
curveTimePQWrong.append(CPlotWidgetPoint(idx, 0));*/
if (ds.timeExpediture()/1000/60 > uMaxTime) uMaxTime = ds.timeExpediture()/1000/60;
date = date.addDays(1);
// X-Tics
if (iDays <= 14)
{ // daily tics
tic.setText(date.toString("ddd"));
tic.setWidth(1);
if (date.dayOfWeek() == Qt::Monday)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
else if (iDays <= 90 && date.dayOfWeek() == Qt::Monday)
{
tic.setText(QString("KW %1").arg(date.weekNumber()));
tic.setWidth(7);
bAddTic=true;
}
else if (iDays > 90 && date.day() == 1)
{
tic.setText(date.toString("MMM"));
tic.setWidth(date.daysInMonth());
if (date.month() == 1)
tic.setLineType(CPlotWidgetTic::LinePlot);
else
tic.setLineType(CPlotWidgetTic::LineNone);
bAddTic=true;
}
idx++;
}
m_pPlotTime->setTicListX(listTics);
//m_pPlotTimePerQuestion->setTicListX(listTics);
curveTimeCorrect.setPen(QPen(Qt::green));
curveTimeCorrect.setBrush(QBrush(Qt::green));
curveTimeWrong.setPen(QPen(Qt::red));
curveTimeWrong.setBrush(QBrush(Qt::red));
m_pPlotTime->clearCurves();
m_pPlotTime->appendCurve(curveTimeCorrect);
m_pPlotTime->appendCurve(curveTimeWrong);
m_pPlotTime->update();
/*
m_pPlotTimePerQuestion->clearCurves();
m_pPlotTimePerQuestion->appendCurve(curveTimePQCorrect);
m_pPlotTimePerQuestion->appendCurve(curveTimePQWrong);
m_pPlotTimePerQuestion->setAutoLimitRoundY(0.1);
m_pPlotTimePerQuestion->update();
*/
unsigned uDiffBase[] = {1, 2, 5, 10}, uDiffMulti=1, uDiff=0, uDiffCount=0;
idx = 0;
do
{
if (idx == 4) { idx = 0; uDiffMulti*=10; }
uDiff = uDiffBase[idx] * uDiffMulti;
uDiffCount = (uMaxTime / uDiff) + 1;
idx++;
}
while (uDiffCount > 9);
m_pPlotTime->setLimitY(0, uDiffCount * uDiff + uDiff/2);
listTics.clear();
tic.clear();
tic.setTextFlags(Qt::AlignRight | Qt::AlignVCenter);
for (unsigned u=0; u<=uDiffCount * uDiff; u+=uDiff)
{
tic.setPos(u);
tic.setText(QString("%1").arg(u));
listTics.append(tic);
}
m_pPlotTime->setTicListY(listTics);
setCursor(Qt::ArrowCursor);
}

54
dlglearnstatistic.h Normal file
View File

@ -0,0 +1,54 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#pragma once
#include <qdialog.h>
#include "ui_dlglearnstatistic.h"
class CChapter;
class CPlotWidget;
class CDlgLearnStatistic : public QDialog, Ui::DlgLearnStatistic
{
Q_OBJECT
public:
CDlgLearnStatistic(QWidget *pParent=0);
~CDlgLearnStatistic() {}
void go(CChapter *pChapter);
protected slots:
void on_cbPeriod_currentIndexChanged(int index);
void on_cbPeriod2_currentIndexChanged(int index);
protected:
void updateTable();
void updateHistory();
void updateTimeExpediture();
protected:
CChapter *m_pChapter;
CPlotWidget *m_pPlotLevel;
CPlotWidget *m_pPlotClicked;
CPlotWidget *m_pPlotTime;
// CPlotWidget *m_pPlotTimePerQuestion;
};

991
dlglearnstatistic.ui Normal file
View File

@ -0,0 +1,991 @@
<ui version="4.0" >
<class>DlgLearnStatistic</class>
<widget class="QDialog" name="DlgLearnStatistic" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>502</width>
<height>552</height>
</rect>
</property>
<property name="windowTitle" >
<string>Lernstatistik</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="labChapter" >
<property name="font" >
<font>
<family>MS Shell Dlg 2</family>
<pointsize>10</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Kapitel-Name</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget" >
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<string>Aktueller Status</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_15" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Lernfortschritt</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="7" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Durchschnittlicher Lernfortschritt:</string>
</property>
</widget>
</item>
<item row="4" column="3" >
<widget class="QLabel" name="labChapterRareBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QLabel" name="labChapterCountBar" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="5" column="2" >
<widget class="QLabel" name="labChapterVeryRare" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_11" >
<property name="text" >
<string>Anfänger:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="4" column="2" >
<widget class="QLabel" name="labChapterRare" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="7" column="2" >
<widget class="QLabel" name="labChapterAvgText" >
<property name="toolTip" >
<string>0.0 = Ahnungslos&lt;br>1.0 = Anfänger&lt;br>2.0 = Fortgeschritten&lt;br>3.0 = Experte&lt;br>4.0 = Freak&lt;br>5.0 = Professor</string>
</property>
<property name="text" >
<string>0.0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="0" >
<widget class="QLabel" name="label_14" >
<property name="text" >
<string>Freak:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="3" column="3" >
<widget class="QLabel" name="labChapterNormalBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="labChapterCount" >
<property name="toolTip" >
<string>Gesamt-Anzahl der Fragen dieses Kapitels</string>
</property>
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="2" >
<widget class="QLabel" name="labChapterExtremeRare" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_12" >
<property name="text" >
<string>Fortgeschritten:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QLabel" name="labChapterOften" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QLabel" name="labChapterVeryOften" >
<property name="minimumSize" >
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLabel" name="label_9" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level3.png</pixmap>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="label_6" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level0.png</pixmap>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Anzahl der Fragen:</string>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QLabel" name="labChapterNormal" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="3" >
<widget class="QLabel" name="labChapterExtremeRareBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_13" >
<property name="text" >
<string>Experte:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="6" column="0" >
<widget class="QLabel" name="label_3" >
<property name="text" >
<string>Professor:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLabel" name="label_8" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level2.png</pixmap>
</property>
</widget>
</item>
<item row="7" column="1" >
<widget class="QLabel" name="labChapterAvgIcon" >
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level0.png</pixmap>
</property>
</widget>
</item>
<item row="6" column="1" >
<widget class="QLabel" name="label_19" >
<property name="toolTip" >
<string>Smiley mit Doktorhut</string>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level5.png</pixmap>
</property>
</widget>
</item>
<item row="5" column="1" >
<widget class="QLabel" name="label_10" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level4.png</pixmap>
</property>
</widget>
</item>
<item row="1" column="3" >
<widget class="QLabel" name="labChapterVeryOftenBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_5" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>3</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string>Ahnungslos:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="3" >
<widget class="QLabel" name="labChapterOftenBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="5" column="3" >
<widget class="QLabel" name="labChapterVeryRareBar" >
<property name="text" >
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="label_7" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>1</hsizetype>
<vsizetype>5</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="pixmap" >
<pixmap resource="afutrainer.qrc" >:/icons/16x16/level1.png</pixmap>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_16" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Abfragen</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="2" column="1" >
<widget class="QLabel" name="labClickCorrect" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QLabel" name="labClickCorrectP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_20" >
<property name="text" >
<string>davon falsche Antworten:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_18" >
<property name="text" >
<string>davon richtige Antworten:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLabel" name="labClickWrong" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_17" >
<property name="text" >
<string>Abfragen gesamt:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labClickCount" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QLabel" name="labClickWrongP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label_28" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>Anzahl </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_29" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>Anteil </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_24" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text" >
<string>Zeitaufwand</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item row="3" column="2" >
<widget class="QLabel" name="labTimeExpeditureWrongP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QLabel" name="labTimeExpeditureCorrectP" >
<property name="text" >
<string>0.0 %</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_22" >
<property name="text" >
<string>davon für richtige Antworten:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="3" >
<widget class="QLabel" name="labTimePerQuestionCorrect" >
<property name="text" >
<string>0 m 0 s</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="3" >
<widget class="QLabel" name="labTimePerQuestionWrong" >
<property name="text" >
<string>0 m 0 s</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_21" >
<property name="text" >
<string>Zeitaufwand gesamt:</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLabel" name="labTimeExpediture" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLabel" name="labTimeExpeditureWrong" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_23" >
<property name="text" >
<string>davon für falsche Antworten:</string>
</property>
<property name="indent" >
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLabel" name="labTimeExpeditureCorrect" >
<property name="text" >
<string>0</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label_25" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>Dauer </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_26" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>Anteil </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QLabel" name="label_27" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>Ø pro Frage </string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="3" >
<widget class="QLabel" name="labTimePerQuestion" >
<property name="text" >
<string>0 m 0 s</string>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>Zeitlicher Verlauf</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Zeitraum:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbPeriod" >
<property name="minimumSize" >
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupLevel" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="title" >
<string>Lernfortschritt</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupClicked" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="title" >
<string>Abfragen</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3" >
<attribute name="title" >
<string>Zeitaufwand</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="label_30" >
<property name="text" >
<string>Zeitraum:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbPeriod2" >
<property name="minimumSize" >
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupTimeExpediture" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="title" >
<string>Zeitaufwand [min]</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Ok</set>
</property>
<property name="centerButtons" >
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>tabWidget</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>cbPeriod</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>DlgLearnStatistic</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel" >
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>DlgLearnStatistic</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel" >
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

43
dlgviewquestion.cpp Normal file
View File

@ -0,0 +1,43 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "dlgviewquestion.h"
#include "catalog.h"
void CDlgViewQuestion::go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer)
{
QString str;
Q_ASSERT (pCatalog != 0);
if (!pQuestion) return;
str = pQuestion->learnText(pCatalog, true, true);
str += "<p><b>";
if (uAnswer != 0 && pQuestion->isCorrectAnswer(uAnswer))
str += "<font color='green'>";
else if (uAnswer != 0)
str += "<font color='red'>";
str += pQuestion->correctionText(uAnswer);
str += "</font></b></p>";
textBrowser->setHtml(str);
setWindowTitle (tr("Frage") + " " + pQuestion->id());
exec();
}

44
dlgviewquestion.h Normal file
View File

@ -0,0 +1,44 @@
/***************************************************************************
* Copyright (C) 2003-2007 by Oliver Saal *
* osaal@gmx.de *
* http://www.oliver-saal.de/software/afutrainer/ *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef DLGVIEWQUESTION_H
#define DLGVIEWQUESTION_H
#include <qdialog.h>
#include "ui_dlgviewquestion.h"
class CQuestion;
class CCatalog;
class CDlgViewQuestion : public QDialog, Ui::DlgViewQuestion
{
Q_OBJECT
public:
CDlgViewQuestion(QWidget *pParent) : QDialog(pParent) { setupUi(this); }
~CDlgViewQuestion() { }
void go (CCatalog *pCatalog, CQuestion *pQuestion, const unsigned uAnswer=0);
protected:
};
#endif // DLGVIEWQUESTION_H

99
dlgviewquestion.ui Normal file
View File

@ -0,0 +1,99 @@
<ui version="4.0" >
<class>DlgViewQuestion</class>
<widget class="QDialog" name="DlgViewQuestion" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>658</width>
<height>577</height>
</rect>
</property>
<property name="windowTitle" >
<string>Frage ansehen</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QTextBrowser" name="textBrowser" >
<property name="font" >
<font>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pbOK" >
<property name="text" >
<string>OK</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>textBrowser</tabstop>
<tabstop>pbOK</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>pbOK</sender>
<signal>clicked()</signal>
<receiver>DlgViewQuestion</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel" >
<x>367</x>
<y>566</y>
</hint>
<hint type="destinationlabel" >
<x>358</x>
<y>293</y>
</hint>
</hints>
</connection>
</connections>
</ui>

98
error.cpp Normal file
View File

@ -0,0 +1,98 @@
/***************************************************************************
* Copyright (C) 1999-2005 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "error.h"
#include <qobject.h>
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlerror.h>
#include <qmap.h>
//#include <qmapiterator.h>
#include <qvariant.h>
#endif
CError::CError ()
{
m_uLine = 0;
}
CError::CError (const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = strText;
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#ifdef ERROR_USE_SQL
CError::CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
m_strText = QString ("%1\n%3").arg (strText, pDB->lastError().text());
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
CError::CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine)
{
QMap<QString, QVariant> map;
m_strText = QString ("%1\nSQL: %2\n").arg (strText, query.lastQuery());
map = query.boundValues();
if (!map.isEmpty())
{
m_strText+="Bound values:\n";
QMap<QString, QVariant>::const_iterator i = map.constBegin();
while (i != map.constEnd())
{
m_strText += QString ("%1 / %2 ==> %4\n").arg (i.key(), i.value().typeName(), i.value().isNull() ? "NULL" : i.value().toString());
++i;
}
}
m_strText += query.lastError().text();
m_strFunction = strFunc;
m_strFile = strFile;
m_uLine = uLine;
}
#endif
QString CError::toPlainText() const
{
return QObject::tr("%1\n\nFunction: %2\nFile: %3 Line: %4\n").arg(m_strText, m_strFunction, m_strFile).arg(m_uLine);
}
QString CError::toHtml() const
{
QString str = m_strText;
str.replace ('\n', "<br>");
return QObject::tr("<p><font color='red'><b>%1</b></font><br>Function: %2<br>File: %3 Line: %4</p><br>\n").arg(str, m_strFunction, m_strFile).arg(m_uLine);
}

78
error.h Normal file
View File

@ -0,0 +1,78 @@
/***************************************************************************
* Copyright (C) 1999-2007 by Oliver Saal *
* http://www.oliver-saal.de/ *
* osaal@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* 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 General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#ifndef ERROR_H
#define ERROR_H
//#define ERROR_USE_SQL
#ifndef __PRETTY_FUNCTION__
# if defined __FUNCSIG__
# define __PRETTY_FUNCTION__ __FUNCSIG__
# elif defined __func__
# define __PRETTY_FUNCTION__ __func__
# else
# define __PRETTY_FUNCTION__ __FILE__
# endif
#endif
#include <qstring.h>
#ifdef ERROR_USE_SQL
#include <qsqlquery.h>
#define THROW_TRANSACTION(x) throw CError (tr("Could not start database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#define THROW_COMMIT(x) throw CError (tr("Could not commit database transaction."), x, __PRETTY_FUNCTION__, __FILE__, __LINE__);
#endif