excel2moodle 0.3.3__py3-none-any.whl → 0.3.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- excel2moodle/__init__.py +38 -96
- excel2moodle/__main__.py +5 -5
- excel2moodle/core/__init__.py +1 -3
- excel2moodle/core/category.py +67 -47
- excel2moodle/core/dataStructure.py +89 -73
- excel2moodle/core/etHelpers.py +26 -26
- excel2moodle/core/exceptions.py +12 -5
- excel2moodle/core/globals.py +43 -29
- excel2moodle/core/numericMultiQ.py +28 -24
- excel2moodle/core/parser.py +228 -147
- excel2moodle/core/question.py +100 -69
- excel2moodle/core/questionValidator.py +56 -54
- excel2moodle/core/questionWriter.py +232 -139
- excel2moodle/core/stringHelpers.py +38 -34
- excel2moodle/extra/__init__.py +1 -3
- excel2moodle/extra/equationVerification.py +37 -33
- excel2moodle/logger.py +102 -0
- excel2moodle/ui/appUi.py +133 -125
- excel2moodle/ui/dialogs.py +71 -18
- excel2moodle/ui/settings.py +108 -21
- excel2moodle/ui/treewidget.py +13 -10
- excel2moodle/ui/windowMain.py +18 -57
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/METADATA +4 -3
- excel2moodle-0.3.5.dist-info/RECORD +33 -0
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/WHEEL +1 -1
- excel2moodle-0.3.5.dist-info/entry_points.txt +2 -0
- excel2moodle-0.3.3.dist-info/RECORD +0 -31
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/licenses/LICENSE +0 -0
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Script for verifying the equations written into the ``result`` field of NFM-type Question
|
1
|
+
"""Script for verifying the equations written into the ``result`` field of NFM-type Question.
|
2
2
|
|
3
3
|
This script does two things.
|
4
4
|
|
@@ -28,16 +28,19 @@ As Script
|
|
28
28
|
#. Rinse and repeat
|
29
29
|
"""
|
30
30
|
|
31
|
-
import re as re
|
32
|
-
import pandas as pd
|
33
31
|
from pathlib import Path
|
32
|
+
|
33
|
+
import pandas as pd
|
34
|
+
|
34
35
|
from excel2moodle.core import numericMultiQ as nmq
|
35
36
|
|
36
37
|
# Hier Bitte die Frage angeben, die getestet Werden soll:
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
# ===========================================================
|
40
|
+
|
41
|
+
|
42
|
+
def checkResult(checkerValue: float, calculation: float, tolerance=0.01) -> bool:
|
43
|
+
"""Checks if the two Arguments are within the tolerance the same value.
|
41
44
|
|
42
45
|
:param checkerValue: the value the calculation is compared against
|
43
46
|
:type checkerValue: fleat
|
@@ -46,21 +49,20 @@ def checkResult(checkerValue:float, calculation:float, tolerance = 0.01)-> bool:
|
|
46
49
|
:param tolerance: the standart tolerance is 0.01 -> 1%
|
47
50
|
:type tolerance: float, optional
|
48
51
|
|
49
|
-
:returns:
|
52
|
+
:returns:
|
50
53
|
True if checkerValue == calculation
|
51
54
|
False if checkerValue != calculation
|
52
55
|
:rtype: bool
|
53
56
|
"""
|
57
|
+
upper = abs(checkerValue + checkerValue * tolerance)
|
58
|
+
lower = abs(checkerValue - checkerValue * tolerance)
|
59
|
+
return bool(abs(calculation) > lower and abs(calculation) < upper)
|
54
60
|
|
55
|
-
upper = abs(checkerValue + checkerValue*tolerance)
|
56
|
-
lower = abs(checkerValue - checkerValue*tolerance)
|
57
|
-
if abs(calculation) > lower and abs(calculation) < upper:
|
58
|
-
return True
|
59
|
-
else :
|
60
|
-
return False
|
61
61
|
|
62
|
-
def equationChecker(
|
63
|
-
|
62
|
+
def equationChecker(
|
63
|
+
categoryName: str, qNumber: int, spreadsheetFile
|
64
|
+
) -> tuple[list[str], list[float], float]:
|
65
|
+
"""This Function calculates all Results an invokes the checkResult function.
|
64
66
|
|
65
67
|
Parameters
|
66
68
|
----------
|
@@ -80,8 +82,8 @@ def equationChecker(categoryName: str, qNumber:int, spreadsheetFile)-> tuple[lis
|
|
80
82
|
The list with the calculated results
|
81
83
|
checkerValue : float
|
82
84
|
The value taken from the ``firstResult`` field
|
83
|
-
"""
|
84
85
|
|
86
|
+
"""
|
85
87
|
spreadsheetFile.resolve()
|
86
88
|
df = pd.read_excel(spreadsheetFile, sheet_name=categoryName, index_col=0)
|
87
89
|
eq = df.loc["result"][qNumber]
|
@@ -89,36 +91,38 @@ def equationChecker(categoryName: str, qNumber:int, spreadsheetFile)-> tuple[lis
|
|
89
91
|
try:
|
90
92
|
res = float(df.loc["firstResult"][qNumber])
|
91
93
|
except Exception:
|
92
|
-
print(f"Es ist kein 'firstResult' gegeben, kann nichts überprüfen")
|
93
94
|
res = 0
|
94
|
-
bps, calcs = nmq.parseNumericMultiQuestion(df,bps,eq, qNumber)
|
95
|
+
bps, calcs = nmq.parseNumericMultiQuestion(df, bps, eq, qNumber)
|
95
96
|
return bps, calcs, res
|
96
97
|
|
97
98
|
|
98
|
-
def main(
|
99
|
-
""
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
def main(
|
100
|
+
spreadsheetFile=Path("../Fragensammlung/Main_question_all.xlsx"),
|
101
|
+
catN=None,
|
102
|
+
qNumber=None,
|
103
|
+
) -> None:
|
104
|
+
"""Takes the Spreadsheet, and asks for a category and a question number."""
|
105
|
+
if catN is None:
|
103
106
|
catN = input("Geben Sie die Kategorie an: KAT_")
|
104
107
|
categoryName = f"KAT_{catN}"
|
105
|
-
if qNumber
|
108
|
+
if qNumber is None:
|
106
109
|
qNumber = int(input("Geben Sie die Fragennummer an: "))
|
107
|
-
bullets, results, firstResult = equationChecker(
|
110
|
+
bullets, results, firstResult = equationChecker(
|
111
|
+
categoryName, qNumber, spreadsheetFile=spreadsheetFile
|
112
|
+
)
|
108
113
|
check = False
|
109
114
|
|
110
115
|
for i, calculation in enumerate(results):
|
111
|
-
if i == 0 and firstResult !=0:
|
112
|
-
|
113
|
-
print(f"Ergebnis {i+1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n")
|
116
|
+
if i == 0 and firstResult != 0:
|
117
|
+
check = checkResult(firstResult, calculation)
|
114
118
|
|
115
|
-
if check
|
116
|
-
|
119
|
+
if check:
|
120
|
+
pass
|
117
121
|
else:
|
118
|
-
|
122
|
+
pass
|
119
123
|
|
120
124
|
|
121
|
-
if __name__ =="__main__":
|
122
|
-
spreadsheet =input(
|
125
|
+
if __name__ == "__main__":
|
126
|
+
spreadsheet = input("Geben Sie den Pfad zu dem spreadsheet an:")
|
123
127
|
while True:
|
124
128
|
main(Path(spreadsheet))
|
excel2moodle/logger.py
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
"""Logging Setup for Excel2moodle.
|
2
|
+
|
3
|
+
Mainly this sets up the general configuration.
|
4
|
+
This includes emitting the signals for the main Window, to fast forward all logs.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import logging
|
8
|
+
|
9
|
+
from PySide6.QtCore import QObject, Signal
|
10
|
+
|
11
|
+
from excel2moodle.ui.settings import Settings, SettingsKey
|
12
|
+
|
13
|
+
settings = Settings()
|
14
|
+
|
15
|
+
loggerConfig = {
|
16
|
+
"version": 1,
|
17
|
+
"disable_existing_loggers": False,
|
18
|
+
"formatters": {
|
19
|
+
"standard": {
|
20
|
+
"format": "[{levelname:^8s}] {module:.^14s}: {message}",
|
21
|
+
"style": "{",
|
22
|
+
},
|
23
|
+
"file": {
|
24
|
+
"format": "%(asctime)s [%(levelname)-5s] %(name)12s: %(message)s",
|
25
|
+
},
|
26
|
+
},
|
27
|
+
"handlers": {
|
28
|
+
"default": {
|
29
|
+
"level": "DEBUG",
|
30
|
+
"formatter": "standard",
|
31
|
+
"class": "logging.StreamHandler",
|
32
|
+
"stream": "ext://sys.stdout", # Default is stderr
|
33
|
+
},
|
34
|
+
"file": {
|
35
|
+
"level": "DEBUG",
|
36
|
+
"formatter": "file",
|
37
|
+
"class": "logging.FileHandler",
|
38
|
+
# "class": "logging.handlers.TimedRotatingFileHandler",
|
39
|
+
"filename": settings.get(SettingsKey.LOGFILE),
|
40
|
+
# "when": "M",
|
41
|
+
# "interval": 1,
|
42
|
+
# "backupCount": "3",
|
43
|
+
"delay": "true",
|
44
|
+
},
|
45
|
+
},
|
46
|
+
"loggers": {
|
47
|
+
"": { # root logger
|
48
|
+
"handlers": ["default", "file"],
|
49
|
+
"level": "DEBUG",
|
50
|
+
"propagate": True,
|
51
|
+
},
|
52
|
+
"excel2moodle.questionParser": {
|
53
|
+
"handlers": ["default"],
|
54
|
+
"level": "DEBUG",
|
55
|
+
"propagate": True,
|
56
|
+
},
|
57
|
+
"__main__": { # if __name__ == '__main__'
|
58
|
+
"handlers": ["default"],
|
59
|
+
"level": "DEBUG",
|
60
|
+
"propagate": True,
|
61
|
+
},
|
62
|
+
},
|
63
|
+
}
|
64
|
+
|
65
|
+
|
66
|
+
class QSignaler(QObject):
|
67
|
+
signal = Signal(str)
|
68
|
+
|
69
|
+
|
70
|
+
class LogWindowHandler(logging.Handler):
|
71
|
+
def __init__(self, *args, **kwargs) -> None:
|
72
|
+
super().__init__(*args, **kwargs)
|
73
|
+
self.emitter = QSignaler()
|
74
|
+
# Define a formatter with log level and module
|
75
|
+
log_format = "[%(levelname)s] %(module)s: %(message)s"
|
76
|
+
self.formatter = logging.Formatter(log_format)
|
77
|
+
self.setFormatter(self.formatter)
|
78
|
+
loglevel = settings.get(SettingsKey.LOGLEVEL)
|
79
|
+
self.setLevel(loglevel)
|
80
|
+
self.logLevelColors = {
|
81
|
+
"DEBUG": "gray",
|
82
|
+
"INFO": "green",
|
83
|
+
"WARNING": "orange",
|
84
|
+
"ERROR": "red",
|
85
|
+
"CRITICAL": "pink",
|
86
|
+
}
|
87
|
+
|
88
|
+
def emit(self, record: logging.LogRecord) -> None:
|
89
|
+
"""Emit the signal, with a new logging message."""
|
90
|
+
log_message = self.format(record)
|
91
|
+
color = self.logLevelColors.get(record.levelname, "black")
|
92
|
+
prettyMessage = f'<span style="color:{color};">{log_message}</span>'
|
93
|
+
print("emitting new log signal") # noqa:T201
|
94
|
+
self.emitter.signal.emit(prettyMessage)
|
95
|
+
|
96
|
+
|
97
|
+
class LogAdapterQuestionID(logging.LoggerAdapter):
|
98
|
+
"""Prepend the Question ID to the logging messages."""
|
99
|
+
|
100
|
+
def process(self, msg, kwargs):
|
101
|
+
"""Append the Question ID to the log Message."""
|
102
|
+
return "[{}]: {}".format(self.extra["qID"], msg), kwargs
|
excel2moodle/ui/appUi.py
CHANGED
@@ -1,49 +1,56 @@
|
|
1
|
-
"""
|
1
|
+
"""AppUi holds the extended class mainWindow() and any other main Windows.
|
2
2
|
|
3
|
-
It needs to be seperated from ``windowMain.py`` because that file will be changed by
|
4
|
-
which generates the python code from the ``.ui`` file
|
3
|
+
It needs to be seperated from ``windowMain.py`` because that file will be changed by the
|
4
|
+
``pyside6-uic`` command, which generates the python code from the ``.ui`` file
|
5
5
|
"""
|
6
6
|
|
7
|
-
|
8
|
-
from PySide6.QtCore import Qt
|
9
|
-
from PySide6 import QtWidgets
|
7
|
+
import logging
|
10
8
|
from pathlib import Path
|
11
|
-
|
12
|
-
from
|
13
|
-
from .
|
14
|
-
|
9
|
+
|
10
|
+
from PySide6 import QtCore, QtWidgets
|
11
|
+
from PySide6.QtCore import Qt
|
12
|
+
|
13
|
+
from excel2moodle import qSignalLogger
|
14
|
+
|
15
|
+
# from excel2moodle.logger import LogWindowHandler
|
15
16
|
from excel2moodle.core.dataStructure import QuestionDB
|
16
|
-
from excel2moodle.ui.treewidget import QuestionItem, CategoryItem
|
17
17
|
from excel2moodle.extra import equationVerification as eqVerif
|
18
|
-
from excel2moodle import
|
19
|
-
from excel2moodle.ui.settings import Settings
|
20
|
-
import
|
18
|
+
from excel2moodle.ui import dialogs
|
19
|
+
from excel2moodle.ui.settings import Settings, SettingsKey
|
20
|
+
from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
|
21
|
+
from excel2moodle.ui.windowMain import Ui_MoodleTestGenerator
|
21
22
|
|
23
|
+
from .windowEquationChecker import Ui_EquationChecker
|
22
24
|
|
23
25
|
logger = logging.getLogger(__name__)
|
24
26
|
|
25
27
|
|
26
|
-
|
27
28
|
class MainWindow(QtWidgets.QMainWindow):
|
28
|
-
def __init__(self, settings:Settings, testDB:QuestionDB)->None:
|
29
|
+
def __init__(self, settings: Settings, testDB: QuestionDB) -> None:
|
29
30
|
super().__init__()
|
30
31
|
self.settings = settings
|
31
|
-
self.excelPath: Path|None = None
|
32
|
-
self.mainPath =
|
32
|
+
self.excelPath: Path | None = None
|
33
|
+
self.mainPath = self.excelPath.parent if self.excelPath is not None else None
|
33
34
|
self.exportFile = Path()
|
34
35
|
self.testDB = testDB
|
35
36
|
self.ui = Ui_MoodleTestGenerator()
|
36
37
|
self.ui.setupUi(self)
|
37
38
|
|
38
39
|
self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
39
|
-
self.ui.treeWidget.header().setSectionResizeMode(
|
40
|
-
|
40
|
+
self.ui.treeWidget.header().setSectionResizeMode(
|
41
|
+
QtWidgets.QHeaderView.ResizeToContents,
|
42
|
+
)
|
43
|
+
self.ui.checkBoxIncludeCategories.setChecked(
|
44
|
+
self.settings.get(SettingsKey.INCLUDEINCATS),
|
45
|
+
)
|
41
46
|
|
42
47
|
self.ui.retranslateUi(self)
|
43
|
-
logger.info(
|
48
|
+
logger.info("Settings are stored under: %s", self.settings.fileName())
|
44
49
|
self.ui.pointCounter.setReadOnly(True)
|
45
50
|
self.ui.questionCounter.setReadOnly(True)
|
46
|
-
self.setStatus(
|
51
|
+
self.setStatus(
|
52
|
+
"Wählen Sie bitte eine Excel Tabelle und einen Export Ordner für die Fragen aus",
|
53
|
+
)
|
47
54
|
try:
|
48
55
|
self.resize(self.settings.value("windowSize"))
|
49
56
|
self.move(self.settings.value("windowPosition"))
|
@@ -51,79 +58,58 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
51
58
|
pass
|
52
59
|
self.connectEvents()
|
53
60
|
|
54
|
-
def connectEvents(self)->None:
|
61
|
+
def connectEvents(self) -> None:
|
55
62
|
self.ui.treeWidget.itemClicked.connect(self.onSelectionChanged)
|
56
|
-
self.ui.checkBoxQuestionListSelectAll.checkStateChanged.connect(
|
63
|
+
self.ui.checkBoxQuestionListSelectAll.checkStateChanged.connect(
|
64
|
+
self.toggleQuestionSelectionState,
|
65
|
+
)
|
57
66
|
qSignalLogger.emitter.signal.connect(self.updateLog)
|
58
|
-
self.ui.actionEquationChecker.triggered.connect(self.
|
59
|
-
self.ui.checkBoxIncludeCategories.checkStateChanged.connect(
|
60
|
-
|
61
|
-
|
62
|
-
self.
|
67
|
+
self.ui.actionEquationChecker.triggered.connect(self.openEqCheckerDlg)
|
68
|
+
self.ui.checkBoxIncludeCategories.checkStateChanged.connect(
|
69
|
+
self.setIncludeCategoriesSetting,
|
70
|
+
)
|
71
|
+
self.ui.actionParseAll.triggered.connect(self.onParseAll)
|
72
|
+
self.testDB.dataChanged.signal.connect(self.refreshList)
|
63
73
|
self.ui.buttonSpreadSheet.clicked.connect(self.onButSpreadsheet)
|
64
74
|
self.ui.buttonTestGen.clicked.connect(self.onButGenTest)
|
65
|
-
self.ui.actionPreviewQ.triggered.connect(self.
|
66
|
-
self.ui.actionAbout.triggered.connect(self.
|
75
|
+
self.ui.actionPreviewQ.triggered.connect(self.openPreviewQuestionDlg)
|
76
|
+
self.ui.actionAbout.triggered.connect(self.openAboutDlg)
|
67
77
|
self.settings.shPathChanged.connect(self.onSheetPathChanged)
|
78
|
+
self.ui.spinBoxDefaultQVariant.valueChanged.connect(self.setQVariantDefault)
|
68
79
|
|
80
|
+
@QtCore.Slot()
|
81
|
+
def setQVariantDefault(self, value: int) -> None:
|
82
|
+
self.settings.set(SettingsKey.QUESTIONVARIANT, value)
|
69
83
|
|
70
84
|
@QtCore.Slot(Path)
|
71
|
-
def onSheetPathChanged(self, sheet:Path)->None:
|
85
|
+
def onSheetPathChanged(self, sheet: Path) -> None:
|
72
86
|
logger.debug("Slot, new Spreadsheet triggered")
|
73
87
|
self.spreadSheetPath = sheet
|
74
88
|
self.mainPath = sheet.parent
|
89
|
+
svgFolder = self.mainPath / self.settings.get(SettingsKey.PICTURESUBFOLDER)
|
90
|
+
svgFolder.resolve()
|
91
|
+
self.settings.set(SettingsKey.PICTUREFOLDER, svgFolder)
|
75
92
|
self.ui.buttonSpreadSheet.setText(str(sheet.name))
|
93
|
+
self.testDB.readSpreadsheetData(self.spreadSheetPath)
|
94
|
+
self.testDB.parseAll()
|
95
|
+
self.refreshList()
|
76
96
|
|
77
|
-
def updateLog(self,log)->None:
|
97
|
+
def updateLog(self, log) -> None:
|
78
98
|
self.ui.loggerWindow.append(log)
|
79
99
|
|
80
|
-
def setIncludeCategoriesSetting(self):
|
100
|
+
def setIncludeCategoriesSetting(self) -> None:
|
81
101
|
if self.ui.checkBoxIncludeCategories.isChecked():
|
82
|
-
self.settings.set(
|
83
|
-
logger.debug("set includeCats to True")
|
102
|
+
self.settings.set(SettingsKey.INCLUDEINCATS, True)
|
84
103
|
else:
|
85
|
-
self.settings.set(
|
86
|
-
logger.debug("set includeCats to False")
|
87
|
-
|
88
|
-
|
89
|
-
@QtCore.Slot()
|
90
|
-
def onAbout(self):
|
91
|
-
aboutMessage: str = f"""
|
92
|
-
<h1> About {e2mMetadata['name']}</h1><br>
|
93
|
-
<p style="text-align:center">
|
94
|
-
|
95
|
-
<b><a href="{e2mMetadata['homepage']}">{e2mMetadata['name']}</a> - {e2mMetadata['description']}</b>
|
96
|
-
</p>
|
97
|
-
<p style="text-align:center">
|
98
|
-
The documentation can be found under <b><a href="{e2mMetadata['documentation']}">{e2mMetadata['documentation']}</a></b>
|
99
|
-
</br>
|
100
|
-
</br>
|
101
|
-
If you encounter any issues please report them under the <a href="{e2mMetadata['issues']}"> repositories issues page</a>
|
102
|
-
</br>
|
103
|
-
</p>
|
104
|
-
<p style="text-align:center">
|
105
|
-
This project is maintained by {e2mMetadata['author']}.
|
106
|
-
<br>
|
107
|
-
Development takes place at <a href="{e2mMetadata['homepage']}">{e2mMetadata['homepage']}</a>
|
108
|
-
Contributions are very welcome
|
109
|
-
<br>
|
110
|
-
</p>
|
111
|
-
<p style="text-align:center">
|
112
|
-
<i>This project is published under {e2mMetadata['license']}, you are welcome, to share, modify and reuse the code.</i>
|
113
|
-
</p>
|
114
|
-
"""
|
115
|
-
QtWidgets.QMessageBox.information(self,
|
116
|
-
f"About {e2mMetadata['name']}",
|
117
|
-
aboutMessage)
|
104
|
+
self.settings.set(SettingsKey.INCLUDEINCATS, False)
|
118
105
|
|
119
|
-
def closeEvent(self, event):
|
106
|
+
def closeEvent(self, event) -> None:
|
120
107
|
self.settings.setValue("windowSize", self.size())
|
121
108
|
self.settings.setValue("windowPosition", self.pos())
|
122
109
|
|
123
110
|
@QtCore.Slot()
|
124
|
-
def onSelectionChanged(self,
|
125
|
-
"""Whenever the selection changes the total of selected points needs to be recalculated"""
|
126
|
-
|
111
|
+
def onSelectionChanged(self, **args) -> None:
|
112
|
+
"""Whenever the selection changes the total of selected points needs to be recalculated."""
|
127
113
|
count: int = 0
|
128
114
|
questions: int = 0
|
129
115
|
selection = self.ui.treeWidget.selectedItems()
|
@@ -131,16 +117,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
131
117
|
questions += 1
|
132
118
|
count += q.getQuestion().points
|
133
119
|
|
134
|
-
logger.info(
|
120
|
+
logger.info("%s questions are selected with %s points", questions, count)
|
135
121
|
self.ui.pointCounter.setValue(count)
|
136
122
|
self.ui.questionCounter.setValue(questions)
|
137
|
-
return None
|
138
123
|
|
139
124
|
@QtCore.Slot()
|
140
|
-
def toggleQuestionSelectionState(self, state):
|
141
|
-
|
142
|
-
setter = True
|
143
|
-
else: setter = False
|
125
|
+
def toggleQuestionSelectionState(self, state) -> None:
|
126
|
+
setter = state == Qt.Checked
|
144
127
|
root = self.ui.treeWidget.invisibleRootItem()
|
145
128
|
childN = root.childCount()
|
146
129
|
for i in range(childN):
|
@@ -149,98 +132,123 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
149
132
|
root.child(i).child(q).setSelected(setter)
|
150
133
|
|
151
134
|
@QtCore.Slot()
|
152
|
-
def onButGenTest(self)->None:
|
153
|
-
|
154
|
-
|
155
|
-
|
135
|
+
def onButGenTest(self) -> None:
|
136
|
+
"""Open a file Dialog so the export file may be choosen."""
|
137
|
+
path = QtWidgets.QFileDialog.getSaveFileName(
|
138
|
+
self,
|
139
|
+
"Select Output File",
|
140
|
+
dir=f"{self.mainPath / 'Testfile.xml'}",
|
141
|
+
filter="xml Files (*.xml)",
|
142
|
+
)
|
156
143
|
self.exportFile = Path(path[0])
|
157
|
-
logger.info(
|
158
|
-
selection:list[QuestionItem] = self.ui.treeWidget.selectedItems()
|
144
|
+
logger.info("New Export File is set %s", self.exportFile)
|
145
|
+
selection: list[QuestionItem] = self.ui.treeWidget.selectedItems()
|
159
146
|
self.testDB.appendQuestions(selection, self.exportFile)
|
160
|
-
return None
|
161
147
|
|
162
148
|
@QtCore.Slot()
|
163
|
-
def onButSpreadsheet(self):
|
164
|
-
file = QtWidgets.QFileDialog.getOpenFileName(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
149
|
+
def onButSpreadsheet(self) -> None:
|
150
|
+
file = QtWidgets.QFileDialog.getOpenFileName(
|
151
|
+
self,
|
152
|
+
self.tr("Open Spreadsheet"),
|
153
|
+
dir=str(self.mainPath),
|
154
|
+
filter=self.tr("Spreadsheet(*.xlsx *.ods)"),
|
155
|
+
selectedFilter=("*.ods"),
|
156
|
+
)
|
169
157
|
self.excelPath = Path(file[0]).resolve()
|
170
158
|
self.settings.setSpreadsheet(self.excelPath)
|
171
|
-
logger.debug(f
|
159
|
+
logger.debug(f"Saved Spreadsheet Path: {self.excelPath}\n")
|
172
160
|
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
173
|
-
return None
|
174
|
-
|
175
161
|
|
176
162
|
@QtCore.Slot()
|
177
|
-
def onParseAll
|
178
|
-
"""Event triggered by the *Tools/Parse all Questions* Event
|
163
|
+
def onParseAll(self) -> None:
|
164
|
+
"""Event triggered by the *Tools/Parse all Questions* Event.
|
179
165
|
|
180
|
-
It parses all the Questions found in the spreadsheet
|
166
|
+
It parses all the Questions found in the spreadsheet
|
167
|
+
and then refreshes the list of questions.
|
181
168
|
If successful it prints out a list of all exported Questions
|
182
169
|
"""
|
183
|
-
self.
|
170
|
+
self.testDB.readSpreadsheetData(self.spreadSheetPath)
|
184
171
|
self.testDB.parseAll()
|
185
172
|
self.setStatus("[OK] Alle Fragen wurden erfolgreich in XML-Dateien umgewandelt")
|
186
|
-
|
173
|
+
self.refreshList()
|
174
|
+
|
175
|
+
def refreshList(self) -> None:
|
176
|
+
"""Refresh the question overview in the main window.
|
177
|
+
|
178
|
+
Enable the export Button afterwards.
|
179
|
+
"""
|
187
180
|
logger.info("starting List refresh")
|
188
|
-
cats =
|
181
|
+
cats = self.testDB.categories
|
189
182
|
self.ui.treeWidget.clear()
|
190
183
|
for cat in cats.values():
|
191
|
-
catItem = CategoryItem(self.ui.treeWidget,cat)
|
184
|
+
catItem = CategoryItem(self.ui.treeWidget, cat)
|
192
185
|
catItem.setFlags(catItem.flags() & ~Qt.ItemIsSelectable)
|
193
186
|
for q in cat.questions.values():
|
194
|
-
QuestionItem(catItem,q)
|
187
|
+
QuestionItem(catItem, q)
|
195
188
|
self.setStatus("[OK] Fragen Liste wurde aktualisiert")
|
196
|
-
|
189
|
+
self.ui.buttonTestGen.setEnabled(True)
|
197
190
|
|
198
191
|
@QtCore.Slot()
|
199
|
-
def
|
192
|
+
def openPreviewQuestionDlg(self) -> None:
|
200
193
|
item = self.ui.treeWidget.currentItem()
|
201
194
|
if isinstance(item, QuestionItem):
|
202
195
|
dialog = dialogs.QuestinoPreviewDialog(self, item.getQuestion())
|
203
196
|
dialog.show()
|
204
|
-
else:
|
197
|
+
else:
|
198
|
+
logger.info("current Item is not a Question, can't preview")
|
205
199
|
|
206
|
-
def setStatus(self, status):
|
200
|
+
def setStatus(self, status) -> None:
|
207
201
|
self.ui.statusbar.clearMessage()
|
208
202
|
self.ui.statusbar.showMessage(self.tr(status))
|
209
203
|
|
210
204
|
@QtCore.Slot()
|
211
|
-
def
|
212
|
-
logger.debug(
|
205
|
+
def openEqCheckerDlg(self) -> None:
|
206
|
+
logger.debug("opening wEquationChecker \n")
|
213
207
|
self.uiEqChecker = EqCheckerWindow()
|
214
208
|
self.uiEqChecker.excelFile = self.excelPath
|
215
209
|
self.uiEqChecker.show()
|
216
210
|
|
211
|
+
@QtCore.Slot()
|
212
|
+
def openAboutDlg(self) -> None:
|
213
|
+
about = dialogs.AboutDialog(self)
|
214
|
+
about.exec()
|
215
|
+
|
217
216
|
|
218
217
|
class EqCheckerWindow(QtWidgets.QWidget):
|
219
|
-
def __init__(self):
|
218
|
+
def __init__(self) -> None:
|
220
219
|
super().__init__()
|
221
220
|
self.excelFile = Path()
|
222
221
|
self.ui = Ui_EquationChecker()
|
223
222
|
self.ui.setupUi(self)
|
224
|
-
self.ui.buttonRunCheck.clicked.connect(
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
223
|
+
self.ui.buttonRunCheck.clicked.connect(
|
224
|
+
lambda: self.onButRunCheck(
|
225
|
+
self.ui.catNumber.value(),
|
226
|
+
self.ui.qNumber.value(),
|
227
|
+
),
|
228
|
+
)
|
229
|
+
|
230
|
+
def onButRunCheck(self, catN: int, qN: int) -> None:
|
231
|
+
"""Is Triggered by the ``Run Check now`` Button and runs the Equation Check."""
|
231
232
|
self.ui.textResultsOutput.clear()
|
232
|
-
bullets, results, firstResult = eqVerif.equationChecker(
|
233
|
+
bullets, results, firstResult = eqVerif.equationChecker(
|
234
|
+
f"KAT_{catN}",
|
235
|
+
qN,
|
236
|
+
self.excelFile,
|
237
|
+
)
|
233
238
|
check = False
|
234
|
-
self.ui.lineFirstResult.setText(f
|
239
|
+
self.ui.lineFirstResult.setText(f"{firstResult}")
|
235
240
|
for i, calculation in enumerate(results):
|
236
|
-
if i == 0 and firstResult !=0:
|
241
|
+
if i == 0 and firstResult != 0:
|
237
242
|
check = eqVerif.checkResult(firstResult, calculation)
|
238
|
-
self.ui.lineCalculatedRes.setText(f
|
239
|
-
self.ui.textResultsOutput.append(
|
243
|
+
self.ui.lineCalculatedRes.setText(f"{calculation}")
|
244
|
+
self.ui.textResultsOutput.append(
|
245
|
+
f"Ergebnis {i + 1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n",
|
246
|
+
)
|
240
247
|
|
241
|
-
if check
|
248
|
+
if check:
|
242
249
|
self.ui.lineCheckResult.setText("[OK]")
|
243
|
-
logger.info(
|
250
|
+
logger.info(
|
251
|
+
"Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n",
|
252
|
+
)
|
244
253
|
else:
|
245
254
|
self.ui.lineCheckResult.setText("[ERROR]")
|
246
|
-
|