excel2moodle 0.3.4__py3-none-any.whl → 0.3.6__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.
@@ -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
- if abs(calculation) > lower and abs(calculation) < upper:
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 == None:
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 == None:
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
- print(
124
- f"Ergebnis {
125
- i+1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n"
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
- print(
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(f"Geben Sie den Pfad zu dem spreadsheet an:")
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,101 @@
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
+ self.emitter.signal.emit(prettyMessage)
94
+
95
+
96
+ class LogAdapterQuestionID(logging.LoggerAdapter):
97
+ """Prepend the Question ID to the logging messages."""
98
+
99
+ def process(self, msg, kwargs):
100
+ """Append the Question ID to the log Message."""
101
+ return "[{}]: {}".format(self.extra["qID"], msg), kwargs
excel2moodle/ui/appUi.py CHANGED
@@ -1,20 +1,20 @@
1
- """This Module holds the extended class mainWindow() and any other main Windows
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 tho ``pyside6-uic`` command,
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 as logging
7
+ import logging
8
8
  from pathlib import Path
9
9
 
10
10
  from PySide6 import QtCore, QtWidgets
11
- from PySide6.QtCore import Qt
11
+ from PySide6.QtCore import QRunnable, Qt, QThreadPool
12
12
 
13
- from excel2moodle import e2mMetadata, qSignalLogger
13
+ from excel2moodle import qSignalLogger
14
14
  from excel2moodle.core.dataStructure import QuestionDB
15
15
  from excel2moodle.extra import equationVerification as eqVerif
16
- from excel2moodle.ui import dialogs, windowEquationChecker
17
- from excel2moodle.ui.settings import Settings
16
+ from excel2moodle.ui import dialogs
17
+ from excel2moodle.ui.settings import Settings, SettingsKey
18
18
  from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
19
19
  from excel2moodle.ui.windowMain import Ui_MoodleTestGenerator
20
20
 
@@ -33,104 +33,92 @@ class MainWindow(QtWidgets.QMainWindow):
33
33
  self.testDB = testDB
34
34
  self.ui = Ui_MoodleTestGenerator()
35
35
  self.ui.setupUi(self)
36
-
36
+ self.connectEvents()
37
+ logger.info("Settings are stored under: %s", self.settings.fileName())
37
38
  self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
38
39
  self.ui.treeWidget.header().setSectionResizeMode(
39
- QtWidgets.QHeaderView.ResizeToContents
40
+ QtWidgets.QHeaderView.ResizeToContents,
40
41
  )
41
42
  self.ui.checkBoxIncludeCategories.setChecked(
42
- self.settings.value("testGen/includeCats", type=bool)
43
+ self.settings.get(SettingsKey.INCLUDEINCATS),
44
+ )
45
+ self.ui.spinBoxDefaultQVariant.setValue(
46
+ self.settings.get(SettingsKey.QUESTIONVARIANT)
43
47
  )
44
-
45
- self.ui.retranslateUi(self)
46
- logger.info(f"Settings are stored under: {self.settings.fileName()}")
47
48
  self.ui.pointCounter.setReadOnly(True)
48
49
  self.ui.questionCounter.setReadOnly(True)
49
50
  self.setStatus(
50
- "Wählen Sie bitte eine Excel Tabelle und einen Export Ordner für die Fragen aus"
51
+ "Wählen Sie eine Excel Tabelle mit den Fragen aus",
51
52
  )
52
53
  try:
53
54
  self.resize(self.settings.value("windowSize"))
54
55
  self.move(self.settings.value("windowPosition"))
55
56
  except Exception:
56
57
  pass
57
- self.connectEvents()
58
+ self.threadPool = QThreadPool()
58
59
 
59
60
  def connectEvents(self) -> None:
60
61
  self.ui.treeWidget.itemClicked.connect(self.onSelectionChanged)
61
62
  self.ui.checkBoxQuestionListSelectAll.checkStateChanged.connect(
62
- self.toggleQuestionSelectionState
63
+ self.toggleQuestionSelectionState,
63
64
  )
64
65
  qSignalLogger.emitter.signal.connect(self.updateLog)
65
- self.ui.actionEquationChecker.triggered.connect(self.onButOpenEqChecker)
66
+ self.ui.actionEquationChecker.triggered.connect(self.openEqCheckerDlg)
66
67
  self.ui.checkBoxIncludeCategories.checkStateChanged.connect(
67
- self.setIncludeCategoriesSetting
68
+ self.setIncludeCategoriesSetting,
68
69
  )
69
- # self.ui.buttonRefresh.clicked.connect(self.refreshList)
70
70
  self.ui.actionParseAll.triggered.connect(self.onParseAll)
71
- self.testDB.dataChanged.signal.connect(self.onParseAll)
71
+ # self.testDB.dataChanged.signal.connect(self.refreshList)
72
72
  self.ui.buttonSpreadSheet.clicked.connect(self.onButSpreadsheet)
73
73
  self.ui.buttonTestGen.clicked.connect(self.onButGenTest)
74
- self.ui.actionPreviewQ.triggered.connect(self.previewQ)
75
- self.ui.actionAbout.triggered.connect(self.onAbout)
74
+ self.ui.actionPreviewQ.triggered.connect(self.openPreviewQuestionDlg)
75
+ self.ui.actionAbout.triggered.connect(self.openAboutDlg)
76
76
  self.settings.shPathChanged.connect(self.onSheetPathChanged)
77
+ self.ui.spinBoxDefaultQVariant.valueChanged.connect(self.setQVariantDefault)
78
+
79
+ @QtCore.Slot()
80
+ def setQVariantDefault(self, value: int) -> None:
81
+ self.settings.set(SettingsKey.QUESTIONVARIANT, value)
82
+
83
+ @QtCore.Slot()
84
+ def onParseAll(self) -> None:
85
+ """Event triggered by the *Tools/Parse all Questions* Event.
86
+
87
+ It parses all the Questions found in the spreadsheet
88
+ and then refreshes the list of questions.
89
+ If successful it prints out a list of all exported Questions
90
+ """
91
+ self.ui.treeWidget.clear()
92
+ process = ParseSpreadsheetThread(self.testDB, self)
93
+ self.threadPool.start(process)
77
94
 
78
95
  @QtCore.Slot(Path)
79
96
  def onSheetPathChanged(self, sheet: Path) -> None:
80
97
  logger.debug("Slot, new Spreadsheet triggered")
81
98
  self.spreadSheetPath = sheet
82
99
  self.mainPath = sheet.parent
100
+ svgFolder = self.mainPath / self.settings.get(SettingsKey.PICTURESUBFOLDER)
101
+ svgFolder.resolve()
102
+ self.settings.set(SettingsKey.PICTUREFOLDER, svgFolder)
83
103
  self.ui.buttonSpreadSheet.setText(str(sheet.name))
104
+ self.onParseAll()
84
105
 
85
106
  def updateLog(self, log) -> None:
86
107
  self.ui.loggerWindow.append(log)
87
108
 
88
- def setIncludeCategoriesSetting(self):
109
+ def setIncludeCategoriesSetting(self) -> None:
89
110
  if self.ui.checkBoxIncludeCategories.isChecked():
90
- self.settings.testgenSet("includeCats", True)
91
- logger.debug("set includeCats to True")
111
+ self.settings.set(SettingsKey.INCLUDEINCATS, True)
92
112
  else:
93
- self.settings.testgenSet("includeCats", False)
94
- logger.debug("set includeCats to False")
113
+ self.settings.set(SettingsKey.INCLUDEINCATS, False)
95
114
 
96
- @QtCore.Slot()
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):
115
+ def closeEvent(self, event) -> None:
127
116
  self.settings.setValue("windowSize", self.size())
128
117
  self.settings.setValue("windowPosition", self.pos())
129
118
 
130
119
  @QtCore.Slot()
131
- def onSelectionChanged(self, item, col):
132
- """Whenever the selection changes the total of selected points needs to be recalculated"""
133
-
120
+ def onSelectionChanged(self, **args) -> None:
121
+ """Whenever the selection changes the total of selected points needs to be recalculated."""
134
122
  count: int = 0
135
123
  questions: int = 0
136
124
  selection = self.ui.treeWidget.selectedItems()
@@ -138,17 +126,13 @@ class MainWindow(QtWidgets.QMainWindow):
138
126
  questions += 1
139
127
  count += q.getQuestion().points
140
128
 
141
- logger.info(f"{questions} questions are selected with {count} points")
129
+ logger.info("%s questions are selected with %s points", questions, count)
142
130
  self.ui.pointCounter.setValue(count)
143
131
  self.ui.questionCounter.setValue(questions)
144
- return None
145
132
 
146
133
  @QtCore.Slot()
147
- def toggleQuestionSelectionState(self, state):
148
- if state == Qt.Checked:
149
- setter = True
150
- else:
151
- setter = False
134
+ def toggleQuestionSelectionState(self, state) -> None:
135
+ setter = state == Qt.Checked
152
136
  root = self.ui.treeWidget.invisibleRootItem()
153
137
  childN = root.childCount()
154
138
  for i in range(childN):
@@ -158,21 +142,20 @@ class MainWindow(QtWidgets.QMainWindow):
158
142
 
159
143
  @QtCore.Slot()
160
144
  def onButGenTest(self) -> None:
145
+ """Open a file Dialog so the export file may be choosen."""
161
146
  path = QtWidgets.QFileDialog.getSaveFileName(
162
147
  self,
163
148
  "Select Output File",
164
- dir=f"{
165
- self.mainPath/"Testfile.xml"}",
149
+ dir=f"{self.mainPath / 'Testfile.xml'}",
166
150
  filter="xml Files (*.xml)",
167
151
  )
168
152
  self.exportFile = Path(path[0])
169
- logger.info(f"New Export File is set{self.exportFile=}")
153
+ logger.info("New Export File is set %s", self.exportFile)
170
154
  selection: list[QuestionItem] = self.ui.treeWidget.selectedItems()
171
155
  self.testDB.appendQuestions(selection, self.exportFile)
172
- return None
173
156
 
174
157
  @QtCore.Slot()
175
- def onButSpreadsheet(self):
158
+ def onButSpreadsheet(self) -> None:
176
159
  file = QtWidgets.QFileDialog.getOpenFileName(
177
160
  self,
178
161
  self.tr("Open Spreadsheet"),
@@ -182,21 +165,13 @@ class MainWindow(QtWidgets.QMainWindow):
182
165
  )
183
166
  self.excelPath = Path(file[0]).resolve()
184
167
  self.settings.setSpreadsheet(self.excelPath)
185
- logger.debug(f"Saved Spreadsheet Path: {self.excelPath}\n")
186
168
  self.setStatus("[OK] Excel Tabelle wurde eingelesen")
187
- return None
188
169
 
189
- @QtCore.Slot()
190
- def onParseAll(self) -> None:
191
- """Event triggered by the *Tools/Parse all Questions* Event
170
+ def refreshList(self) -> None:
171
+ """Refresh the question overview in the main window.
192
172
 
193
- It parses all the Questions found in the spreadsheet and then refreshes the list of questions.
194
- If successful it prints out a list of all exported Questions
173
+ Enable the export Button afterwards.
195
174
  """
196
- self.ui.buttonTestGen.setEnabled(True)
197
- self.testDB.parseAll()
198
- self.setStatus("[OK] Alle Fragen wurden erfolgreich in XML-Dateien umgewandelt")
199
- # below is former refres method
200
175
  logger.info("starting List refresh")
201
176
  cats = self.testDB.categories
202
177
  self.ui.treeWidget.clear()
@@ -206,49 +181,69 @@ class MainWindow(QtWidgets.QMainWindow):
206
181
  for q in cat.questions.values():
207
182
  QuestionItem(catItem, q)
208
183
  self.setStatus("[OK] Fragen Liste wurde aktualisiert")
209
- return None
184
+ self.ui.buttonTestGen.setEnabled(True)
210
185
 
211
186
  @QtCore.Slot()
212
- def previewQ(self) -> None:
187
+ def openPreviewQuestionDlg(self) -> None:
213
188
  item = self.ui.treeWidget.currentItem()
214
189
  if isinstance(item, QuestionItem):
215
190
  dialog = dialogs.QuestinoPreviewDialog(self, item.getQuestion())
216
191
  dialog.show()
217
192
  else:
218
- logger.info(f"current Item is not a Question, can't preview")
193
+ logger.info("current Item is not a Question, can't preview")
219
194
 
220
- def setStatus(self, status):
195
+ def setStatus(self, status) -> None:
221
196
  self.ui.statusbar.clearMessage()
222
197
  self.ui.statusbar.showMessage(self.tr(status))
223
198
 
224
199
  @QtCore.Slot()
225
- def onButOpenEqChecker(self):
226
- logger.debug(f"opening wEquationChecker \n")
200
+ def openEqCheckerDlg(self) -> None:
201
+ logger.debug("opening wEquationChecker \n")
227
202
  self.uiEqChecker = EqCheckerWindow()
228
203
  self.uiEqChecker.excelFile = self.excelPath
229
204
  self.uiEqChecker.show()
230
205
 
206
+ @QtCore.Slot()
207
+ def openAboutDlg(self) -> None:
208
+ about = dialogs.AboutDialog(self)
209
+ about.exec()
210
+
211
+
212
+ class ParseSpreadsheetThread(QRunnable):
213
+ def __init__(self, questionDB: QuestionDB, mainApp: MainWindow) -> None:
214
+ super().__init__()
215
+ self.testDB = questionDB
216
+ self.mainApp = mainApp
217
+
218
+ @QtCore.Slot()
219
+ def run(self) -> None:
220
+ self.testDB.readSpreadsheetData(self.mainApp.spreadSheetPath)
221
+ self.mainApp.setStatus("[OK] Tabellen wurde eingelesen")
222
+ self.testDB.parseAll()
223
+ self.mainApp.setStatus("[OK] Alle Fragen wurden erfolgreich geparsed")
224
+ self.mainApp.refreshList()
225
+
231
226
 
232
227
  class EqCheckerWindow(QtWidgets.QWidget):
233
- def __init__(self):
228
+ def __init__(self) -> None:
234
229
  super().__init__()
235
230
  self.excelFile = Path()
236
231
  self.ui = Ui_EquationChecker()
237
232
  self.ui.setupUi(self)
238
233
  self.ui.buttonRunCheck.clicked.connect(
239
234
  lambda: self.onButRunCheck(
240
- self.ui.catNumber.value(), self.ui.qNumber.value()
241
- )
235
+ self.ui.catNumber.value(),
236
+ self.ui.qNumber.value(),
237
+ ),
242
238
  )
243
239
 
244
240
  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
-
241
+ """Is Triggered by the ``Run Check now`` Button and runs the Equation Check."""
249
242
  self.ui.textResultsOutput.clear()
250
243
  bullets, results, firstResult = eqVerif.equationChecker(
251
- f"KAT_{catN}", qN, self.excelFile
244
+ f"KAT_{catN}",
245
+ qN,
246
+ self.excelFile,
252
247
  )
253
248
  check = False
254
249
  self.ui.lineFirstResult.setText(f"{firstResult}")
@@ -257,13 +252,13 @@ class EqCheckerWindow(QtWidgets.QWidget):
257
252
  check = eqVerif.checkResult(firstResult, calculation)
258
253
  self.ui.lineCalculatedRes.setText(f"{calculation}")
259
254
  self.ui.textResultsOutput.append(
260
- f"Ergebnis {i+1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n"
255
+ f"Ergebnis {i + 1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n",
261
256
  )
262
257
 
263
- if check == True:
258
+ if check:
264
259
  self.ui.lineCheckResult.setText("[OK]")
265
260
  logger.info(
266
- f"Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n"
261
+ "Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n",
267
262
  )
268
263
  else:
269
264
  self.ui.lineCheckResult.setText("[ERROR]")
@@ -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(f"Result", text)
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)