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
class CError
{
public:
CError ();
CError (const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#ifdef ERROR_USE_SQL
CError (const QString& strText, const QSqlDatabase* pDB, const QString& strFunc, const QString& strFile, const unsigned int uLine);
CError (const QString& strText, const QSqlQuery& query, const QString& strFunc, const QString& strFile, const unsigned int uLine);
#endif
inline void preText (const QString& str) { m_strText = str + m_strText; }
inline void postText (const QString& str) { m_strText += str; }
inline QString text() const { return m_strText; }
inline QString function() const { return m_strFunction; }
inline QString file() const { return m_strFile; }
inline unsigned line() const { return m_uLine; }
QString toPlainText() const;
QString toHtml() const;
protected:
QString m_strText;
QString m_strFunction;
QString m_strFile;
unsigned int m_uLine;
};
#endif // ERROR_H

306
exam.cpp Normal file
View File

@ -0,0 +1,306 @@
/***************************************************************************
* 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 "exam.h"
#include "question.h"
#include "error.h"
#include "tools.h"
#include <qregexp.h>
#include <qvariant.h>
//#define DEBUGMSG
void CExamPart::clear()
{
m_iQuestionCount = 0;
m_strRegExp.clear();
}
bool CExamPart::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam_part")) return false;
m_iQuestionCount = elem.attribute("count").toUInt();
if (m_iQuestionCount == 0) return false;
m_strGroup = elem.attribute("group");
m_strRegExp = elem.text ();
if (m_strRegExp.isEmpty()) return false;
return true;
}
void CExamPart::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam_part");
elemRoot.setAttribute("count", QString("%1").arg(m_iQuestionCount));
elemRoot.setAttribute("group", m_strGroup);
elemRoot.appendChild(doc.createTextNode(m_strRegExp));
parent.appendChild(elemRoot);
}
QList<CQuestion*> CExamPart::createQuestionPool(const QList<CQuestion*>& listAllQuestions) const
{
QList<CQuestion*> listRet, listSelected;
QRegExp regexp(m_strRegExp);
int i=0;
CQuestion *q=0;
#ifdef DEBUGMSG
qDebug ("\tPart Group = '%s' RegExp '%s' mit %i Fragen", qPrintable (m_strGroup), qPrintable(m_strRegExp), m_iQuestionCount);
#endif
// Alle Fragen raussuchen, die dem RegExp entsprechen
for (i=0; i<listAllQuestions.size(); i++)
{
q = listAllQuestions.at(i);
if (!m_strGroup.isEmpty() && !q->groups().contains(m_strGroup, Qt::CaseInsensitive))
continue;
if (regexp.exactMatch(q->id()))
{
#ifdef DEBUGMSG
qDebug ("\t\tAdding Question '%s'", qPrintable (q->id()));
#endif
listSelected.append(q);
}
}
if (listSelected.size() < questionCount())
{
throw CError (
QString("Für den regulären Ausdruck '%1' wurden nur %2 Fragen gefunden - zu wenig, um daraus %3 Fragen für die Prüfung auszuwählen.")
.arg(m_strRegExp).arg(listSelected.size()).arg(questionCount()), __PRETTY_FUNCTION__, __FILE__, __LINE__);
}
#ifdef DEBUGMSG
qDebug ("\tStarte Auswahlverfahren...");
#endif
for (i=0; i < questionCount(); i++)
{
int rnd = afu_random (0, listSelected.size()-1);
q = listSelected.at(rnd);
#ifdef DEBUGMSG
qDebug ("\t\tSelected question '%s'", qPrintable (q->id()));
#endif
listRet.append (q);
listSelected.removeAt(rnd);
}
return listRet;
}
void CExam::clear()
{
m_strId.clear();
m_strName.clear();
m_strComment.clear();
m_uDuration = 0;
m_uMaxErrorPoints = 0;
m_listParts.clear();
}
bool CExam::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam")) return false;
m_strId = elem.attribute("id");
m_strName = elem.attribute("name");
m_uDuration = elem.attribute("duration").toUInt();
m_uMaxErrorPoints = elem.attribute("maxerrorpoints").toUInt();
m_strComment = elem.attribute("comment");
if (m_strName.isEmpty()) return false;
if (m_uDuration == 0) return false;
QDomNode n = elem.firstChild();
while (!n.isNull())
{
if (n.isElement ())
{
QDomElement e = n.toElement ();
if (e.tagName() == QString ("exam_part"))
{
CExamPart ep;
if (ep.load(e)) m_listParts.append(ep);
}
}
n = n.nextSibling();
}
return true;
}
void CExam::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam");
elemRoot.setAttribute("id", m_strId);
elemRoot.setAttribute("name", m_strName);
elemRoot.setAttribute("duration", QString("%1").arg(m_uDuration));
elemRoot.setAttribute("maxerrorpoints", QString("%1").arg(m_uMaxErrorPoints));
elemRoot.setAttribute("comment", m_strComment);
for (int i=0; i<m_listParts.size(); i++)
m_listParts.at(i).save(elemRoot, doc);
parent.appendChild(elemRoot);
}
unsigned CExam::questionCount() const
{
unsigned u=0;
for (int i=0; i<m_listParts.size(); i++)
{
u += m_listParts.at(i).questionCount();
}
return u;
}
QList<CQuestion*> CExam::createQuestionPool(const QList<CQuestion*>& listAllQuestions) const
{
QList<CQuestion*> listRet;
#ifdef DEBUGMSG
qDebug ("Erzeuge Prüfungsfragen für '%s'", qPrintable(name()));
#endif
try
{
for (int i=0; i<m_listParts.size(); i++)
{
listRet << m_listParts.at(i).createQuestionPool(listAllQuestions);
}
}
catch (CError e)
{
e.preText(QString("Konnte Prüfung '%1' nicht erzeugen.").arg(name()));
throw;
}
#ifdef DEBUGMSG
qDebug ("Insg. %i Prüfungsfragen ausgewählt", listRet.size());
for (int i=0; i<listRet.size(); i++)
qDebug ("\t%i. Frage ID '%s'", i+1, qPrintable(listRet.at(i)->id()));
#endif
return listRet;
}
CExamStat::CExamStat(const CExam& exam)
{
clear();
m_strId = exam.id();
}
void CExamStat::clear()
{
m_strId.clear();
m_dt = QDateTime::currentDateTime();
m_uSecs = 0;
m_strlQuestionId.clear();
m_listAnswer.clear();
m_uCorrect = 0;
m_uWrong = 0;
m_uErrorPoints = 0;
m_bPassed = false;
}
void CExamStat::setQuestions(const QList<CQuestion*>& listQuestion, const QList<unsigned>& listAnswerMask)
{
for (int i=0; i<listQuestion.size(); i++)
{
CQuestion *q = listQuestion.at(i);
m_strlQuestionId.append(q->id());
m_listAnswer.append(q->orderedAnswerMask(listAnswerMask.at(i)));
}
}
void CExamStat::setResult (const unsigned uCorrect, const unsigned uWrong, const unsigned uErrorPoints, const bool bPassed)
{
m_uCorrect = uCorrect;
m_uWrong = uWrong;
m_uErrorPoints = uErrorPoints;
m_bPassed = bPassed;
}
bool CExamStat::load (QDomElement elem)
{
if (elem.tagName() != QString ("exam")) return false;
m_strId = elem.attribute("id");
m_uSecs = elem.attribute("secs").toUInt();
m_dt = QDateTime::fromString(elem.attribute("datetime"), Qt::ISODate);
m_uCorrect = elem.attribute("correct").toUInt();
m_uWrong = elem.attribute("wrong").toUInt();
m_uErrorPoints = elem.attribute("errorpoints").toUInt();
m_bPassed = QVariant(elem.attribute("passed")).toBool();
if (m_strId.isEmpty()) return false;
if (m_uSecs == 0) 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");
if (!strId.isEmpty())
{
m_strlQuestionId.append (strId);
m_listAnswer.append(e.attribute("answer").toUInt());
}
}
}
n = n.nextSibling();
}
return true;
}
void CExamStat::save (QDomElement& parent, QDomDocument& doc) const
{
QDomElement elemRoot = doc.createElement("exam");
elemRoot.setAttribute("id", m_strId);
elemRoot.setAttribute("secs", QString("%1").arg(m_uSecs));
elemRoot.setAttribute("datetime", m_dt.toString(Qt::ISODate));
elemRoot.setAttribute("correct", QString("%1").arg(m_uCorrect));
elemRoot.setAttribute("wrong", QString("%1").arg(m_uWrong));
elemRoot.setAttribute("errorpoints", QString("%1").arg(m_uErrorPoints));
elemRoot.setAttribute("passed", QString("%1").arg(m_bPassed));
for (int i=0; i<m_strlQuestionId.size(); i++)
{
QDomElement elemQuestion = doc.createElement("question");
elemQuestion.setAttribute("id", m_strlQuestionId.at(i));
elemQuestion.setAttribute("answer", m_listAnswer.at(i));
elemRoot.appendChild(elemQuestion);
}
parent.appendChild(elemRoot);
}

142
exam.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 EXAM_H
#define EXAM_H
#include <qstring.h>
#include <qlist.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CQuestion;
class CExamPart
{
public:
CExamPart() { clear(); }
~CExamPart() {}
void clear();
inline int questionCount() const { return m_iQuestionCount; }
inline void setQuestionCount(int i) { m_iQuestionCount = i; }
inline QString group() const { return m_strGroup; }
inline void setGroup(const QString& str) { m_strGroup = str; }
inline QString regexp() const { return m_strRegExp; }
inline void setRegExp(const QString& str) { m_strRegExp = str; }
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
int m_iQuestionCount;
QString m_strGroup;
QString m_strRegExp;
};
class CExam
{
public:
CExam() { clear(); }
~CExam() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten der Prüfung gelöscht. */
void clear();
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline QString name() const { return m_strName; }
inline QString comment() const { return m_strComment; }
unsigned duration() const { return m_uDuration; }
unsigned maxErrorPoints() const { return m_uMaxErrorPoints; }
unsigned questionCount() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
QList<CQuestion*> createQuestionPool(const QList<CQuestion*>& listAllQuestions) const;
protected:
QString m_strId; //< ID der Prüfung
QString m_strName; //< Name / Bezeichnung
QString m_strComment; //< Kommentar / Hinweis
unsigned m_uDuration; //< Prüfungsdauer in min
unsigned m_uMaxErrorPoints; //< Max. Anzahl an erlaubten Fehlerpunkten, um die Prüfung zu bestehen
QList<CExamPart> m_listParts; //< Abschnitte, aus denen sich die Prüfung zusammensetzt.
};
class CExamStat
{
public:
CExamStat() { clear(); }
CExamStat(const CExam& exam);
~CExamStat() {}
//! Zurücksetzen aller Werte
/*! Es werden alle Daten dieser Prüfungsstatistik gelöscht. */
void clear();
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc) const;
//! ID abfragen
inline QString id() const { return m_strId; }
//! ID setzen
inline void setId(const QString& strId) { m_strId = strId; }
inline void setSecs(const unsigned uSecs) { m_uSecs = uSecs; }
void setQuestions(const QList<CQuestion*>& listQuestion, const QList<unsigned>& listAnswerMask);
void setResult (const unsigned uCorrect, const unsigned uWrong, const unsigned uErrorPoints, const bool bPassed);
inline unsigned duration() const { return m_uSecs; }
inline bool passed() const { return m_bPassed; }
inline unsigned correctAnswers() const { return m_uCorrect; }
inline unsigned wrongAnswers() const { return m_uWrong; }
inline unsigned errorPoints() const { return m_uErrorPoints; }
QDateTime datetime() const { return m_dt; }
protected:
QString m_strId; //< ID der Prüfung
QDateTime m_dt; //< Datum/Uhrzeit
unsigned m_uSecs; //< Benötigte Zeit in sec
QStringList m_strlQuestionId; //< IDs der Fragen
QList<unsigned> m_listAnswer; //< Antworten
unsigned m_uCorrect; //< Anzahl d. richtigen Fragen
unsigned m_uWrong; //< Anzahl d. falschen Fragen
unsigned m_uErrorPoints; //< Fehlerpunkte
bool m_bPassed; //< Bestanden Ja/Nein
};
#endif

84
helper.cpp 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. *
***************************************************************************/
#include "helper.h"
#include "catalog.h"
void CHint::clear()
{
m_strlQuestionId.clear();
m_strAuthor.clear();
m_date = QDate();
m_strText.clear();
m_strComment.clear();
}
bool CHint::load (QDomElement elem)
{
QString str;
if (elem.tagName() != QString ("hint")) return false;
m_strAuthor = elem.attribute ("author", "AFUTrainer-Hilfe");
m_date = QDate::fromString(elem.attribute ("date"), Qt::ISODate);
str = elem.attribute("question");
str = str.replace(' ', ';').replace(',', ';');
m_strlQuestionId = str.split(";", QString::SkipEmptyParts);
m_strComment = elem.attribute ("comment");
m_strText = elem.text ();
if (m_strText.isEmpty()) return false;
return true;
}
void CHint::save (QDomElement& parent, QDomDocument& doc)
{
QDomElement elemRoot = doc.createElement("hint");
if (!m_strAuthor.isEmpty()) elemRoot.setAttribute("author", m_strAuthor);
if (m_date.isValid()) elemRoot.setAttribute("date", m_date.toString(Qt::ISODate));
elemRoot.setAttribute("question", m_strlQuestionId.join(";"));
if (!m_strComment.isEmpty()) elemRoot.setAttribute("comment", m_strComment);
parent.appendChild(elemRoot);
elemRoot.appendChild(doc.createTextNode(m_strText));
}
QString CHint::showText() const
{
QString str;
/* if (text().isEmpty())
{
if (pCatalog)
return pCatalog->hintText(id());
else
return QString();
}
*/
/* str = "<p><table cellspacing='0' border='0' width='100%'>";
str += "<tr><td bgcolor='gray'><b>"+author()+"</b></td>";
str += "<td bgcolor='gray' align='right'><b>"+dateString()+"</b></td></tr>";
str += "<tr><td colspan='2'>"+text()+"</td></tr>";
str += "<tr><td colspan='2'>&nbsp;</td></tr>";
str += "</table></p>";
*/
str += "<p>" + text() + "</p>"; //"<p><i><font size=-1>" + author() + "&nbsp;" + date() + "</font></i></p>";
return (str);
}

71
helper.h Normal file
View File

@ -0,0 +1,71 @@
/***************************************************************************
* 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 HELPER_H
#define HELPER_H
#include <qstring.h>
#include <qdom.h>
#include <qdatetime.h>
#include <qstringlist.h>
class CCatalog;
class CHint
{
public:
CHint() { clear(); }
~CHint() {}
void clear();
inline void appendQuestion(const QString& id) { if (!hasQuestion(id)) m_strlQuestionId.append(id); }
inline void removeQuestion(const QString& id) { m_strlQuestionId.removeAll(id); }
inline bool hasQuestion(const QString& id) const { return m_strlQuestionId.contains(id); }
inline QString author() const { return m_strAuthor; }
inline void setAuthor(const QString& strAuthor) { m_strAuthor = strAuthor; }
inline QDate date() const { return m_date; }
inline QString dateString() const { return m_date.toString(Qt::LocalDate); }
inline void setDate (const QDate& date) { m_date = date; }
inline QString text() const { return m_strText; }
inline void setText(const QString& strText) { m_strText = strText; }
inline QString comment() const { return m_strComment; }
inline void setComment (const QString& strComment) { m_strComment = strComment; }
QString showText() const;
bool load (QDomElement elem);
void save (QDomElement& parent, QDomDocument& doc);
protected:
QStringList m_strlQuestionId;
QString m_strAuthor;
QDate m_date;
QString m_strText;
QString m_strComment;
};
#endif

BIN
icons/16x16/book1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

BIN
icons/16x16/button_ok.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

BIN
icons/16x16/cancel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

BIN
icons/16x16/clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

BIN
icons/16x16/contexthelp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 B

BIN
icons/16x16/exit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

BIN
icons/16x16/filenew.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
icons/16x16/fileopen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/16x16/filesave.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

BIN
icons/16x16/filesaveas.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/16x16/finish.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

BIN
icons/16x16/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

BIN
icons/16x16/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

BIN
icons/16x16/idea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 829 B

BIN
icons/16x16/idea_gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

BIN
icons/16x16/idea_info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

BIN
icons/16x16/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 B

BIN
icons/16x16/level0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

BIN
icons/16x16/level1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

BIN
icons/16x16/level1a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

BIN
icons/16x16/level2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

BIN
icons/16x16/level2a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

BIN
icons/16x16/level3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

BIN
icons/16x16/level3a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

BIN
icons/16x16/level4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
icons/16x16/level5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

BIN
icons/16x16/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

BIN
icons/16x16/previous.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

BIN
icons/16x16/start.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 852 B

BIN
icons/16x16/stats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

BIN
icons/16x16/stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 B

BIN
icons/16x16/viewmag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1023 B

BIN
icons/32x32/idea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
icons/32x32/qt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

BIN
icons/64x16/level0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

BIN
icons/64x16/level1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

BIN
icons/64x16/level2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

BIN
icons/64x16/level3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
icons/64x16/level4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

BIN
icons/level.xcf Normal file

Binary file not shown.

BIN
icons/veryrare.xcf Normal file

Binary file not shown.

42
main.cpp Normal file
View File

@ -0,0 +1,42 @@
/***************************************************************************
* 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 "mainwindow.h"
#include <qapplication.h>
#include <qtranslator.h>
#include <time.h>
int main (int argc, char *argv[])
{
QApplication app (argc, argv);
QTranslator translator;
app.setOrganizationName ("osaal");
app.setApplicationName ("AFUTrainer");
translator.load(":/translations/qt_de");
app.installTranslator(&translator);
srand (time (NULL));
CMainWindow mw;
mw.show();
return app.exec();
}

819
mainwindow.cpp Normal file
View File

@ -0,0 +1,819 @@
/***************************************************************************
* 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 "mainwindow.h"
#include <qwhatsthis.h>
#include <qmessagebox.h>
#include <qfiledialog.h>
#include <qheaderview.h>
#include <qtextstream.h>
#include <qregexp.h>
#include <qdir.h>
#include <qsettings.h>
#include "dlglearn.h"
#include "dlglearnassistant.h"
#include "dlginformation.h"
#include "dlgexamselect.h"
#include "dlgexam.h"
#include "dlgexamstatistic.h"
#include "dlglearnstatistic.h"
#include "catalog.h"
CMainWindow::CMainWindow() : QMainWindow()
{
setupUi(this);
m_pSplitter = new QSplitter (this);
setCentralWidget (m_pSplitter);
m_pViewChapter = new QTreeView (m_pSplitter);
m_pViewChapter->setModel(&m_modelCatalog);
m_pViewChapter->header()->setStretchLastSection(false);
m_pViewChapter->header()->setResizeMode (0, QHeaderView::Stretch);
m_pViewChapter->header()->setResizeMode (1, QHeaderView::Interactive);
m_pViewChapter->header()->setResizeMode (3, QHeaderView::Interactive);
m_pViewChapter->header()->resizeSection(1, 45);
m_pViewChapter->header()->resizeSection(2, 150);
m_pViewChapter->header()->resizeSection(3, 20);
//m_pViewChapter->setSelectionBehavior(QAbstractItemView::SelectRows);
connect (m_pViewChapter->selectionModel(), SIGNAL(selectionChanged (const QItemSelection& , const QItemSelection& )), this, SLOT(onCatalogSelectionChanged (const QItemSelection& , const QItemSelection& )));
m_pSplitter2 = new QSplitter (m_pSplitter);
m_pSplitter2->setOrientation(Qt::Vertical);
m_pViewQuestions = new QTreeView (m_pSplitter2);
m_pViewQuestions->setModel(&m_modelQuestion);
m_pViewQuestions->header()->setStretchLastSection(false);
m_pViewQuestions->header()->setResizeMode (0, QHeaderView::Interactive);
m_pViewQuestions->header()->setResizeMode (1, QHeaderView::Stretch);
m_pViewQuestions->header()->resizeSection(0, 60);
m_pViewQuestions->header()->resizeSection(2, 20);
m_pViewQuestions->header()->resizeSection(3, 20);
m_pViewQuestions->header()->resizeSection(4, 100);
m_pViewQuestions->header()->resizeSection(5, 80);
m_pViewQuestions->header()->resizeSection(6, 80);
m_pViewQuestions->setRootIsDecorated(false);
connect (m_pViewQuestions->selectionModel(), SIGNAL(selectionChanged (const QItemSelection& , const QItemSelection& )), this, SLOT(onQuestionSelectionChanged (const QItemSelection& , const QItemSelection& )));
m_pTextQuestion = new QTextBrowser (m_pSplitter2);
m_pTextQuestion->setOpenExternalLinks(true);
//m_pTextQuestion->setReadOnly(true);
//connect (m_pTextQuestion, SIGNAL(anchorClicked (const QUrl &)), this, SLOT(onAnchorClicked (const QUrl &)));
m_pCatalog = 0;
connect (&m_rf, SIGNAL(loadFile(const QString&)), this, SLOT(onOpenFile(const QString&)));
m_rf.create(QString(), 8);
m_rf.insertToMenu(menuFile, actFileExit);
m_rf.setShowNoEntry(false);
m_rf.setShowSeperator(CRecentFiles::SeperatorBottom);
// open last file
onOpenFile(m_rf.recentFile(0));
#ifndef _DEBUG
actFileSave->setVisible(false);
actFileSaveAs->setVisible(false);
actFileImport->setVisible(false);
actFileImportUS->setVisible(false);
#endif
updateWindowTitle();
}
CMainWindow::~CMainWindow()
{
if (m_pCatalog) delete m_pCatalog;
}
void CMainWindow::updateWindowTitle()
{
QString str;
str = tr("AFUTrainer 3.0");
if (m_pCatalog)
{
str += " - ";
if (m_pCatalog->name().isEmpty())
str += tr("unbenannt");
else
str += m_pCatalog->name();
if (!m_pCatalog->fileName().isEmpty())
str += " [" + m_pCatalog->fileName() + "]";
}
setWindowTitle(str);
}
void CMainWindow::setCatalog (CCatalog *pCatalog)
{
m_modelCatalog.setModelData(pCatalog);
m_pViewChapter->expandAll();
if (m_pCatalog) delete m_pCatalog;
m_pCatalog = pCatalog;
m_modelQuestion.setModelData(0);
m_pTextQuestion->clear();
updateWindowTitle();
if (m_pCatalog == 0) return;
QDate d = m_pCatalog->validUntil();
if (d.isValid() && d < QDate::currentDate())
{
QString str = tr("<b>Dieser Fragenkatalog ist seit dem %1 nicht mehr gültig!</b>").arg(d.toString(Qt::LocalDate));
if (!m_pCatalog->publisher().isEmpty())
str += tr("<p>Weitere Informationen zur Gültigkeit erhalten Sie vom Herausgeber:<br>")+m_pCatalog->publisher();
if (!m_pCatalog->contact().isEmpty())
str += tr("<p>Einen aktuellen Fragenkatalog für den AFUTrainer erhalten Sie evt. von:<br>")+m_pCatalog->contact();
QMessageBox::warning(this, tr("Warnung"), str);
}
}
bool CMainWindow::checkForErrors()
{
QString str;
if (m_pCatalog == 0) return false;
str = m_pCatalog->checkForErrors();
if (str.isEmpty()) return false;
QMessageBox::critical(this, tr("Fehler im Fragenkatalog"), tr("Die gewünschte Funktion kann nicht ausgeführt werden, da der Fragenkatalog folgende Fehler enthält:<p>")+ str);
return true;
}
bool CMainWindow::checkForHomeDir()
{
QString strDir = QDir::homePath() + "/.afutrainer/";
QDir dir;
if (dir.exists(strDir)) return true;
if (!dir.mkpath(strDir))
{
QMessageBox::critical(this, tr("Fehler"), tr("Konnte Verzeichnis %1 nicht anlegen!").arg(strDir));
return false;
}
return true;
}
void CMainWindow::on_actFileNew_triggered()
{
if (!checkForHomeDir()) return;
setCatalog(0);
}
void CMainWindow::on_actFileOpen_triggered()
{
QString strFileName;
if (!checkForHomeDir()) return;
strFileName = QFileDialog::getOpenFileName(this, tr("Öffne Fragenkatalog"), QString(), tr("Amateur Radio Questionary Data Format (*.aqz)\nAlle Dateien (*.*)"));
onOpenFile(strFileName);
}
void CMainWindow::onOpenFile(const QString& strFileName)
{
CCatalog *pCatalog=0;
if (strFileName.isEmpty()) return;
pCatalog = new CCatalog;
if (pCatalog->load(strFileName, this))
{
setCatalog (pCatalog);
m_rf.setRecentFile(strFileName);
}
else
{
m_rf.removeFile(strFileName);
delete pCatalog;
}
}
void CMainWindow::on_actFileInformation_triggered()
{
CDlgInformation dlg(this);
if (!m_pCatalog)
{
QMessageBox::information(this, tr("Information"), tr("Kein Fragenkatalog geladen, zu dem Informationen angezeigt werden könnten."));
return;
}
dlg.setup(m_pCatalog);
dlg.exec();
}
void CMainWindow::on_actFileSave_triggered()
{
if (!m_pCatalog) return;
if (m_pCatalog->fileName().isEmpty())
on_actFileSaveAs_triggered();
else
{
m_pCatalog->save(m_pCatalog->fileName(), this);
updateWindowTitle();
}
}
void CMainWindow::on_actFileSaveAs_triggered()
{
QString strFileName;
if (!m_pCatalog) return;
strFileName = QFileDialog::getSaveFileName(this, tr("Speichere Fragenkatalog"), QString(), tr("XML-Dateien (*.xml)\nAlle Dateien (*.*)"));
if (strFileName.isEmpty()) return;
m_pCatalog->save(strFileName, this);
updateWindowTitle();
}
bool ImportDE_isChapter(const QString& strLine)
{
if (strLine.contains(QRegExp ("^[0-9](\\.[0-9]+)*\\s\\w")))
return true;
else
return false;
}
int ImportDE_chapterLevel(const QString& strLine)
{
QString str = strLine.left(strLine.indexOf(' '));
return (str.count('.'));
}
bool ImportDE_isQuestion(const QString& strLine)
{
return strLine.contains(QRegExp("^[A-Z]{2,2}[0-9]{3,3}"));
}
bool ImportDE_isAnswer(const QString& strLine)
{
return strLine.contains(QRegExp("^[A-D]\\s")) || strLine.contains(QRegExp("^[A-D]$"));
}
void CMainWindow::on_actFileImport_triggered()
{
QString strFileName, strLine, strChapter;
CChapter *pChapter=0, *pTempChapter=0;
CQuestion *pQuestion=0;
int uCurrentLevel=-1, uLevel=-1;
enum LastAdded {None, Chapter, Question, Answer};
LastAdded la=None;
CCatalog *pCatalog=0;
strFileName = QFileDialog::getOpenFileName(this, tr("Öffne Datei zum Fragenkatalog-Import"), QString("D:/projekte/afutrainer/fragenkataloge/2007-02/Klasse A Technik/"), tr("TXT-Dateien (*.txt)\nAlle Dateien (*.*)"));
if (strFileName.isEmpty()) return;
QFile file(strFileName);
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::information(this, tr("Fehler"), tr("Konnte Datei '%1' nicht zum Lesen öffnen!").arg(strFileName));
return;
}
QTextStream in(&file);
pCatalog = new CCatalog();
while (!in.atEnd())
{
strLine = in.readLine().trimmed();
if (strLine.isEmpty() || strLine.contains(QRegExp("^Prüfungsfragen")) || strLine.contains("^Bundesnetzagentur"))
{
la = None;
}
else if (ImportDE_isChapter(strLine)) // && (uCurrentLevel+1 == ImportDE_chapterLevel(strLine) || uCurrentLevel-1 == ImportDE_chapterLevel(strLine)))
{
uLevel = ImportDE_chapterLevel(strLine);
while (uCurrentLevel >= uLevel && pChapter)
{
pChapter = pChapter->parentChapter();
uCurrentLevel--;
}
pTempChapter = new CChapter();
if (pChapter == 0)
pCatalog->appendChapter(pTempChapter);
else
pChapter->appendChapter(pTempChapter);
pTempChapter->setText(strLine.mid(strLine.indexOf(' ') + 1));
pChapter = pTempChapter;
uCurrentLevel++;
strChapter += QString("%1 -- %2<br>").arg(uLevel).arg(strLine);
qDebug ("%i -- %s", uLevel, qPrintable(strLine));
la = Chapter;
}
else if (ImportDE_isQuestion(strLine))
{
pQuestion = new CQuestion();
pQuestion->setId (strLine.left(5));
pQuestion->setText (strLine.mid(6).trimmed());
if (pChapter)
{
pChapter->appendQuestion(pQuestion);
// update id of chapters
pTempChapter = pChapter;
uLevel = uCurrentLevel;
while (pTempChapter && uLevel >= 0)
{
if (pTempChapter->id().isEmpty())
pTempChapter->setId(pQuestion->id().at(uLevel));
pTempChapter = pTempChapter->parentChapter();
uLevel--;
}
}
else
delete pQuestion;
//qDebug (qPrintable(strLine));
la = Question;
}
else if (ImportDE_isAnswer(strLine))
{
CAnswer a(strLine.mid(2).trimmed(), strLine[0] == QChar('A'));
if (pQuestion)
pQuestion->appendAnswer(a);
//qDebug (qPrintable("\t"+strLine));
la = Answer;
}
else
{
if (la == Chapter && pChapter)
{
if (pChapter->text().isEmpty())
pChapter->appendText (strLine.trimmed());
else
pChapter->appendText (" " + strLine.trimmed());
}
else if (la == Question && pQuestion)
{
if (pQuestion->text().isEmpty() || pQuestion->text().right(1) == "-")
pQuestion->appendText (strLine.trimmed());
else
pQuestion->appendText (" " + strLine.trimmed());
}
else if (la == Answer && pQuestion && pQuestion->countAnswer() > 0)
{
QString strText = pQuestion->answerAt(pQuestion->countAnswer()-1).text();
if (strText.isEmpty() || strText.right(1) == "-")
pQuestion->answerAt(pQuestion->countAnswer()-1).appendText(strLine.trimmed());
else
pQuestion->answerAt(pQuestion->countAnswer()-1).appendText(" " + strLine.trimmed());
}
}
}
// Bilder hinzufügen
QList<CQuestion*> listPool = pCatalog->questionPool();
QDir dirPath(strFileName.left(strFileName.lastIndexOf('/')));
for (int i=0; i<listPool.size(); i++)
{
pQuestion = listPool.at(i);
QStringList strlFiles = dirPath.entryList(QStringList() << pQuestion->id().toLower()+"*");
for (int j=0; j<strlFiles.size(); j++)
{
QString strImgFile = strlFiles.at(j).toLower();
// Überprüfen, ob Verweis
if (strImgFile.contains("_"))
{ // Ja, Verweis
QString strImgFile1 = strImgFile.left(strImgFile.indexOf('_'));
QString strImgFile2 = strImgFile.mid(strImgFile.indexOf('_') + 1);
QStringList strlFiles2 = dirPath.entryList(QStringList() << strImgFile2 + "*");
if (strlFiles2.size() == 0)
{
qDebug ("Verlinkte Datei %s von Frage %s existiert nicht. Link: %s", qPrintable(strImgFile2), qPrintable(strImgFile1), qPrintable(strImgFile));
}
else
{
qDebug ("Datei %s verlinkt auf reale Datei %s", qPrintable(strImgFile), qPrintable(strlFiles2.at(0)));
strImgFile = strlFiles2.at(0);
}
/*int idx = strlFiles.indexOf(QRegExp(strImgFile2 + "\\..*"));
if (idx < 0)
{
qDebug ("Verlinkte Datei %s von Frage %s existiert nicht. Link: %s", qPrintable(strImgFile2), qPrintable(strImgFile1), qPrintable(strImgFile));
}
else
{
qDebug ("Datei %s verlinkt auf reale Datei %s", qPrintable(strImgFile), qPrintable(strlFiles.at(idx)));
strImgFile = strlFiles.at(idx);
}*/
}
QString strLink = "<img src='" + strImgFile + "'>";
if (strImgFile.contains(QRegExp("f\\d*\\.")))
{ // Frage
qDebug("Adding image %s to question %s", qPrintable(strImgFile), qPrintable(pQuestion->id()));
pQuestion->appendText("<p>" + strLink + "</p>");
}
else if (strImgFile.contains("a.") && pQuestion->countAnswer() > 0)
{ // Antwort A
//qDebug("Adding image %s to answer A of question %s", qPrintable(strImgFile), qPrintable(pQuestion->id()));
pQuestion->answerAt(0).appendText("<p>" + strLink + "</p>");
}
else if (strImgFile.contains("b.") && pQuestion->countAnswer() > 1)
{ // Antwort B
//qDebug("Adding image %s to answer B of question %s", qPrintable(strImgFile), qPrintable(pQuestion->id()));
pQuestion->answerAt(1).appendText("<p>" + strLink + "</p>");
}
else if (strImgFile.contains("c.") && pQuestion->countAnswer() > 2)
{ // Antwort C
//qDebug("Adding image %s to answer C of question %s", qPrintable(strImgFile), qPrintable(pQuestion->id()));
pQuestion->answerAt(2).appendText("<p>" + strLink + "</p>");
}
else if (strImgFile.contains("d.") && pQuestion->countAnswer() > 3)
{ // Antwort D
//qDebug("Adding image %s to answer D of question %s", qPrintable(strImgFile), qPrintable(pQuestion->id()));
pQuestion->answerAt(3).appendText("<p>" + strLink + "</p>");
}
else
{
qDebug ("Konnte Grafik %s nicht zuordnen.\n\tMögliche Gründe: Frage oder Antwort existiert nicht. Dateiname der Grafik falsch geschrieben.", qPrintable(strImgFile));
}
}
}
pCatalog->setName("Importierter Katalog von " + strFileName);
QMessageBox::information(this, tr("Information"),
"Bitte Debug-Ausgabe überprüfen, ob alle Grafik-Dateien zugeordnet wurden!<p>"
"Bitte überprüfen, ob alle Kapitel korrekt erkannt wurden. "
"Wenn nicht, muss die TXT-Datei von Hand kontrolliert werden!<hr>"+strChapter);
qDebug("Weitere Vorgehensweise:\n\t1. Fragenkatalog als XML-Datei abspeichern.\n\t2. ggf. Korrekturen in der XML-Datei vornehmen\n\t3. XML-Datei und alle Grafik-Dateien in ein ZIP-Archiv packen und die Dateiänderung auf .atc ändern.\n\tFertig!");
setCatalog (pCatalog);
}
bool ImportUS_isChapter(const QString& strLine)
{
if (strLine.contains(QRegExp("^SUBELEMENT")) || strLine.contains(QRegExp("^[A-Z][0-9][A-Z]\\s")))
return true;
else
return false;
}
bool ImportUS_isQuestion(const QString& strLine)
{
return strLine.contains(QRegExp("^[A-Z][0-9][A-Z][0-9]{2,2}"));
}
bool ImportUS_isAnswer(const QString& strLine)
{
return strLine.contains(QRegExp("^[A-D]\\.\\s"));
}
void CMainWindow::on_actFileImportUS_triggered()
{
QString strFileName, strLine, strChapter, str;
CChapter *pChapter=0, *pTempChapter=0;
CQuestion *pQuestion=0;
int uCurrentLevel=-1, uLevel=-1;
enum LastAdded {None, Chapter, Question, Answer};
LastAdded la=None;
CCatalog *pCatalog=0;
strFileName = QFileDialog::getOpenFileName(this, tr("Öffne Datei zum Fragenkatalog-Import"), QString("D:/projekte/afutrainer/fragenkataloge/US/"), tr("TXT-Dateien (*.txt)\nAlle Dateien (*.*)"));
if (strFileName.isEmpty()) return;
QFile file(strFileName);
if(!file.open(QIODevice::ReadOnly))
{
QMessageBox::information(this, tr("Fehler"), tr("Konnte Datei '%1' nicht zum Lesen öffnen!").arg(strFileName));
return;
}
QTextStream in(&file);
pCatalog = new CCatalog();
while (!in.atEnd())
{
strLine = in.readLine().trimmed();
if (strLine.isEmpty())
{
//la = None;
}
else if (strLine == "~~")
{
la = None;
}
else if (ImportUS_isChapter(strLine))
{
pTempChapter = new CChapter();
if (strLine.contains(QRegExp("^SUBELEMENT")))
{
uLevel = 0;
strLine = strLine.mid(strLine.indexOf(' ')+1);
pTempChapter->setId(strLine.left(2));
// str = strLine.mid(strLine.indexOf(QRegExp("[A-Z]"), 2));
// str.remove(QRegExp("\\[.*\\]"));
pTempChapter->setText(strLine.mid(strLine.indexOf(QRegExp("[A-Z]"), 2)));
}
else
{
uLevel = 1;
pTempChapter->setId(strLine.mid(2, 1));
// str = strLine.mid(strLine.indexOf(QRegExp("[A-Z]"), 3));
// str.remove(QRegExp("\\[.*\\]"));
pTempChapter->setText(strLine.mid(strLine.indexOf(QRegExp("[A-Z]"), 3)));
}
while (uCurrentLevel >= uLevel && pChapter)
{
pChapter = pChapter->parentChapter();
uCurrentLevel--;
}
if (!pChapter)
pCatalog->appendChapter(pTempChapter);
else
{
// pTempChapter->setExam("main", 1);
pChapter->appendChapter(pTempChapter);
}
strChapter += QString("%1 -- %2 - %3<br>").arg(uLevel).arg(pTempChapter->id(), pTempChapter->text());
pChapter = pTempChapter;
uCurrentLevel++;
la = Chapter;
}
else if (ImportUS_isQuestion(strLine))
{
pQuestion = new CQuestion();
pQuestion->setId (strLine.left(5));
pQuestion->setText (strLine.mid(6).trimmed());
if (pChapter)
pChapter->appendQuestion(pQuestion);
else
delete pQuestion;
//qDebug (qPrintable(strLine));
la = Question;
}
else if (ImportUS_isAnswer(strLine))
{
CAnswer a(strLine.mid(3).trimmed(), false);
if (pQuestion)
pQuestion->appendAnswer(a);
//qDebug (qPrintable("\t"+strLine));
la = Answer;
}
else
{
if (la == Chapter && pChapter)
{
if (pChapter->text().isEmpty())
pChapter->appendText (strLine.trimmed());
else
pChapter->appendText (" " + strLine.trimmed());
}
else if (la == Question && pQuestion)
{
if (pQuestion->text().isEmpty() || pQuestion->text().right(1) == "-")
pQuestion->appendText (strLine.trimmed());
else
pQuestion->appendText (" " + strLine.trimmed());
}
else if (la == Answer && pQuestion && pQuestion->countAnswer() > 0)
{
QString strText = pQuestion->answerAt(pQuestion->countAnswer()-1).text();
if (strText.isEmpty() || strText.right(1) == "-")
pQuestion->answerAt(pQuestion->countAnswer()-1).appendText(strLine.trimmed());
else
pQuestion->answerAt(pQuestion->countAnswer()-1).appendText(" " + strLine.trimmed());
}
}
}
// Fragen durchgehen und richtige Antworten eintragen
QList<CQuestion*> listPool = pCatalog->questionPool();
for (int i=0; i<listPool.size(); i++)
{
pQuestion = listPool.at(i);
QString strText = pQuestion->text();
int idx = strText.indexOf(QRegExp("\\([A-Z]\\)"));
if (idx == -1) continue;
int iCorrect = pQuestion->text().at(idx+1).toAscii() - 'A';
if (pQuestion->countAnswer() > iCorrect)
pQuestion->answerAt(iCorrect).setCorrect(true);
strText.remove(idx, 3);
idx = strText.indexOf(QRegExp("\\[.*\\]"));
if (idx >= 0)
{
int iLen = strText.indexOf(']', idx) - idx + 1;
CHint hint;
hint.appendQuestion(pQuestion->id());
hint.setAuthor("FCC");
hint.setText("See FCC rules part " + strText.mid(idx + 1, iLen - 2));
pCatalog->appendHint(hint);
strText.remove(idx, iLen);
}
pQuestion->setText(strText.trimmed());
}
// Kapitelnamen korrigieren
QList<CChapter*> listChapter = pCatalog->subChapters();
for (int i=0; i<listChapter.size(); i++)
{
pChapter = listChapter.at(i);
QString strText = pChapter->text();
//strText = strText.left(strText.indexOf(" - "));
strText.remove(QRegExp("\\[.*\\]"));
pChapter->setText(strText.trimmed());
}
// Allgemeine Angaben:
//pCatalog->setVersionText("");
pCatalog->setPublisher("NCVEC (National Conference of Volunteer Examiner Coordinators)<br>Question Pool Committee<br>http://www.ncvec.org/");
pCatalog->setContact("Oliver Saal, DM1OLI<br>http://www.oliver-saal.de/software/afutrainer/<br>Mail: osaal@gmx.de");
pCatalog->setName("Importierter Katalog von " + strFileName);
QMessageBox::information(this, tr("Information"),
"Bitte überprüfen, ob alle Kapitel korrekt erkannt wurden. "
"Wenn nicht, muss die TXT-Datei von Hand kontrolliert werden!<hr>"+strChapter);
qDebug("Weitere Vorgehensweise:\n\t1. Fragenkatalog als XML-Datei abspeichern.\n\t2. ggf. Korrekturen in der XML-Datei vornehmen\n\t3. XML-Datei und alle Grafik-Dateien in ein ZIP-Archiv packen und die Dateiänderung auf .atc ändern.\n\tFertig!");
setCatalog (pCatalog);
}
void CMainWindow::on_actFileExit_triggered()
{
qApp->quit();
}
void CMainWindow::on_actQuestionAssistant_triggered()
{
CDlgLearnAssistant dlg(this);
CDlgLearn dlgLearn(this);
CChapter *pChapter=0;
if (m_pCatalog == 0) return;
if (checkForErrors()) return;
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;
dlgLearn.go(m_pCatalog, pChapter);
m_pCatalog->saveStatistic(this);
}
void CMainWindow::on_actQuestionsLearn_triggered()
{
CDlgLearn dlg(this);
QModelIndexList list = m_pViewChapter->selectionModel()->selectedIndexes();
if (checkForErrors()) return;
if (list.isEmpty())
{
QMessageBox::information(this, tr("Information"), tr("Bitte ein Kapitel zum Lernen auswählen!"));
return;
}
CChapter *p = (CChapter*)list.first().internalPointer();
Q_ASSERT(p != 0);
dlg.go(m_pCatalog, p);
m_pCatalog->saveStatistic(this);
}
void CMainWindow::on_actQuestionsLearnStatistics_triggered()
{
CDlgLearnStatistic dlg(this);
QModelIndexList list = m_pViewChapter->selectionModel()->selectedIndexes();
CChapter *p=0;
if (checkForErrors()) return;
if (list.isEmpty())
p = m_pCatalog;
else
p = (CChapter*)list.first().internalPointer();
dlg.go(p);
}
void CMainWindow::on_actQuestionsTest_triggered()
{
int iCount=0;
CExam exam;
if (checkForErrors()) return;
iCount = m_pCatalog->countExam();
if (iCount == 0)
{
QMessageBox::information(this, tr("Information"), tr("Dieser Fragenkatalog enthält keine Prüfungen."));
return;
}
else if (iCount == 1)
{
exam = m_pCatalog->examAt(0);
}
else if (iCount > 1)
{
CDlgExamSelect dlg1(this);
dlg1.setup(m_pCatalog);
dlg1.exec();
if (dlg1.result() == QDialog::Rejected) return;
exam = m_pCatalog->examAt(dlg1.selectedExam());
}
CDlgExam dlg2(m_pCatalog, this);
if (dlg2.setup(exam))
dlg2.exec();
}
void CMainWindow::on_actQuestionsTestStatistics_triggered()
{
CDlgExamStatistic dlg(this);
if (checkForErrors()) return;
if (m_pCatalog->countExam() == 0)
{
QMessageBox::information(this, tr("Information"), tr("Dieser Fragenkatalog enthält keine Prüfungen."));
return;
}
dlg.go(m_pCatalog);
}
void CMainWindow::on_actViewToolbar_toggled(bool bChecked)
{
if (bChecked)
toolBar->show();
else
toolBar->hide();
}
void CMainWindow::on_actViewStatusbar_toggled(bool bChecked)
{
if (bChecked)
statusbar->show();
else
statusbar->hide();
}
void CMainWindow::on_actHelpWhatsThis_triggered()
{
QWhatsThis::enterWhatsThisMode();
}
void CMainWindow::on_actHelpAbout_triggered()
{
QString str = tr("<b>AFUTrainer Version 3.0</b><br>"
"(c) 2003-2007 by Oliver Saal (DM1OLI)<br><hr>"
"EMail: osaal@gmx.de<br>"
"http://www.oliver-saal.de/software/afutrainer/<hr>"
"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.<p>"
"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.<p>"
"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.");
QMessageBox::about(this,tr("Über..."), str);
}
void CMainWindow::on_actHelpAboutQt_triggered()
{
qApp->aboutQt();
}
void CMainWindow::onCatalogSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected)
{
Q_UNUSED(deselected);
m_pTextQuestion->clear();
if (!selected.indexes().isEmpty())
{
CChapter *pChapter = (CChapter*)selected.indexes().first().internalPointer();
if (pChapter)
m_modelQuestion.setModelData(pChapter);
}
else
m_modelQuestion.clear();
}
void CMainWindow::onQuestionSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected)
{
Q_UNUSED(deselected);
m_pTextQuestion->clear();
if (selected.indexes().isEmpty()) return;
CQuestion *pQuestion = (CQuestion*)selected.indexes().first().internalPointer();
if (pQuestion == 0) return;
m_pTextQuestion->setHtml(pQuestion->showText(m_pCatalog));
}
/*
void CMainWindow::onAnchorClicked (const QUrl &link)
{
QMessageBox::information(this, tr("Click"), link.toString());
m_pTextQuestion->home();
}
*/

91
mainwindow.h Normal file
View File

@ -0,0 +1,91 @@
/***************************************************************************
* 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 MAINWINDOW_H
#define MAINWINDOW_H
#include <qmainwindow.h>
#include <qsplitter.h>
#include <qtreeview.h>
#include <qtextbrowser.h>
#include "catalogmodel.h"
#include "questionmodel.h"
#include "recentfiles.h"
#include "ui_mainwindow.h"
class CMainWindow : public QMainWindow, protected Ui::MainWindow
{
Q_OBJECT
public:
CMainWindow();
~CMainWindow();
protected:
void setCatalog (CCatalog *pCatalog);
void updateWindowTitle();
bool checkForErrors();
bool checkForHomeDir();
protected slots:
void on_actFileNew_triggered();
void on_actFileOpen_triggered();
void on_actFileInformation_triggered();
void on_actFileSave_triggered();
void on_actFileSaveAs_triggered();
void on_actFileImport_triggered();
void on_actFileImportUS_triggered();
void on_actFileExit_triggered();
void on_actQuestionAssistant_triggered();
void on_actQuestionsLearn_triggered();
void on_actQuestionsLearnStatistics_triggered();
void on_actQuestionsTest_triggered();
void on_actQuestionsTestStatistics_triggered();
void on_actViewToolbar_toggled(bool bChecked);
void on_actViewStatusbar_toggled(bool bChecked);
void on_actHelpWhatsThis_triggered();
void on_actHelpAbout_triggered();
void on_actHelpAboutQt_triggered();
void onCatalogSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onQuestionSelectionChanged (const QItemSelection& selected, const QItemSelection& deselected);
void onOpenFile(const QString& strFileName);
// void onAnchorClicked (const QUrl &link );
protected:
CRecentFiles m_rf;
QSplitter *m_pSplitter; // splitter widget
QTreeView *m_pViewChapter; // listview chapters
QTreeView *m_pViewQuestions; // listview questions
QSplitter *m_pSplitter2;
QTextBrowser *m_pTextQuestion;
CCatalog *m_pCatalog;
CCatalogModel m_modelCatalog;
CQuestionModel m_modelQuestion;
};
#endif // MAINWINDOW_H

397
mainwindow.ui Normal file
View File

@ -0,0 +1,397 @@
<ui version="4.0" >
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle" >
<string>AFUTrainer 3.0</string>
</property>
<property name="windowIcon" >
<iconset resource="afutrainer.qrc" >:/icons/32x32/idea.png</iconset>
</property>
<widget class="QWidget" name="centralwidget" />
<widget class="QMenuBar" name="menubar" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_Hilfe" >
<property name="title" >
<string>&amp;Hilfe</string>
</property>
<addaction name="actHelpWhatsThis" />
<addaction name="separator" />
<addaction name="actHelpAbout" />
<addaction name="actHelpAboutQt" />
</widget>
<widget class="QMenu" name="menu_Ansicht" >
<property name="title" >
<string>&amp;Ansicht</string>
</property>
<addaction name="actViewToolbar" />
<addaction name="actViewStatusbar" />
</widget>
<widget class="QMenu" name="menu_Fragen" >
<property name="title" >
<string>&amp;Fragen</string>
</property>
<addaction name="actQuestionsLearn" />
<addaction name="actQuestionAssistant" />
<addaction name="actQuestionsLearnStatistics" />
<addaction name="separator" />
<addaction name="actQuestionsTest" />
<addaction name="actQuestionsTestStatistics" />
</widget>
<widget class="QMenu" name="menuFile" >
<property name="title" >
<string>&amp;Datei</string>
</property>
<addaction name="actFileNew" />
<addaction name="actFileOpen" />
<addaction name="actFileInformation" />
<addaction name="separator" />
<addaction name="actFileSave" />
<addaction name="actFileSaveAs" />
<addaction name="actFileImport" />
<addaction name="actFileImportUS" />
<addaction name="actFileExit" />
</widget>
<addaction name="menuFile" />
<addaction name="menu_Fragen" />
<addaction name="menu_Ansicht" />
<addaction name="menu_Hilfe" />
</widget>
<widget class="QStatusBar" name="statusbar" />
<widget class="QToolBar" name="toolBar" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<attribute name="toolBarArea" >
<number>4</number>
</attribute>
<addaction name="actFileOpen" />
<addaction name="actFileInformation" />
<addaction name="actFileExit" />
<addaction name="separator" />
<addaction name="actQuestionsLearn" />
<addaction name="actQuestionAssistant" />
<addaction name="actQuestionsLearnStatistics" />
<addaction name="actQuestionsTest" />
<addaction name="separator" />
<addaction name="actHelpWhatsThis" />
</widget>
<action name="actFileOpen" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/fileopen.png</iconset>
</property>
<property name="text" >
<string>Ö&amp;ffnen</string>
</property>
<property name="toolTip" >
<string>Öffnet einen Fragenkatalog</string>
</property>
<property name="statusTip" >
<string>Öffnet einen Fragenkatalog</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Datei öffnen&lt;/b>&lt;p>Öffnet einen existierenden Fragenkatalog</string>
</property>
<property name="shortcut" >
<string>Ctrl+O</string>
</property>
</action>
<action name="actFileExit" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/exit.png</iconset>
</property>
<property name="text" >
<string>&amp;Beenden</string>
</property>
<property name="toolTip" >
<string>Beendet den AFUTrainer</string>
</property>
<property name="statusTip" >
<string>Beendet den AFUTrainer</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Beenden&lt;/b>&lt;p>Beendet den AFUTrainer</string>
</property>
<property name="shortcut" >
<string>Alt+F4</string>
</property>
</action>
<action name="actViewToolbar" >
<property name="checkable" >
<bool>true</bool>
</property>
<property name="checked" >
<bool>true</bool>
</property>
<property name="text" >
<string>&amp;Werkzeugleiste</string>
</property>
<property name="toolTip" >
<string>Aktiviert/deaktiviert die Werkzeugleiste</string>
</property>
<property name="statusTip" >
<string>Aktiviert/deaktiviert die Werkzeugleiste</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Werkzeugleiste&lt;/b>&lt;p>Aktiviert/deaktiviert die Werkzeugleiste</string>
</property>
</action>
<action name="actViewStatusbar" >
<property name="checkable" >
<bool>true</bool>
</property>
<property name="checked" >
<bool>true</bool>
</property>
<property name="text" >
<string>&amp;Statusleiste</string>
</property>
<property name="toolTip" >
<string>Aktiviert/deaktiviert die Statusleiste</string>
</property>
<property name="statusTip" >
<string>Aktiviert/deaktiviert die Statusleiste</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Statusleiste&lt;/b>&lt;p>Aktiviert/deaktiviert die Statusleiste</string>
</property>
</action>
<action name="actHelpAbout" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/idea.png</iconset>
</property>
<property name="text" >
<string>&amp;Über...</string>
</property>
<property name="iconText" >
<string>Über</string>
</property>
<property name="toolTip" >
<string>Über den AFUTrainer</string>
</property>
<property name="statusTip" >
<string>Über den AFUTrainer</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Über&lt;/b>&lt;p>Copyright-Hinweise und Autoren</string>
</property>
</action>
<action name="actHelpWhatsThis" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/contexthelp.png</iconset>
</property>
<property name="text" >
<string>Was ist &amp;das?</string>
</property>
<property name="statusTip" >
<string>Was ist das?</string>
</property>
<property name="shortcut" >
<string>Shift+F1</string>
</property>
</action>
<action name="actQuestionsView" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/viewmag.png</iconset>
</property>
<property name="text" >
<string>&amp;Ansehen...</string>
</property>
<property name="toolTip" >
<string>Zeigt ausgewählte Frage an</string>
</property>
<property name="statusTip" >
<string>Zeigt ausgewählte Frage an</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Frage ansehen&lt;/b>&lt;p>Zeigt die Frage mit Anworten und Statistik&lt;br>in einem neuen Fenster an</string>
</property>
<property name="shortcut" >
<string>F3</string>
</property>
</action>
<action name="actQuestionsLearn" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/idea.png</iconset>
</property>
<property name="text" >
<string>&amp;Lernen...</string>
</property>
<property name="toolTip" >
<string>Fragen lernen</string>
</property>
<property name="statusTip" >
<string>Fragen lernen</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Fragen lernen&lt;/b>&lt;p>Hier können Sie die Fragen lernen. Eine Frage wird so lange abgefragt, bis Sie sie richtig beantworten können.</string>
</property>
<property name="shortcut" >
<string>F4</string>
</property>
</action>
<action name="actQuestionsLearnStatistics" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/stats.png</iconset>
</property>
<property name="text" >
<string>&amp;Lernstatistik...</string>
</property>
<property name="toolTip" >
<string>Zeigt Lernstatistik des ausgewählten Kapitels an</string>
</property>
<property name="statusTip" >
<string>Zeigt Lernstatistik des ausgewählten Kapitels an</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Lernstatistik&lt;/b>&lt;p>Zeigt Lernstatistik des ausgewählten Kapitels an</string>
</property>
</action>
<action name="actQuestionsTest" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/clock.png</iconset>
</property>
<property name="text" >
<string>&amp;Prüfungssimulation...</string>
</property>
<property name="toolTip" >
<string>Simuliert die Prüfung</string>
</property>
<property name="statusTip" >
<string>Simuliert die Prüfung</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Prüfungssimulation&lt;/b>&lt;p>Sie erhalten zufällig generierte Fragenbögen,&lt;br>die Sie in vorgegebener Zeit lösen müssen!</string>
</property>
<property name="shortcut" >
<string>F6</string>
</property>
</action>
<action name="actQuestionsTestStatistics" >
<property name="text" >
<string>&amp;Prüfstatistik...</string>
</property>
<property name="toolTip" >
<string>Zeigt Ergebnisse der Prüfungssimulationen an</string>
</property>
<property name="statusTip" >
<string>Zeigt Ergebnisse der Prüfungssimulationen an</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Prüfstatistik&lt;/b>&lt;p>Sie erhalten eine detaillierte Auflistung&lt;br>der Ergebnisse der Prüfungssimulationen.</string>
</property>
</action>
<action name="actHelpAboutQt" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/32x32/qt.png</iconset>
</property>
<property name="text" >
<string>Über &amp;Qt...</string>
</property>
<property name="toolTip" >
<string>Über die Qt-Bibliothek</string>
</property>
<property name="statusTip" >
<string>Über die Qt-Bibliothek</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Über Qt&lt;/b>&lt;p>Zeigt Copyright-Hinweise zur verwendeten Qt-Bibliothek an</string>
</property>
</action>
<action name="actFileImport" >
<property name="text" >
<string>&amp;Import DE...</string>
</property>
<property name="iconText" >
<string>Import DE</string>
</property>
<property name="toolTip" >
<string>Import DE</string>
</property>
</action>
<action name="actFileNew" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/filenew.png</iconset>
</property>
<property name="text" >
<string>&amp;Neu</string>
</property>
</action>
<action name="actFileSave" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/filesave.png</iconset>
</property>
<property name="text" >
<string>&amp;Speichern</string>
</property>
</action>
<action name="actFileSaveAs" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/filesaveas.png</iconset>
</property>
<property name="text" >
<string>Speichern &amp;unter...</string>
</property>
</action>
<action name="actQuestionAssistant" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/idea_info.png</iconset>
</property>
<property name="text" >
<string>Lern-Assistent...</string>
</property>
<property name="toolTip" >
<string>Ruft den Lern-Assistenten auf</string>
</property>
<property name="statusTip" >
<string>Ruft den Lern-Assistenten auf</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Lern-Assistent&lt;/b>&lt;p>Der Lern-Assistent hilft Ihnen beim Auswahl der zu lerndenden Fragen.</string>
</property>
<property name="shortcut" >
<string>F5</string>
</property>
</action>
<action name="actFileImportUS" >
<property name="text" >
<string>Import US...</string>
</property>
</action>
<action name="actFileInformation" >
<property name="icon" >
<iconset resource="afutrainer.qrc" >:/icons/16x16/info.png</iconset>
</property>
<property name="text" >
<string>&amp;Information...</string>
</property>
<property name="toolTip" >
<string>Informationen zum Fragenkatalog</string>
</property>
<property name="statusTip" >
<string>Zeigt Informationen zum Fragenkatalog an.</string>
</property>
<property name="whatsThis" >
<string>&lt;b>Information&lt;/b>&lt;p>Zeigt Informationen, wie z.B. Gültigkeitseitraum, Herausgeber, Version,... zum aktuell geladenen Fragenkatalog an.</string>
</property>
</action>
</widget>
<resources>
<include location="afutrainer.qrc" />
</resources>
<connections/>
</ui>

467
osziparchive.cpp Normal file
View File

@ -0,0 +1,467 @@
#include "osziparchive.h"
#include "zlib/zlib.h"
#include <qbytearray.h>
#include <qdatastream.h>
#include <qtextstream.h>
void CZipFileHeader::clear()
{
m_uVersionMadeBy = 0;
m_uVersionNeeded = 0;
m_uFlags = 0;
m_uCompression = 0;
m_uTime = 0;
m_uDate = 0;
m_uCRC = 0;
m_uSizeCompressed = 0;
m_uSizeUncompressed = 0;
m_uDiskNumberStart = 0;
m_uInternalFileAttributes = 0;
m_uExternalFileAttributes = 0;
m_uRelativeOffsetLocalHeader = 0;
m_strFileName.clear();
m_strComment.clear();
m_baExtraField.clear();
// helpers
m_uDataPosition = 0;
m_uLocalHeaderPosition = 0;
m_uCentralHeaderPosition = 0;
}
void CZipFileHeader::integrate(const CZipFileHeader& head)
{
if (m_uVersionMadeBy == 0) m_uVersionMadeBy = head.m_uVersionMadeBy;
if (m_uVersionNeeded == 0) m_uVersionNeeded = head.m_uVersionNeeded;
if (m_uFlags == 0) m_uFlags = head.m_uFlags;
if (m_uCompression == 0) m_uCompression = head.m_uCompression;
if (m_uTime == 0) m_uTime = head.m_uTime;
if (m_uDate == 0) m_uDate = head.m_uDate;
if (m_uCRC == 0) m_uCRC = head.m_uCRC;
if (m_uSizeCompressed == 0) m_uSizeCompressed = head.m_uSizeCompressed;
if (m_uSizeUncompressed == 0) m_uSizeUncompressed = head.m_uSizeUncompressed;
if (m_uDiskNumberStart == 0) m_uDiskNumberStart = head.m_uDiskNumberStart;
if (m_uInternalFileAttributes == 0) m_uInternalFileAttributes = head.m_uInternalFileAttributes;
if (m_uExternalFileAttributes == 0) m_uExternalFileAttributes = head.m_uExternalFileAttributes;
if (m_uRelativeOffsetLocalHeader == 0) m_uRelativeOffsetLocalHeader = head.m_uRelativeOffsetLocalHeader;
if (m_strFileName.isEmpty()) m_strFileName = head.m_strFileName;
if (m_baExtraField.isEmpty()) m_baExtraField = head.m_baExtraField;
if (m_strComment.isEmpty()) m_strComment = head.m_strComment;
if (m_uDataPosition == 0) m_uDataPosition = head.m_uDataPosition;
if (m_uLocalHeaderPosition == 0) m_uLocalHeaderPosition = head.m_uLocalHeaderPosition;
if (m_uCentralHeaderPosition == 0) m_uCentralHeaderPosition = head.m_uCentralHeaderPosition;
}
bool CZipFileHeader::readLocalFileHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uLocalHeaderPosition = file.pos();
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
m_uDataPosition = file.pos();
in.skipRawData(m_uSizeCompressed);
if (hasDataDescriptor())
{
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
}
return true;
}
void CZipFileHeader::writeLocalFileHeader(QFile& file)
{
Q_UNUSED(file);
}
bool CZipFileHeader::readCentralDirectoryHeader(QFile& file)
{
QDataStream in(&file);
quint16 uFileNameLength=0, uExtraFieldLength=0, uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
m_uCentralHeaderPosition = file.pos();
in >> m_uVersionMadeBy;
in >> m_uVersionNeeded;
in >> m_uFlags;
in >> m_uCompression;
in >> m_uTime;
in >> m_uDate;
in >> m_uCRC;
in >> m_uSizeCompressed;
in >> m_uSizeUncompressed;
in >> uFileNameLength;
in >> uExtraFieldLength;
in >> uCommentLength;
in >> m_uDiskNumberStart;
in >> m_uInternalFileAttributes;
in >> m_uExternalFileAttributes;
in >> m_uRelativeOffsetLocalHeader;
if (uFileNameLength != 0)
{
QByteArray a (uFileNameLength, 0);
in.readRawData(a.data(), uFileNameLength);
m_strFileName = a;
}
if (uExtraFieldLength != 0)
{
m_baExtraField.resize(uExtraFieldLength);
in.readRawData(m_baExtraField.data(), uExtraFieldLength);
}
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipFileHeader::writeCentralDirectoryHeader(QFile& file)
{
Q_UNUSED(file);
}
void CZipEndRecord::clear()
{
m_uDisk = 0;
m_uDiskCentralDir = 0;
m_uEntriesCentralDirDisk = 0;
m_uEntriesCentralDir = 0;
m_uCentralDirSize = 0;
m_uCentralDirOffset = 0;
m_strComment.clear();
}
bool CZipEndRecord::read (QFile& file)
{
QDataStream in(&file);
quint16 uCommentLength=0;
clear();
in.setByteOrder(QDataStream::LittleEndian);
in >> m_uDisk;
in >> m_uDiskCentralDir;
in >> m_uEntriesCentralDirDisk;
in >> m_uEntriesCentralDir;
in >> m_uCentralDirSize;
in >> m_uCentralDirOffset;
in >> uCommentLength;
if (uCommentLength != 0)
{
QByteArray a (uCommentLength, 0);
in.readRawData(a.data(), uCommentLength);
m_strComment = a;
}
return true;
}
void CZipEndRecord::write (QFile& file)
{
Q_UNUSED(file);
}
CZipFile::CZipFile(CZipArchive *pArchive)
{
m_pArchive = pArchive;
clear();
}
CZipFile::~CZipFile()
{
}
void CZipFile::clear()
{
}
bool CZipFile::readHeader ()
{
QFile& file = m_pArchive->m_file;
return (m_head.readLocalFileHeader(file));
}
QByteArray CZipFile::deflateToByteArray()
{
/*QByteArray a, b;
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
m_pArchive->m_file.seek (m_head.m_uDataPosition);
a = m_pArchive->m_file.read (m_head.m_uSizeCompressed);
b.resize(m_head.m_uSizeUncompressed);
quint32 u = m_head.m_uSizeUncompressed;
Bytef* src = (Bytef*)a.data();
Bytef* dst = (Bytef*)b.data();
if (uncompress(dst, (uLongf*) &u, src, m_head.m_uSizeCompressed) != Z_OK)
return QByteArray();
return b;*/
QByteArray a;
z_stream strm;
char *pIn=0, *pOut=0;
int ret;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return QByteArray();
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return QByteArray();
// read data
pIn = new char[m_head.m_uSizeCompressed+1];
memset (pIn, 0, m_head.m_uSizeCompressed+1);
m_pArchive->m_file.seek (m_head.m_uDataPosition);
m_pArchive->m_file.read (pIn, m_head.m_uSizeCompressed);
// prepare output
pOut = new char[m_head.m_uSizeUncompressed];
memset(pOut, 0, m_head.m_uSizeUncompressed);
/*
// DEBUG START
FILE *fpt;
fpt = fopen ("questions.xml", "rt");
fread (pOut, m_head.m_uSizeUncompressed, 1, fpt);
fclose (fpt);
unsigned u = m_head.m_uSizeCompressed;
fpt = fopen ("test2.gz", "wb");
compress2((Bytef*)pIn, (uLongf*) &u, (Bytef*)pOut, m_head.m_uSizeUncompressed, 9);
fwrite (pIn, u, 1, fpt);
fclose (fpt);
// DEBUG ENDE
*/
do
{
strm.avail_in = m_head.m_uSizeCompressed+1;
strm.next_in = (Bytef*) pIn;
do
{
strm.avail_out = m_head.m_uSizeUncompressed;
strm.next_out = (Bytef*) pOut;
ret = inflate (&strm, Z_SYNC_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
delete [] pIn;
delete [] pOut;
return QByteArray();
}
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
a = QByteArray (pOut, m_head.m_uSizeUncompressed);
delete [] pIn;
delete [] pOut;
return a;
}
/*
QString CZipFile::deflateToString()
{
QByteArray a = deflateToByteArray();
QTextStream in (a, QIODevice::ReadOnly);
//QString str;
// in >> str;
return in.readAll();
}
*/
#define CHUNK (1<<16)
bool CZipFile::deflateToFile (QIODevice& dev)
{
z_stream strm;
char cIn[CHUNK], cOut[CHUNK];
int ret;
if ((dev.openMode() & QIODevice::WriteOnly) == 0)
return false;
memset(&strm, 0, sizeof(z_stream));
if (m_head.m_uDataPosition == 0 || m_head.m_uSizeUncompressed == 0) return false;
// prepare zip-stream
/* windowBits is passed < 0 to tell that there is no zlib header.
* Note that in this case inflate *requires* an extra "dummy" byte
* after the compressed stream in order to complete decompression and
* return Z_STREAM_END.
*/
if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) return false;
// prepare archive
m_pArchive->m_file.seek (m_head.m_uDataPosition);
// unzip
unsigned uRead=0, uBytes=0;
do
{
uBytes = m_pArchive->m_file.read(cIn, CHUNK);
if (uRead + uBytes > m_head.m_uSizeCompressed)
uBytes = m_head.m_uSizeCompressed - uRead + 1; // one dummy byte extra
uRead += uBytes;
strm.avail_in = uBytes;
if (strm.avail_in == 0) break;
strm.next_in = (Bytef*) cIn;
do
{
strm.avail_out = CHUNK;
strm.next_out = (Bytef*) cOut;
ret = inflate (&strm, Z_NO_FLUSH);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
inflateEnd(&strm);
return false;
}
unsigned uHave = CHUNK - strm.avail_out;
dev.write(cOut, uHave);
}
while (strm.avail_out == 0);
/* done when inflate() says it's done */
}
while (ret != Z_STREAM_END);
inflateEnd(&strm);
return true;
}
CZipArchive::CZipArchive()
{
}
CZipArchive::~CZipArchive()
{
qDeleteAll(m_listFiles);
qDeleteAll(m_listEndRecords);
}
bool CZipArchive::open (const QString& strFileName, const OpenMode om)
{
unsigned uSignature=0;
CZipFile *pzf=0;
if (strFileName.isEmpty()) return false;
if (om != OpenReadOnly) return false;
m_strFileName = strFileName;
m_file.close();
m_file.setFileName(strFileName);
if (!m_file.open(QIODevice::ReadOnly)) return false;
QDataStream in(&m_file);
in.setByteOrder(QDataStream::LittleEndian);
while (!in.atEnd())
{
uSignature = 0;
in >> uSignature;
if (uSignature == 0x04034b50)
{ // local file header with data
pzf = new CZipFile(this);
if (pzf->readHeader())
m_listFiles.append(pzf);
//qDebug("%7i %7i %s", pzf->m_head.m_uSizeUncompressed, pzf->m_head.m_uSizeCompressed, qPrintable(pzf->fileName()));
// file.deflateToFile("test.tmp");
}
else if (uSignature == 0x02014b50)
{ // central directory file header
CZipFileHeader head;
head.readCentralDirectoryHeader(m_file);
pzf = findFile(head.m_strFileName);
if (pzf) pzf->m_head.integrate(head);
}
else if (uSignature == 0x06054b50)
{ // End of central directory record
CZipEndRecord *pzer = new CZipEndRecord();
pzer->read(m_file);
m_listEndRecords.append(pzer);
}
else
{
qDebug("Unknown signature: %X", uSignature);
break;
}
}
return true;
}
CZipFile* CZipArchive::findFile (const QString& strFileName)
{
for (int i=0; i<m_listFiles.size(); i++)
{
if (m_listFiles.at(i)->fileName() == strFileName)
return m_listFiles.at(i);
}
return 0;
}

155
osziparchive.h Normal file
View File

@ -0,0 +1,155 @@
/***************************************************************************
* Copyright (C) 2003-2006 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 OSZIPARCHIVE_H
#define OSZIPARCHIVE_H
#include <qfile.h>
#include <qstring.h>
#include <qlist.h>
class CZipFile;
class CZipArchive;
class CZipFileHeader
{
public:
CZipFileHeader() { clear(); }
~CZipFileHeader() {}
void clear();
void integrate(const CZipFileHeader& head);
bool readLocalFileHeader(QFile& file);
void writeLocalFileHeader(QFile& file);
bool readCentralDirectoryHeader(QFile& file);
void writeCentralDirectoryHeader(QFile& file);
inline bool hasDataDescriptor() const { return m_uFlags & (1<<3) ? true : false; }
public:
quint16 m_uVersionMadeBy; //!< version made by 2 bytes
quint16 m_uVersionNeeded; //!< version needed to extract 2 bytes
quint16 m_uFlags; //!< general purpose bit flag 2 bytes
quint16 m_uCompression; //!< compression method 2 bytes
quint16 m_uTime; //!< last mod file time 2 bytes
quint16 m_uDate; //!< last mod file date 2 bytes
quint32 m_uCRC; //!< crc-32 4 bytes
quint32 m_uSizeCompressed; //!< compressed size 4 bytes
quint32 m_uSizeUncompressed; //!< uncompressed size 4 bytes
quint16 m_uDiskNumberStart; //!< disk number start 2 bytes
quint16 m_uInternalFileAttributes; //!< internal file attributes 2 bytes
quint32 m_uExternalFileAttributes; //!< external file attributes 4 bytes
quint32 m_uRelativeOffsetLocalHeader; //!< relative offset of local header 4 bytes
QString m_strFileName; //!< file name (variable size)
QByteArray m_baExtraField; //!< extra field (variable size)
QString m_strComment; //!< file comment (variable size)
// helpers
quint64 m_uLocalHeaderPosition; //!< Position of the local file header, after the signature field
quint64 m_uDataPosition; //!< Position in the file of the data
quint64 m_uCentralHeaderPosition; //!< Position of the central directory file header, after the signature field
};
class CZipEndRecord
{
public:
CZipEndRecord() { clear(); }
~CZipEndRecord() { }
void clear();
bool read (QFile& file);
void write (QFile& file);
public:
quint16 m_uDisk; //!< number of this disk 2 bytes
quint16 m_uDiskCentralDir; //!< number of the disk with the start of the central directory 2 bytes
quint16 m_uEntriesCentralDirDisk; //!< total number of entries in the central directory on this disk 2 bytes
quint16 m_uEntriesCentralDir; //!< total number of entries in the central directory 2 bytes
quint32 m_uCentralDirSize; //!< size of the central directory 4 bytes
quint32 m_uCentralDirOffset; //!< offset of start of central directory with respect to the starting disk number 4 bytes
QString m_strComment;
};
//! Represents a file in a zip archive
class CZipFile
{
public:
CZipFile() { m_pArchive = 0; clear(); }
CZipFile(CZipArchive *pArchive);
~CZipFile();
void clear();
inline bool isValid() const { return m_pArchive != 0; }
//! Reads local file header
//! Position has to be after the signature field
//! After the operation, the current position in the file is after the file data
bool readHeader();
bool deflateToFile (QIODevice& dev);
QByteArray deflateToByteArray();
//QString deflateToString();
// bool read (FILE *fpt, unsigned uPosition);
//! this file has a data descriptor
inline QString fileName() const { return m_head.m_strFileName; }
public:
CZipArchive *m_pArchive;
CZipFileHeader m_head;
};
class CZipArchive
{
public:
CZipArchive();
~CZipArchive();
enum OpenMode { OpenReadOnly, OpenCreate, OpenModify };
bool open (const QString& strFileName, const OpenMode om);
CZipFile* findFile (const QString& strFileName);
inline int fileCount() const { return m_listFiles.size(); }
const CZipFile* fileAt(const int i) const { return m_listFiles.at(i); }
CZipFile* fileAt(const int i) { return m_listFiles.at(i); }
protected:
friend class CZipFile;
QFile m_file;
QString m_strFileName;
QList<CZipFile*> m_listFiles;
QList<CZipEndRecord*> m_listEndRecords;
};
#endif

426
plotwidget.cpp Normal file
View File

@ -0,0 +1,426 @@
/***************************************************************************
* 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 "plotwidget.h"
#include <qpainter.h>
void CPlotWidgetPoint::clear()
{
}
void CPlotWidgetCurve::clear()
{
QList<CPlotWidgetPoint>::clear();
}
QRectF CPlotWidgetCurve::boundaries() const
{
QRectF rect;
for (int i=0; i<size(); i++)
{
QPointF p = at(i);
if (i == 0)
{
rect.setBottomLeft(p);
rect.setTopRight(p);
}
else
{
if (p.x() < rect.left())
rect.setLeft(p.x());
else if (p.x() > rect.right())
rect.setRight(p.x());
if (p.y() > rect.bottom())
rect.setBottom(p.y());
else if (p.y() < rect.top())
rect.setTop(p.y());
}
}
return rect;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QString& strText)
{
clear();
m_dPos = dPos;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const double dWidth, const QString& strText)
{
clear();
m_dPos = dPos;
m_dWidth = dWidth;
m_strText = strText;
}
CPlotWidgetTic::CPlotWidgetTic(const double dPos, const QPixmap& pixmap)
{
clear();
m_dPos = dPos;
m_pixmap = pixmap;
}
void CPlotWidgetTic::clear()
{
m_dPos = 0.0;
m_dWidth = 0.0;
m_pen = QPen(Qt::DashLine);
m_pen.setColor(Qt::darkGray);
m_penFont = QPen(Qt::black);
m_pixmap = QPixmap();
m_strText.clear();
m_fillType = FillNone;
m_lineType = LinePlot;
m_iTextFlags = Qt::AlignHCenter | Qt::AlignTop;
}
void CPlotWidgetTic::paintX (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top()));
ptBR = pWidget->mapToPlot(QPointF(m_dPos+m_dWidth, pWidget->m_rectData.bottom()));
if (m_fillType == FillAll)
{
ptTL.setY(pWidget->m_rectPlot.top());
ptBR.setY(pWidget->m_rectPlot.bottom());
}
if (ptTL.x() < pWidget->m_rectPlot.left())
ptTL.setX(pWidget->m_rectPlot.left());
if (ptBR.x() > pWidget->m_rectPlot.right())
ptBR.setX(pWidget->m_rectPlot.right());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(ptTL.x(), pWidget->m_rectPlot.bottom() + 5),
QPoint(ptBR.x(), pWidget->rect().bottom()));
}
else
{
rectText = QRect();
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.top())),
pWidget->mapToPlot(QPointF(m_dPos, pWidget->m_rectData.bottom())));
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
void CPlotWidgetTic::paintY (QPainter *pPainter, CPlotWidget *pWidget) const
{
QPoint ptTL, ptBR; // TopLeft, BottomRight
QRect rectText;
if (m_fillType != FillNone && m_dWidth > 0.0)
{
ptTL = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
ptBR = pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos+m_dWidth));
if (m_fillType == FillAll)
{
ptTL.setX(pWidget->m_rectPlot.left());
ptBR.setX(pWidget->m_rectPlot.right());
}
if (ptTL.y() < pWidget->m_rectPlot.top())
ptTL.setY(pWidget->m_rectPlot.top());
if (ptBR.y() > pWidget->m_rectPlot.bottom())
ptBR.setY(pWidget->m_rectPlot.bottom());
pPainter->fillRect(QRect(ptTL, ptBR), m_brush);
rectText = QRect(
QPoint(3, ptTL.y()),
QPoint(pWidget->m_rectPlot.left()-3, ptBR.y()));
}
else
{
QFontMetrics fm(m_font);
QPoint pt = pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos));
rectText = QRect(
QPoint(3, pt.y()-fm.height()),
QPoint(pWidget->m_rectPlot.left()-3, pt.y()+fm.height()));
}
if (m_lineType != LineNone)
{
pPainter->setPen(m_pen);
pPainter->drawLine(
pWidget->mapToPlot(QPointF(pWidget->m_rectData.left(), m_dPos)),
pWidget->mapToPlot(QPointF(pWidget->m_rectData.right(), m_dPos)));
}
if (!m_pixmap.isNull())
{
// Ziel-Mittelpunkt errechnen
QPoint pt = pWidget->mapToPlot(QPointF(0, m_dPos));
pt.setX(pWidget->m_rectPlot.left() - m_pixmap.width()/2 - 5);
// Linke obere Ecke errechnen und malen!
pt -= QPoint (m_pixmap.width()/2, m_pixmap.height()/2);
pPainter->drawPixmap(pt, m_pixmap);
}
if (!m_strText.isEmpty())
{
pPainter->setPen(m_penFont);
pPainter->drawText(rectText, m_iTextFlags, m_strText);
}
}
CPlotWidget::CPlotWidget(QWidget *pParent) : QFrame(pParent)
{
clear();
}
void CPlotWidget::clear()
{
m_type = PlotLines;
m_bLimitAutoY = true;
m_bLimitAutoX = true;
m_dLimitXMin = 0.0;
m_dLimitXMax = 10.0;
m_dLimitYMin = 0.0;
m_dLimitYMax = 10.0;
m_dLimitXRound = 0.0;
m_dLimitYRound = 0.0;
m_dTicX = 0.0;
m_penTicX = QPen(Qt::DashLine);
m_penTicX.setColor(Qt::darkGray);
m_dTicY = 0.0;
m_penTicY = QPen(Qt::DashLine);
m_penTicY.setColor(Qt::darkGray);
m_iBorder = BorderLeft|BorderBottom;
m_iBorderDistTop = 5;
m_iBorderDistBottom = 5;
m_iBorderDistLeft = 5;
m_iBorderDistRight = 5;
m_brushPlotBkg = QBrush(Qt::white);
m_listTicX.clear();
m_listTicY.clear();
m_dBarWidth = 0.6;
m_dBarOffset = 0.0;
m_listCurves.clear();
}
void CPlotWidget::setBorderDistance(const int iLeft, const int iRight, const int iTop, const int iBottom)
{
m_iBorderDistTop = iTop;
m_iBorderDistBottom = iBottom;
m_iBorderDistLeft = iLeft;
m_iBorderDistRight = iRight;
}
void CPlotWidget::updateCache()
{
m_rectPlot = plotArea();
m_rectData = rectData();
}
QRect CPlotWidget::plotArea() const
{
QRect rect = frameRect();
rect.adjust(m_iBorderDistLeft, m_iBorderDistTop, -m_iBorderDistRight, -m_iBorderDistBottom);
return rect;
}
QRectF CPlotWidget::rectData() const
{
QRectF rect;
if (m_bLimitAutoX || m_bLimitAutoY)
{
for (int i=0; i<m_listCurves.size(); i++)
{
rect = rect.united(m_listCurves.at(i).boundaries());
}
}
if (!m_bLimitAutoX)
{
rect.setLeft(m_dLimitXMin);
rect.setRight(m_dLimitXMax);
}
else if (m_dLimitXRound > 0.0)
{
rect.setLeft((unsigned)(rect.left() / m_dLimitXRound) * m_dLimitXRound);
rect.setRight((unsigned)(rect.right() / m_dLimitXRound + 1) * m_dLimitXRound);
}
if (!m_bLimitAutoY)
{
rect.setTop(m_dLimitYMin);
rect.setBottom(m_dLimitYMax);
}
else if (m_dLimitYRound > 0.0)
{
rect.setTop((unsigned)(rect.top() / m_dLimitYRound) * m_dLimitYRound);
rect.setBottom((unsigned)(rect.bottom() / m_dLimitYRound + 1) * m_dLimitYRound);
}
return rect;
}
QPoint CPlotWidget::mapToPlot (QPointF p)
{
QPointF ret;
double m;
// Umrechung X-Koordinate
m = ((double) (m_rectPlot.left() - m_rectPlot.right())) / (m_rectData.left() - m_rectData.right());
ret.setX(m * (p.x() - m_rectData.left()) + m_rectPlot.left());
// Umrechnung Y-Koordinate (mit Spiegelung)
m = ((double) (m_rectPlot.bottom() - m_rectPlot.top())) / (m_rectData.top() - m_rectData.bottom());
ret.setY(m * (p.y() - m_rectData.top()) + m_rectPlot.bottom());
return ret.toPoint();
}
void CPlotWidget::paintEvent (QPaintEvent *e)
{
QList<QPoint> listPoints;
QList<CPlotWidgetTic> listTicsX, listTicsY;
double d=0.0;
int i=0;
QFrame::paintEvent(e);
QPainter painter(this);
updateCache();
// Draw Background
if (m_brushPlotBkg.style() != Qt::NoBrush)
{
painter.fillRect(m_rectPlot, m_brushPlotBkg);
}
// Draw Tics
listTicsX = m_listTicX;
if (listTicsX.isEmpty() && m_dTicX > 0.0)
{
d = ((unsigned)(m_rectData.left() / m_dTicX)) * m_dTicX;
if (d < m_rectData.left()) d+=m_dTicX;
while (d <= m_rectData.right())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicX);
listTicsX.append(tic);
d += m_dTicX;
}
}
listTicsY = m_listTicY;
if (listTicsY.isEmpty() && m_dTicY > 0.0)
{
d = ((unsigned)(m_rectData.top() / m_dTicY)) * m_dTicY;
if (d < m_rectData.top()) d+=m_dTicY;
while (d <= m_rectData.bottom())
{
CPlotWidgetTic tic(d, QString("%1").arg(d,0,'f',2));
tic.setPen(m_penTicY);
listTicsY.append(tic);
d += m_dTicY;
}
}
for (i=0; i<listTicsX.size(); i++)
listTicsX.at(i).paintX(&painter, this);
for (i=0; i<listTicsY.size(); i++)
listTicsY.at(i).paintY(&painter, this);
// Draw Curves
if (m_type == PlotLines)
{
for (int i=0; i<m_listCurves.size(); i++)
{
CPlotWidgetCurve c = m_listCurves.at(i);
for (int j=0; j<c.size(); j++)
{
CPlotWidgetPoint p = c.at(j);
listPoints.append(mapToPlot (p));
}
painter.setPen(c.pen());
painter.drawPolyline(listPoints.toVector());
}
}
else if (m_type == PlotBarsSum && m_listCurves.size() != 0)
{
CPlotWidgetCurve c1 = m_listCurves.at(0);
//painter.setPen(c1.pen());
//painter.setBrush(c1.brush());
QPoint ptTL, ptBR;
for (int j=0; j<c1.size(); j++)
{ // Alle Punkte der ersten Kurve durchgehen
CPlotWidgetPoint p1 = c1.at(j);
ptTL = mapToPlot(QPointF(p1.x() + m_dBarOffset - m_dBarWidth/2, p1.y()));
ptBR = mapToPlot(QPointF(p1.x() + m_dBarOffset + m_dBarWidth/2, m_rectData.top()));
if (p1.y() != 0.0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
painter.fillRect(QRect(ptTL, ptBR), c1.brush());
double dStart = p1.y();
for (int i=1; i<m_listCurves.size(); i++)
{ // alle Weiteren Kurven durchgehen
CPlotWidgetCurve c2 = m_listCurves.at(i);
for (int jj=0; jj<c2.size(); jj++)
{ // alle Punkte der zweiten Kurve durchgehen
CPlotWidgetPoint p2 = c2.at(jj);
if (p2.x() != p1.x()) continue;
ptTL = mapToPlot(QPointF(p2.x() + m_dBarOffset - m_dBarWidth/2, dStart+p2.y()));
ptBR = mapToPlot(QPointF(p2.x() + m_dBarOffset + m_dBarWidth/2, dStart+m_rectData.top()));
if (p2.y() != 0 && m_rectPlot.contains(ptTL) && m_rectPlot.contains(ptBR))
{
dStart += p2.y();
painter.fillRect(QRect(ptTL, ptBR), c2.brush());
}
}
}
}
}
// Draw border
painter.setPen(m_penBorder);
if (m_iBorder & BorderLeft)
painter.drawLine(m_rectPlot.topLeft(), m_rectPlot.bottomLeft());
if (m_iBorder & BorderRight)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.bottomRight());
if (m_iBorder & BorderTop)
painter.drawLine(m_rectPlot.topRight(), m_rectPlot.topLeft());
if (m_iBorder & BorderBottom)
painter.drawLine(m_rectPlot.bottomRight(), m_rectPlot.bottomLeft());
}

Some files were not shown because too many files have changed in this diff Show More