excel2moodle 0.3.4__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 +16 -83
- excel2moodle/core/__init__.py +1 -3
- excel2moodle/core/category.py +32 -32
- excel2moodle/core/dataStructure.py +34 -50
- excel2moodle/core/etHelpers.py +12 -17
- excel2moodle/core/exceptions.py +1 -1
- excel2moodle/core/globals.py +2 -1
- excel2moodle/core/numericMultiQ.py +11 -12
- excel2moodle/core/parser.py +121 -102
- excel2moodle/core/question.py +32 -30
- excel2moodle/core/questionValidator.py +28 -19
- excel2moodle/core/questionWriter.py +232 -139
- excel2moodle/core/stringHelpers.py +16 -23
- excel2moodle/extra/equationVerification.py +13 -27
- excel2moodle/logger.py +102 -0
- excel2moodle/ui/appUi.py +76 -91
- excel2moodle/ui/dialogs.py +40 -4
- excel2moodle/ui/settings.py +104 -54
- excel2moodle/ui/treewidget.py +13 -10
- excel2moodle/ui/windowMain.py +18 -57
- {excel2moodle-0.3.4.dist-info → excel2moodle-0.3.5.dist-info}/METADATA +1 -1
- excel2moodle-0.3.5.dist-info/RECORD +33 -0
- {excel2moodle-0.3.4.dist-info → excel2moodle-0.3.5.dist-info}/WHEEL +1 -1
- excel2moodle-0.3.4.dist-info/RECORD +0 -32
- {excel2moodle-0.3.4.dist-info → excel2moodle-0.3.5.dist-info}/entry_points.txt +0 -0
- {excel2moodle-0.3.4.dist-info → excel2moodle-0.3.5.dist-info}/licenses/LICENSE +0 -0
- {excel2moodle-0.3.4.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
|
|
@@ -40,7 +40,7 @@ from excel2moodle.core import numericMultiQ as nmq
|
|
40
40
|
|
41
41
|
|
42
42
|
def checkResult(checkerValue: float, calculation: float, tolerance=0.01) -> bool:
|
43
|
-
"""Checks if the two Arguments are within the tolerance the same value
|
43
|
+
"""Checks if the two Arguments are within the tolerance the same value.
|
44
44
|
|
45
45
|
:param checkerValue: the value the calculation is compared against
|
46
46
|
:type checkerValue: fleat
|
@@ -54,19 +54,15 @@ def checkResult(checkerValue: float, calculation: float, tolerance=0.01) -> bool
|
|
54
54
|
False if checkerValue != calculation
|
55
55
|
:rtype: bool
|
56
56
|
"""
|
57
|
-
|
58
57
|
upper = abs(checkerValue + checkerValue * tolerance)
|
59
58
|
lower = abs(checkerValue - checkerValue * tolerance)
|
60
|
-
|
61
|
-
return True
|
62
|
-
else:
|
63
|
-
return False
|
59
|
+
return bool(abs(calculation) > lower and abs(calculation) < upper)
|
64
60
|
|
65
61
|
|
66
62
|
def equationChecker(
|
67
63
|
categoryName: str, qNumber: int, spreadsheetFile
|
68
64
|
) -> tuple[list[str], list[float], float]:
|
69
|
-
"""This Function calculates all Results an invokes the checkResult function
|
65
|
+
"""This Function calculates all Results an invokes the checkResult function.
|
70
66
|
|
71
67
|
Parameters
|
72
68
|
----------
|
@@ -86,8 +82,8 @@ def equationChecker(
|
|
86
82
|
The list with the calculated results
|
87
83
|
checkerValue : float
|
88
84
|
The value taken from the ``firstResult`` field
|
89
|
-
"""
|
90
85
|
|
86
|
+
"""
|
91
87
|
spreadsheetFile.resolve()
|
92
88
|
df = pd.read_excel(spreadsheetFile, sheet_name=categoryName, index_col=0)
|
93
89
|
eq = df.loc["result"][qNumber]
|
@@ -95,7 +91,6 @@ def equationChecker(
|
|
95
91
|
try:
|
96
92
|
res = float(df.loc["firstResult"][qNumber])
|
97
93
|
except Exception:
|
98
|
-
print(f"Es ist kein 'firstResult' gegeben, kann nichts überprüfen")
|
99
94
|
res = 0
|
100
95
|
bps, calcs = nmq.parseNumericMultiQuestion(df, bps, eq, qNumber)
|
101
96
|
return bps, calcs, res
|
@@ -106,11 +101,11 @@ def main(
|
|
106
101
|
catN=None,
|
107
102
|
qNumber=None,
|
108
103
|
) -> None:
|
109
|
-
"""Takes the Spreadsheet, and asks for a category and a question number"""
|
110
|
-
if catN
|
104
|
+
"""Takes the Spreadsheet, and asks for a category and a question number."""
|
105
|
+
if catN is None:
|
111
106
|
catN = input("Geben Sie die Kategorie an: KAT_")
|
112
107
|
categoryName = f"KAT_{catN}"
|
113
|
-
if qNumber
|
108
|
+
if qNumber is None:
|
114
109
|
qNumber = int(input("Geben Sie die Fragennummer an: "))
|
115
110
|
bullets, results, firstResult = equationChecker(
|
116
111
|
categoryName, qNumber, spreadsheetFile=spreadsheetFile
|
@@ -120,23 +115,14 @@ def main(
|
|
120
115
|
for i, calculation in enumerate(results):
|
121
116
|
if i == 0 and firstResult != 0:
|
122
117
|
check = checkResult(firstResult, calculation)
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
)
|
127
|
-
|
128
|
-
if check == True:
|
129
|
-
print(
|
130
|
-
f"Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n"
|
131
|
-
)
|
118
|
+
|
119
|
+
if check:
|
120
|
+
pass
|
132
121
|
else:
|
133
|
-
|
134
|
-
f"WARNUNG: Das erste berechnete Ergebnis weicht von dem Wert {
|
135
|
-
firstResult=} ab.\n"
|
136
|
-
)
|
122
|
+
pass
|
137
123
|
|
138
124
|
|
139
125
|
if __name__ == "__main__":
|
140
|
-
spreadsheet = input(
|
126
|
+
spreadsheet = input("Geben Sie den Pfad zu dem spreadsheet an:")
|
141
127
|
while True:
|
142
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,20 +1,22 @@
|
|
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
|
-
import logging
|
7
|
+
import logging
|
8
8
|
from pathlib import Path
|
9
9
|
|
10
10
|
from PySide6 import QtCore, QtWidgets
|
11
11
|
from PySide6.QtCore import Qt
|
12
12
|
|
13
|
-
from excel2moodle import
|
13
|
+
from excel2moodle import qSignalLogger
|
14
|
+
|
15
|
+
# from excel2moodle.logger import LogWindowHandler
|
14
16
|
from excel2moodle.core.dataStructure import QuestionDB
|
15
17
|
from excel2moodle.extra import equationVerification as eqVerif
|
16
|
-
from excel2moodle.ui import dialogs
|
17
|
-
from excel2moodle.ui.settings import Settings
|
18
|
+
from excel2moodle.ui import dialogs
|
19
|
+
from excel2moodle.ui.settings import Settings, SettingsKey
|
18
20
|
from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
|
19
21
|
from excel2moodle.ui.windowMain import Ui_MoodleTestGenerator
|
20
22
|
|
@@ -36,18 +38,18 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
36
38
|
|
37
39
|
self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
38
40
|
self.ui.treeWidget.header().setSectionResizeMode(
|
39
|
-
QtWidgets.QHeaderView.ResizeToContents
|
41
|
+
QtWidgets.QHeaderView.ResizeToContents,
|
40
42
|
)
|
41
43
|
self.ui.checkBoxIncludeCategories.setChecked(
|
42
|
-
self.settings.
|
44
|
+
self.settings.get(SettingsKey.INCLUDEINCATS),
|
43
45
|
)
|
44
46
|
|
45
47
|
self.ui.retranslateUi(self)
|
46
|
-
logger.info(
|
48
|
+
logger.info("Settings are stored under: %s", self.settings.fileName())
|
47
49
|
self.ui.pointCounter.setReadOnly(True)
|
48
50
|
self.ui.questionCounter.setReadOnly(True)
|
49
51
|
self.setStatus(
|
50
|
-
"Wählen Sie bitte eine Excel Tabelle und einen Export Ordner für die Fragen aus"
|
52
|
+
"Wählen Sie bitte eine Excel Tabelle und einen Export Ordner für die Fragen aus",
|
51
53
|
)
|
52
54
|
try:
|
53
55
|
self.resize(self.settings.value("windowSize"))
|
@@ -59,78 +61,55 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
59
61
|
def connectEvents(self) -> None:
|
60
62
|
self.ui.treeWidget.itemClicked.connect(self.onSelectionChanged)
|
61
63
|
self.ui.checkBoxQuestionListSelectAll.checkStateChanged.connect(
|
62
|
-
self.toggleQuestionSelectionState
|
64
|
+
self.toggleQuestionSelectionState,
|
63
65
|
)
|
64
66
|
qSignalLogger.emitter.signal.connect(self.updateLog)
|
65
|
-
self.ui.actionEquationChecker.triggered.connect(self.
|
67
|
+
self.ui.actionEquationChecker.triggered.connect(self.openEqCheckerDlg)
|
66
68
|
self.ui.checkBoxIncludeCategories.checkStateChanged.connect(
|
67
|
-
self.setIncludeCategoriesSetting
|
69
|
+
self.setIncludeCategoriesSetting,
|
68
70
|
)
|
69
|
-
# self.ui.buttonRefresh.clicked.connect(self.refreshList)
|
70
71
|
self.ui.actionParseAll.triggered.connect(self.onParseAll)
|
71
|
-
self.testDB.dataChanged.signal.connect(self.
|
72
|
+
self.testDB.dataChanged.signal.connect(self.refreshList)
|
72
73
|
self.ui.buttonSpreadSheet.clicked.connect(self.onButSpreadsheet)
|
73
74
|
self.ui.buttonTestGen.clicked.connect(self.onButGenTest)
|
74
|
-
self.ui.actionPreviewQ.triggered.connect(self.
|
75
|
-
self.ui.actionAbout.triggered.connect(self.
|
75
|
+
self.ui.actionPreviewQ.triggered.connect(self.openPreviewQuestionDlg)
|
76
|
+
self.ui.actionAbout.triggered.connect(self.openAboutDlg)
|
76
77
|
self.settings.shPathChanged.connect(self.onSheetPathChanged)
|
78
|
+
self.ui.spinBoxDefaultQVariant.valueChanged.connect(self.setQVariantDefault)
|
79
|
+
|
80
|
+
@QtCore.Slot()
|
81
|
+
def setQVariantDefault(self, value: int) -> None:
|
82
|
+
self.settings.set(SettingsKey.QUESTIONVARIANT, value)
|
77
83
|
|
78
84
|
@QtCore.Slot(Path)
|
79
85
|
def onSheetPathChanged(self, sheet: Path) -> None:
|
80
86
|
logger.debug("Slot, new Spreadsheet triggered")
|
81
87
|
self.spreadSheetPath = sheet
|
82
88
|
self.mainPath = sheet.parent
|
89
|
+
svgFolder = self.mainPath / self.settings.get(SettingsKey.PICTURESUBFOLDER)
|
90
|
+
svgFolder.resolve()
|
91
|
+
self.settings.set(SettingsKey.PICTUREFOLDER, svgFolder)
|
83
92
|
self.ui.buttonSpreadSheet.setText(str(sheet.name))
|
93
|
+
self.testDB.readSpreadsheetData(self.spreadSheetPath)
|
94
|
+
self.testDB.parseAll()
|
95
|
+
self.refreshList()
|
84
96
|
|
85
97
|
def updateLog(self, log) -> None:
|
86
98
|
self.ui.loggerWindow.append(log)
|
87
99
|
|
88
|
-
def setIncludeCategoriesSetting(self):
|
100
|
+
def setIncludeCategoriesSetting(self) -> None:
|
89
101
|
if self.ui.checkBoxIncludeCategories.isChecked():
|
90
|
-
self.settings.
|
91
|
-
logger.debug("set includeCats to True")
|
102
|
+
self.settings.set(SettingsKey.INCLUDEINCATS, True)
|
92
103
|
else:
|
93
|
-
self.settings.
|
94
|
-
logger.debug("set includeCats to False")
|
104
|
+
self.settings.set(SettingsKey.INCLUDEINCATS, False)
|
95
105
|
|
96
|
-
|
97
|
-
def onAbout(self):
|
98
|
-
aboutMessage: str = f"""
|
99
|
-
<h1> About {e2mMetadata['name']}</h1><br>
|
100
|
-
<p style="text-align:center">
|
101
|
-
|
102
|
-
<b><a href="{e2mMetadata['homepage']}">{e2mMetadata['name']}</a> - {e2mMetadata['description']}</b>
|
103
|
-
</p>
|
104
|
-
<p style="text-align:center">
|
105
|
-
The documentation can be found under <b>
|
106
|
-
<a href="{e2mMetadata['documentation']}">{e2mMetadata['documentation']}</a></b>
|
107
|
-
</br>
|
108
|
-
</p>
|
109
|
-
<p style="text-align:center">
|
110
|
-
This project is maintained by {e2mMetadata['author']}.
|
111
|
-
<br>
|
112
|
-
Development takes place at <a href="{e2mMetadata['homepage']}"> GitLab: {e2mMetadata['homepage']}</a>
|
113
|
-
contributions are very welcome
|
114
|
-
</br>
|
115
|
-
If you encounter any issues please report them under the repositories issues page.
|
116
|
-
</br>
|
117
|
-
</p>
|
118
|
-
<p style="text-align:center">
|
119
|
-
<i>This project is published under {e2mMetadata['license']}, you are welcome, to share, modify and reuse the code.</i>
|
120
|
-
</p>
|
121
|
-
"""
|
122
|
-
QtWidgets.QMessageBox.information(
|
123
|
-
self, f"About {e2mMetadata['name']}", aboutMessage
|
124
|
-
)
|
125
|
-
|
126
|
-
def closeEvent(self, event):
|
106
|
+
def closeEvent(self, event) -> None:
|
127
107
|
self.settings.setValue("windowSize", self.size())
|
128
108
|
self.settings.setValue("windowPosition", self.pos())
|
129
109
|
|
130
110
|
@QtCore.Slot()
|
131
|
-
def onSelectionChanged(self,
|
132
|
-
"""Whenever the selection changes the total of selected points needs to be recalculated"""
|
133
|
-
|
111
|
+
def onSelectionChanged(self, **args) -> None:
|
112
|
+
"""Whenever the selection changes the total of selected points needs to be recalculated."""
|
134
113
|
count: int = 0
|
135
114
|
questions: int = 0
|
136
115
|
selection = self.ui.treeWidget.selectedItems()
|
@@ -138,17 +117,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
138
117
|
questions += 1
|
139
118
|
count += q.getQuestion().points
|
140
119
|
|
141
|
-
logger.info(
|
120
|
+
logger.info("%s questions are selected with %s points", questions, count)
|
142
121
|
self.ui.pointCounter.setValue(count)
|
143
122
|
self.ui.questionCounter.setValue(questions)
|
144
|
-
return None
|
145
123
|
|
146
124
|
@QtCore.Slot()
|
147
|
-
def toggleQuestionSelectionState(self, state):
|
148
|
-
|
149
|
-
setter = True
|
150
|
-
else:
|
151
|
-
setter = False
|
125
|
+
def toggleQuestionSelectionState(self, state) -> None:
|
126
|
+
setter = state == Qt.Checked
|
152
127
|
root = self.ui.treeWidget.invisibleRootItem()
|
153
128
|
childN = root.childCount()
|
154
129
|
for i in range(childN):
|
@@ -158,21 +133,20 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
158
133
|
|
159
134
|
@QtCore.Slot()
|
160
135
|
def onButGenTest(self) -> None:
|
136
|
+
"""Open a file Dialog so the export file may be choosen."""
|
161
137
|
path = QtWidgets.QFileDialog.getSaveFileName(
|
162
138
|
self,
|
163
139
|
"Select Output File",
|
164
|
-
dir=f"{
|
165
|
-
self.mainPath/"Testfile.xml"}",
|
140
|
+
dir=f"{self.mainPath / 'Testfile.xml'}",
|
166
141
|
filter="xml Files (*.xml)",
|
167
142
|
)
|
168
143
|
self.exportFile = Path(path[0])
|
169
|
-
logger.info(
|
144
|
+
logger.info("New Export File is set %s", self.exportFile)
|
170
145
|
selection: list[QuestionItem] = self.ui.treeWidget.selectedItems()
|
171
146
|
self.testDB.appendQuestions(selection, self.exportFile)
|
172
|
-
return None
|
173
147
|
|
174
148
|
@QtCore.Slot()
|
175
|
-
def onButSpreadsheet(self):
|
149
|
+
def onButSpreadsheet(self) -> None:
|
176
150
|
file = QtWidgets.QFileDialog.getOpenFileName(
|
177
151
|
self,
|
178
152
|
self.tr("Open Spreadsheet"),
|
@@ -184,19 +158,25 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
184
158
|
self.settings.setSpreadsheet(self.excelPath)
|
185
159
|
logger.debug(f"Saved Spreadsheet Path: {self.excelPath}\n")
|
186
160
|
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
187
|
-
return None
|
188
161
|
|
189
162
|
@QtCore.Slot()
|
190
163
|
def onParseAll(self) -> None:
|
191
|
-
"""Event triggered by the *Tools/Parse all Questions* Event
|
164
|
+
"""Event triggered by the *Tools/Parse all Questions* Event.
|
192
165
|
|
193
|
-
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.
|
194
168
|
If successful it prints out a list of all exported Questions
|
195
169
|
"""
|
196
|
-
self.
|
170
|
+
self.testDB.readSpreadsheetData(self.spreadSheetPath)
|
197
171
|
self.testDB.parseAll()
|
198
172
|
self.setStatus("[OK] Alle Fragen wurden erfolgreich in XML-Dateien umgewandelt")
|
199
|
-
|
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
|
+
"""
|
200
180
|
logger.info("starting List refresh")
|
201
181
|
cats = self.testDB.categories
|
202
182
|
self.ui.treeWidget.clear()
|
@@ -206,49 +186,54 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
206
186
|
for q in cat.questions.values():
|
207
187
|
QuestionItem(catItem, q)
|
208
188
|
self.setStatus("[OK] Fragen Liste wurde aktualisiert")
|
209
|
-
|
189
|
+
self.ui.buttonTestGen.setEnabled(True)
|
210
190
|
|
211
191
|
@QtCore.Slot()
|
212
|
-
def
|
192
|
+
def openPreviewQuestionDlg(self) -> None:
|
213
193
|
item = self.ui.treeWidget.currentItem()
|
214
194
|
if isinstance(item, QuestionItem):
|
215
195
|
dialog = dialogs.QuestinoPreviewDialog(self, item.getQuestion())
|
216
196
|
dialog.show()
|
217
197
|
else:
|
218
|
-
logger.info(
|
198
|
+
logger.info("current Item is not a Question, can't preview")
|
219
199
|
|
220
|
-
def setStatus(self, status):
|
200
|
+
def setStatus(self, status) -> None:
|
221
201
|
self.ui.statusbar.clearMessage()
|
222
202
|
self.ui.statusbar.showMessage(self.tr(status))
|
223
203
|
|
224
204
|
@QtCore.Slot()
|
225
|
-
def
|
226
|
-
logger.debug(
|
205
|
+
def openEqCheckerDlg(self) -> None:
|
206
|
+
logger.debug("opening wEquationChecker \n")
|
227
207
|
self.uiEqChecker = EqCheckerWindow()
|
228
208
|
self.uiEqChecker.excelFile = self.excelPath
|
229
209
|
self.uiEqChecker.show()
|
230
210
|
|
211
|
+
@QtCore.Slot()
|
212
|
+
def openAboutDlg(self) -> None:
|
213
|
+
about = dialogs.AboutDialog(self)
|
214
|
+
about.exec()
|
215
|
+
|
231
216
|
|
232
217
|
class EqCheckerWindow(QtWidgets.QWidget):
|
233
|
-
def __init__(self):
|
218
|
+
def __init__(self) -> None:
|
234
219
|
super().__init__()
|
235
220
|
self.excelFile = Path()
|
236
221
|
self.ui = Ui_EquationChecker()
|
237
222
|
self.ui.setupUi(self)
|
238
223
|
self.ui.buttonRunCheck.clicked.connect(
|
239
224
|
lambda: self.onButRunCheck(
|
240
|
-
self.ui.catNumber.value(),
|
241
|
-
|
225
|
+
self.ui.catNumber.value(),
|
226
|
+
self.ui.qNumber.value(),
|
227
|
+
),
|
242
228
|
)
|
243
229
|
|
244
230
|
def onButRunCheck(self, catN: int, qN: int) -> None:
|
245
|
-
"""
|
246
|
-
Is Triggered by the ``Run Check now`` Button and runs the Equation Check
|
247
|
-
"""
|
248
|
-
|
231
|
+
"""Is Triggered by the ``Run Check now`` Button and runs the Equation Check."""
|
249
232
|
self.ui.textResultsOutput.clear()
|
250
233
|
bullets, results, firstResult = eqVerif.equationChecker(
|
251
|
-
f"KAT_{catN}",
|
234
|
+
f"KAT_{catN}",
|
235
|
+
qN,
|
236
|
+
self.excelFile,
|
252
237
|
)
|
253
238
|
check = False
|
254
239
|
self.ui.lineFirstResult.setText(f"{firstResult}")
|
@@ -257,13 +242,13 @@ class EqCheckerWindow(QtWidgets.QWidget):
|
|
257
242
|
check = eqVerif.checkResult(firstResult, calculation)
|
258
243
|
self.ui.lineCalculatedRes.setText(f"{calculation}")
|
259
244
|
self.ui.textResultsOutput.append(
|
260
|
-
f"Ergebnis {i+1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n"
|
245
|
+
f"Ergebnis {i + 1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n",
|
261
246
|
)
|
262
247
|
|
263
|
-
if check
|
248
|
+
if check:
|
264
249
|
self.ui.lineCheckResult.setText("[OK]")
|
265
250
|
logger.info(
|
266
|
-
|
251
|
+
"Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n",
|
267
252
|
)
|
268
253
|
else:
|
269
254
|
self.ui.lineCheckResult.setText("[ERROR]")
|
excel2moodle/ui/dialogs.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
"""This Module hosts the various Dialog Classes, that can be shown from main Window"""
|
1
|
+
"""This Module hosts the various Dialog Classes, that can be shown from main Window."""
|
2
2
|
|
3
3
|
import lxml.etree as ET
|
4
4
|
from PySide6 import QtGui, QtWidgets
|
5
5
|
from PySide6.QtSvgWidgets import QGraphicsSvgItem
|
6
6
|
|
7
|
+
from excel2moodle import e2mMetadata
|
7
8
|
from excel2moodle.core.globals import XMLTags
|
8
9
|
from excel2moodle.core.question import Question
|
9
10
|
from excel2moodle.ui.questionPreviewDialog import Ui_QuestionPrevDialog
|
@@ -11,7 +12,7 @@ from excel2moodle.ui.variantDialog import Ui_Dialog
|
|
11
12
|
|
12
13
|
|
13
14
|
class QuestionVariantDialog(QtWidgets.QDialog):
|
14
|
-
def __init__(self, parent, question: Question):
|
15
|
+
def __init__(self, parent, question: Question) -> None:
|
15
16
|
super().__init__(parent)
|
16
17
|
self.setWindowTitle("Question Variant Dialog")
|
17
18
|
self.maxVal = question.variants
|
@@ -37,6 +38,7 @@ class QuestinoPreviewDialog(QtWidgets.QDialog):
|
|
37
38
|
self.question = question
|
38
39
|
self.ui = Ui_QuestionPrevDialog()
|
39
40
|
self.ui.setupUi(self)
|
41
|
+
self.setModal(True)
|
40
42
|
self.setWindowTitle(f"Question - {question.id} - Preview")
|
41
43
|
self.setupQuestion()
|
42
44
|
|
@@ -81,13 +83,13 @@ class QuestinoPreviewDialog(QtWidgets.QDialog):
|
|
81
83
|
for i, ans in enumerate(self.question.answerVariants):
|
82
84
|
a = ans.find("text").text
|
83
85
|
text = QtWidgets.QLineEdit(a, self)
|
84
|
-
self.ui.answersFormLayout.addRow(f"Answer {i+1}", text)
|
86
|
+
self.ui.answersFormLayout.addRow(f"Answer {i + 1}", text)
|
85
87
|
|
86
88
|
elif self.question.qtype == "NF":
|
87
89
|
ans = self.question.element.find(XMLTags.ANSWER)
|
88
90
|
a = ans.find("text").text
|
89
91
|
text = QtWidgets.QLineEdit(a, self)
|
90
|
-
self.ui.answersFormLayout.addRow(
|
92
|
+
self.ui.answersFormLayout.addRow("Result", text)
|
91
93
|
|
92
94
|
elif self.question.qtype == "MC":
|
93
95
|
for i, ans in enumerate(self.question.element.findall(XMLTags.ANSWER)):
|
@@ -95,3 +97,37 @@ class QuestinoPreviewDialog(QtWidgets.QDialog):
|
|
95
97
|
frac = ans.get("fraction")
|
96
98
|
text = QtWidgets.QLineEdit(a, self)
|
97
99
|
self.ui.answersFormLayout.addRow(f"Fraction: {frac}", text)
|
100
|
+
|
101
|
+
|
102
|
+
class AboutDialog(QtWidgets.QMessageBox):
|
103
|
+
def __init__(self, parent: QtWidgets.QWidget) -> None:
|
104
|
+
super().__init__(parent)
|
105
|
+
self.setWindowTitle(f"About {e2mMetadata['name']}")
|
106
|
+
self.setIcon(QtWidgets.QMessageBox.Information)
|
107
|
+
self.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Close)
|
108
|
+
|
109
|
+
self.aboutMessage: str = f"""
|
110
|
+
<h1> About {e2mMetadata["name"]}</h1><br>
|
111
|
+
<p style="text-align:center">
|
112
|
+
|
113
|
+
<b><a href="{e2mMetadata["homepage"]}">{e2mMetadata["name"]}</a> - {e2mMetadata["description"]}</b>
|
114
|
+
</p>
|
115
|
+
<p style="text-align:center">
|
116
|
+
The documentation can be found under <b>
|
117
|
+
<a href="{e2mMetadata["documentation"]}">{e2mMetadata["documentation"]}</a></b>
|
118
|
+
</br>
|
119
|
+
</p>
|
120
|
+
<p style="text-align:center">
|
121
|
+
This project is maintained by {e2mMetadata["author"]}.
|
122
|
+
<br>
|
123
|
+
Development takes place at <a href="{e2mMetadata["homepage"]}"> GitLab: {e2mMetadata["homepage"]}</a>
|
124
|
+
contributions are very welcome
|
125
|
+
</br>
|
126
|
+
If you encounter any issues please report them under the repositories issues page.
|
127
|
+
</br>
|
128
|
+
</p>
|
129
|
+
<p style="text-align:center">
|
130
|
+
<i>This project is published under {e2mMetadata["license"]}, you are welcome, to share, modify and reuse the code.</i>
|
131
|
+
</p>
|
132
|
+
"""
|
133
|
+
self.setText(self.aboutMessage)
|