excel2moodle 0.4.1__py3-none-any.whl → 0.4.3__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 +0 -7
- excel2moodle/__main__.py +2 -2
- excel2moodle/core/__init__.py +0 -10
- excel2moodle/core/category.py +4 -3
- excel2moodle/core/dataStructure.py +116 -61
- excel2moodle/core/etHelpers.py +2 -2
- excel2moodle/core/exceptions.py +2 -2
- excel2moodle/core/globals.py +10 -27
- excel2moodle/core/parser.py +24 -30
- excel2moodle/core/question.py +147 -63
- excel2moodle/core/settings.py +107 -111
- excel2moodle/core/validator.py +36 -55
- excel2moodle/logger.py +7 -4
- excel2moodle/question_types/__init__.py +2 -0
- excel2moodle/question_types/cloze.py +207 -0
- excel2moodle/question_types/mc.py +26 -16
- excel2moodle/question_types/nf.py +17 -3
- excel2moodle/question_types/nfm.py +60 -17
- excel2moodle/ui/{windowEquationChecker.py → UI_equationChecker.py} +98 -78
- excel2moodle/ui/{exportSettingsDialog.py → UI_exportSettingsDialog.py} +55 -4
- excel2moodle/ui/{windowMain.py → UI_mainWindow.py} +32 -39
- excel2moodle/ui/appUi.py +66 -86
- excel2moodle/ui/dialogs.py +40 -2
- excel2moodle/ui/equationChecker.py +70 -0
- excel2moodle/ui/treewidget.py +4 -4
- {excel2moodle-0.4.1.dist-info → excel2moodle-0.4.3.dist-info}/METADATA +2 -3
- excel2moodle-0.4.3.dist-info/RECORD +38 -0
- {excel2moodle-0.4.1.dist-info → excel2moodle-0.4.3.dist-info}/entry_points.txt +0 -3
- excel2moodle/ui/questionPreviewDialog.py +0 -115
- excel2moodle-0.4.1.dist-info/RECORD +0 -37
- /excel2moodle/ui/{variantDialog.py → UI_variantDialog.py} +0 -0
- {excel2moodle-0.4.1.dist-info → excel2moodle-0.4.3.dist-info}/WHEEL +0 -0
- {excel2moodle-0.4.1.dist-info → excel2moodle-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {excel2moodle-0.4.1.dist-info → excel2moodle-0.4.3.dist-info}/top_level.txt +0 -0
excel2moodle/ui/appUi.py
CHANGED
@@ -8,20 +8,20 @@ import logging
|
|
8
8
|
from pathlib import Path
|
9
9
|
|
10
10
|
from PySide6 import QtCore, QtWidgets
|
11
|
-
from PySide6.QtCore import QRunnable, Qt, QThreadPool
|
11
|
+
from PySide6.QtCore import QRunnable, QSettings, Qt, QThreadPool
|
12
12
|
|
13
13
|
from excel2moodle import mainLogger
|
14
14
|
from excel2moodle.core.category import Category
|
15
15
|
from excel2moodle.core.dataStructure import QuestionDB
|
16
|
-
from excel2moodle.core.settings import Settings,
|
17
|
-
from excel2moodle.extra import equationVerification as eqVerif
|
16
|
+
from excel2moodle.core.settings import Settings, Tags
|
18
17
|
from excel2moodle.logger import LogWindowHandler
|
18
|
+
from excel2moodle.question_types.mc import MCQuestion
|
19
|
+
from excel2moodle.question_types.nf import NFQuestion
|
19
20
|
from excel2moodle.ui import dialogs
|
21
|
+
from excel2moodle.ui.equationChecker import EqCheckerWindow
|
20
22
|
from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
|
23
|
+
from excel2moodle.ui.UI_mainWindow import Ui_MoodleTestGenerator
|
21
24
|
from excel2moodle.ui.windowDoc import DocumentationWindow
|
22
|
-
from excel2moodle.ui.windowMain import Ui_MoodleTestGenerator
|
23
|
-
|
24
|
-
from .windowEquationChecker import Ui_EquationChecker
|
25
25
|
|
26
26
|
logger = logging.getLogger(__name__)
|
27
27
|
|
@@ -33,6 +33,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
33
33
|
def __init__(self, settings: Settings, testDB: QuestionDB) -> None:
|
34
34
|
super().__init__()
|
35
35
|
self.settings = settings
|
36
|
+
self.qSettings = QSettings("jbosse3", "excel2moodle")
|
37
|
+
logger.info("Settings are stored under: %s", self.qSettings.fileName())
|
38
|
+
|
36
39
|
self.excelPath: Path | None = None
|
37
40
|
self.mainPath = self.excelPath.parent if self.excelPath is not None else None
|
38
41
|
self.exportFile = Path()
|
@@ -41,17 +44,18 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
41
44
|
self.ui.setupUi(self)
|
42
45
|
self.exportDialog = dialogs.ExportDialog(self)
|
43
46
|
self.questionPreview = dialogs.QuestionPreview(self)
|
47
|
+
self.eqChecker = EqCheckerWindow()
|
44
48
|
self.connectEvents()
|
45
|
-
logger.info("Settings are stored under: %s", self.
|
49
|
+
logger.info("Settings are stored under: %s", self.qSettings.fileName())
|
46
50
|
self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
47
51
|
self.ui.treeWidget.header().setSectionResizeMode(
|
48
52
|
QtWidgets.QHeaderView.ResizeToContents,
|
49
53
|
)
|
50
54
|
self.exportDialog.ui.checkBoxIncludeCategories.setChecked(
|
51
|
-
self.
|
55
|
+
self.qSettings.value(Tags.INCLUDEINCATS, defaultValue=True, type=bool)
|
52
56
|
)
|
53
57
|
self.exportDialog.ui.spinBoxDefaultQVariant.setValue(
|
54
|
-
self.
|
58
|
+
self.qSettings.value(Tags.QUESTIONVARIANT, defaultValue=1, type=int)
|
55
59
|
)
|
56
60
|
self.ui.pointCounter.setReadOnly(True)
|
57
61
|
self.ui.questionCounter.setReadOnly(True)
|
@@ -59,11 +63,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
59
63
|
"Wählen Sie eine Excel Tabelle mit den Fragen aus",
|
60
64
|
)
|
61
65
|
try:
|
62
|
-
self.resize(self.
|
63
|
-
self.move(self.
|
66
|
+
self.resize(self.qSettings.value("windowSize"))
|
67
|
+
self.move(self.qSettings.value("windowPosition"))
|
64
68
|
except Exception:
|
65
69
|
pass
|
66
70
|
self.threadPool = QThreadPool()
|
71
|
+
if self.qSettings.contains(Tags.SPREADSHEETPATH.full):
|
72
|
+
sheet = self.qSettings.value(Tags.SPREADSHEETPATH.full)
|
73
|
+
self.setSheetPath(sheet)
|
67
74
|
|
68
75
|
def connectEvents(self) -> None:
|
69
76
|
self.ui.treeWidget.itemSelectionChanged.connect(self.onSelectionChanged)
|
@@ -84,14 +91,13 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
84
91
|
self.ui.treeWidget.itemClicked.connect(self.updateQuestionPreview)
|
85
92
|
self.ui.actionAbout.triggered.connect(self.openAboutDlg)
|
86
93
|
self.ui.actionDocumentation.triggered.connect(self.openDocumentation)
|
87
|
-
self.settings.shPathChanged.connect(self.onSheetPathChanged)
|
88
94
|
self.exportDialog.ui.spinBoxDefaultQVariant.valueChanged.connect(
|
89
95
|
self.setQVariantDefault
|
90
96
|
)
|
91
97
|
|
92
98
|
@QtCore.Slot()
|
93
99
|
def setQVariantDefault(self, value: int) -> None:
|
94
|
-
self.settings.set(
|
100
|
+
self.settings.set(Tags.QUESTIONVARIANT, value)
|
95
101
|
|
96
102
|
@QtCore.Slot()
|
97
103
|
def parseSpreadsheetAll(self) -> None:
|
@@ -102,32 +108,44 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
102
108
|
If successful it prints out a list of all exported Questions
|
103
109
|
"""
|
104
110
|
self.ui.treeWidget.clear()
|
111
|
+
self.testDB.readCategoriesMetadata()
|
105
112
|
process = ParseAllThread(self.testDB, self)
|
106
113
|
self.threadPool.start(process)
|
107
114
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
115
|
+
def setSheetPath(self, sheet: Path) -> None:
|
116
|
+
logger.debug("Received new spreadsheet.")
|
117
|
+
if not sheet.is_file():
|
118
|
+
logger.warning("Sheet is not a file")
|
119
|
+
self.setStatus("[ERROR] keine Tabelle angegeben")
|
120
|
+
return
|
121
|
+
self.excelPath = sheet
|
112
122
|
self.mainPath = sheet.parent
|
113
|
-
svgFolder = self.mainPath / self.settings.get(SettingsKey.PICTURESUBFOLDER)
|
114
|
-
svgFolder.resolve()
|
115
|
-
self.settings.set(SettingsKey.PICTUREFOLDER, svgFolder)
|
116
123
|
self.ui.buttonSpreadsheet.setText(f"../{sheet.name}")
|
124
|
+
self.testDB.spreadsheet = sheet
|
125
|
+
self.qSettings.setValue(Tags.SPREADSHEETPATH.full, sheet)
|
117
126
|
self.parseSpreadsheetAll()
|
127
|
+
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
118
128
|
|
119
129
|
def updateLog(self, log) -> None:
|
120
130
|
self.ui.loggerWindow.append(log)
|
121
131
|
|
122
132
|
def setIncludeCategoriesSetting(self) -> None:
|
123
133
|
if self.exportDialog.ui.checkBoxIncludeCategories.isChecked():
|
124
|
-
self.settings.set(
|
134
|
+
self.settings.set(Tags.INCLUDEINCATS, True)
|
125
135
|
else:
|
126
|
-
self.settings.set(
|
136
|
+
self.settings.set(Tags.INCLUDEINCATS, False)
|
127
137
|
|
128
138
|
def closeEvent(self, event) -> None:
|
129
|
-
|
130
|
-
self.
|
139
|
+
logger.info("Closing. Saving window stats.")
|
140
|
+
self.qSettings.setValue("windowSize", self.size())
|
141
|
+
self.qSettings.setValue("windowPosition", self.pos())
|
142
|
+
self.qSettings.setValue(
|
143
|
+
Tags.INCLUDEINCATS, self.settings.get(Tags.INCLUDEINCATS)
|
144
|
+
)
|
145
|
+
self.qSettings.setValue(
|
146
|
+
Tags.QUESTIONVARIANT,
|
147
|
+
self.settings.get(Tags.QUESTIONVARIANT),
|
148
|
+
)
|
131
149
|
|
132
150
|
@QtCore.Slot()
|
133
151
|
def onSelectionChanged(self, **args) -> None:
|
@@ -140,6 +158,8 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
140
158
|
count += q.getQuestion().points
|
141
159
|
self.ui.pointCounter.setValue(count)
|
142
160
|
self.ui.questionCounter.setValue(questions)
|
161
|
+
if self.eqChecker.isVisible():
|
162
|
+
self.openEqCheckerDlg()
|
143
163
|
|
144
164
|
@QtCore.Slot()
|
145
165
|
def toggleQuestionSelectionState(self, state) -> None:
|
@@ -154,17 +174,16 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
154
174
|
@QtCore.Slot()
|
155
175
|
def onButGenTest(self) -> None:
|
156
176
|
"""Open a file Dialog so the export file may be choosen."""
|
157
|
-
self.exportDialog.exec()
|
158
|
-
path = QtWidgets.QFileDialog.getSaveFileName(
|
159
|
-
self,
|
160
|
-
"Select Output File",
|
161
|
-
dir=f"{self.mainPath / 'Testfile.xml'}",
|
162
|
-
filter="xml Files (*.xml)",
|
163
|
-
)
|
164
|
-
self.exportFile = Path(path[0])
|
165
|
-
logger.info("New Export File is set %s", self.exportFile)
|
166
177
|
selection: list[QuestionItem] = self.ui.treeWidget.selectedItems()
|
167
|
-
self.
|
178
|
+
self.exportDialog.exportFile = Path(self.mainPath / "TestFile.xml")
|
179
|
+
self.exportDialog.ui.questionCount.setValue(self.ui.questionCounter.value())
|
180
|
+
self.exportDialog.ui.pointCount.setValue(self.ui.pointCounter.value())
|
181
|
+
if self.exportDialog.exec():
|
182
|
+
self.exportFile = self.exportDialog.exportFile
|
183
|
+
logger.info("New Export File is set %s", self.exportFile)
|
184
|
+
self.testDB.appendQuestions(selection, self.exportFile)
|
185
|
+
else:
|
186
|
+
logger.info("Aborting Export")
|
168
187
|
|
169
188
|
@QtCore.Slot()
|
170
189
|
def actionSpreadsheet(self) -> None:
|
@@ -176,12 +195,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
176
195
|
selectedFilter=("*.ods"),
|
177
196
|
)
|
178
197
|
path = Path(file[0]).resolve(strict=True)
|
179
|
-
|
180
|
-
self.excelPath = path
|
181
|
-
self.settings.setSpreadsheet(self.excelPath)
|
182
|
-
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
183
|
-
else:
|
184
|
-
self.setStatus("[ERROR] keine Tabelle angegeben")
|
198
|
+
self.setSheetPath(path)
|
185
199
|
|
186
200
|
@QtCore.Slot(Category)
|
187
201
|
def treeRefreshCategory(self, cat: Category) -> None:
|
@@ -206,10 +220,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
206
220
|
|
207
221
|
@QtCore.Slot()
|
208
222
|
def openEqCheckerDlg(self) -> None:
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
223
|
+
item = self.ui.treeWidget.currentItem()
|
224
|
+
if isinstance(item, QuestionItem):
|
225
|
+
question = item.getQuestion()
|
226
|
+
if isinstance(question, (NFQuestion, MCQuestion)):
|
227
|
+
logger.debug("Can't check an MC or NF Question")
|
228
|
+
else:
|
229
|
+
logger.debug("opening wEquationChecker \n")
|
230
|
+
self.eqChecker.setup(item.getQuestion())
|
231
|
+
self.eqChecker.show()
|
232
|
+
else:
|
233
|
+
logger.debug("No Question Item selected: %s", type(item))
|
213
234
|
|
214
235
|
@QtCore.Slot()
|
215
236
|
def openAboutDlg(self) -> None:
|
@@ -238,47 +259,6 @@ class ParseAllThread(QRunnable):
|
|
238
259
|
|
239
260
|
@QtCore.Slot()
|
240
261
|
def run(self) -> None:
|
241
|
-
self.testDB.
|
242
|
-
self.testDB.asyncInitAllCategories(self.mainApp.spreadSheetPath)
|
262
|
+
self.testDB.asyncInitAllCategories(self.mainApp.excelPath)
|
243
263
|
self.mainApp.setStatus("[OK] Tabellen wurde eingelesen")
|
244
264
|
self.testDB.parseAllQuestions()
|
245
|
-
|
246
|
-
|
247
|
-
class EqCheckerWindow(QtWidgets.QWidget):
|
248
|
-
def __init__(self) -> None:
|
249
|
-
super().__init__()
|
250
|
-
self.excelFile = Path()
|
251
|
-
self.ui = Ui_EquationChecker()
|
252
|
-
self.ui.setupUi(self)
|
253
|
-
self.ui.buttonRunCheck.clicked.connect(
|
254
|
-
lambda: self.onButRunCheck(
|
255
|
-
self.ui.catNumber.value(),
|
256
|
-
self.ui.qNumber.value(),
|
257
|
-
),
|
258
|
-
)
|
259
|
-
|
260
|
-
def onButRunCheck(self, catN: int, qN: int) -> None:
|
261
|
-
"""Is Triggered by the ``Run Check now`` Button and runs the Equation Check."""
|
262
|
-
self.ui.textResultsOutput.clear()
|
263
|
-
bullets, results, firstResult = eqVerif.equationChecker(
|
264
|
-
f"KAT_{catN}",
|
265
|
-
qN,
|
266
|
-
self.excelFile,
|
267
|
-
)
|
268
|
-
check = False
|
269
|
-
self.ui.lineFirstResult.setText(f"{firstResult}")
|
270
|
-
for i, calculation in enumerate(results):
|
271
|
-
if i == 0 and firstResult != 0:
|
272
|
-
check = eqVerif.checkResult(firstResult, calculation)
|
273
|
-
self.ui.lineCalculatedRes.setText(f"{calculation}")
|
274
|
-
self.ui.textResultsOutput.append(
|
275
|
-
f"Ergebnis {i + 1}: \t{calculation}\n\tMit den Werten: \n{bullets[i]}\n",
|
276
|
-
)
|
277
|
-
|
278
|
-
if check:
|
279
|
-
self.ui.lineCheckResult.setText("[OK]")
|
280
|
-
logger.info(
|
281
|
-
"Das erste berechnete Ergebnis stimmt mit dem Wert in 'firstResult' überein\n",
|
282
|
-
)
|
283
|
-
else:
|
284
|
-
self.ui.lineCheckResult.setText("[ERROR]")
|
excel2moodle/ui/dialogs.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
"""This Module hosts the various Dialog Classes, that can be shown from main Window."""
|
2
2
|
|
3
|
+
import logging
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
3
7
|
import lxml.etree as ET
|
4
8
|
from PySide6 import QtGui, QtWidgets
|
5
9
|
from PySide6.QtSvgWidgets import QGraphicsSvgItem
|
@@ -7,8 +11,13 @@ from PySide6.QtSvgWidgets import QGraphicsSvgItem
|
|
7
11
|
from excel2moodle import e2mMetadata
|
8
12
|
from excel2moodle.core.globals import XMLTags
|
9
13
|
from excel2moodle.core.question import Question
|
10
|
-
from excel2moodle.ui.
|
11
|
-
from excel2moodle.ui.
|
14
|
+
from excel2moodle.ui.UI_exportSettingsDialog import Ui_ExportDialog
|
15
|
+
from excel2moodle.ui.UI_variantDialog import Ui_Dialog
|
16
|
+
|
17
|
+
if TYPE_CHECKING:
|
18
|
+
from excel2moodle.ui.appUi import MainWindow
|
19
|
+
|
20
|
+
logger = logging.getLogger(__name__)
|
12
21
|
|
13
22
|
|
14
23
|
class QuestionVariantDialog(QtWidgets.QDialog):
|
@@ -36,8 +45,37 @@ class ExportDialog(QtWidgets.QDialog):
|
|
36
45
|
def __init__(self, parent) -> None:
|
37
46
|
super().__init__(parent)
|
38
47
|
self.setWindowTitle("Export question Selection")
|
48
|
+
self.appUi: MainWindow = parent
|
39
49
|
self.ui = Ui_ExportDialog()
|
40
50
|
self.ui.setupUi(self)
|
51
|
+
self.ui.btnExportFile.clicked.connect(self.getExportFile)
|
52
|
+
|
53
|
+
@property
|
54
|
+
def exportFile(self) -> Path:
|
55
|
+
return self._exportFile
|
56
|
+
|
57
|
+
@exportFile.setter
|
58
|
+
def exportFile(self, value: Path) -> None:
|
59
|
+
self._exportFile = value
|
60
|
+
self.ui.btnExportFile.setText(
|
61
|
+
f"../{(self.exportFile.parent.name)}/{self.exportFile.name}"
|
62
|
+
)
|
63
|
+
|
64
|
+
def getExportFile(self) -> None:
|
65
|
+
path = QtWidgets.QFileDialog.getSaveFileName(
|
66
|
+
self,
|
67
|
+
"Select Output File",
|
68
|
+
dir=str(self.exportFile),
|
69
|
+
filter="xml Files (*.xml)",
|
70
|
+
)
|
71
|
+
path = Path(path[0])
|
72
|
+
if path.is_file():
|
73
|
+
self.exportFile = path
|
74
|
+
self.ui.btnExportFile.setText(
|
75
|
+
f"../{(self.exportFile.parent.name)}/{self.exportFile.name}"
|
76
|
+
)
|
77
|
+
else:
|
78
|
+
logger.warning("No Export File selected")
|
41
79
|
|
42
80
|
|
43
81
|
class QuestionPreview:
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import logging
|
2
|
+
import math
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
from PySide6 import QtWidgets
|
6
|
+
|
7
|
+
from excel2moodle import mainLogger
|
8
|
+
from excel2moodle.core.question import ParametricQuestion
|
9
|
+
from excel2moodle.core.settings import Tags
|
10
|
+
from excel2moodle.logger import LogWindowHandler
|
11
|
+
from excel2moodle.question_types.nfm import NFMQuestionParser
|
12
|
+
|
13
|
+
from .UI_equationChecker import Ui_EquationChecker
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
loggerSignal = LogWindowHandler()
|
18
|
+
mainLogger.addHandler(loggerSignal)
|
19
|
+
|
20
|
+
|
21
|
+
class EqCheckerWindow(QtWidgets.QWidget):
|
22
|
+
def __init__(self) -> None:
|
23
|
+
super().__init__()
|
24
|
+
self.excelFile = Path()
|
25
|
+
self.ui = Ui_EquationChecker()
|
26
|
+
self.ui.setupUi(self)
|
27
|
+
self.ui.buttonRunCheck.clicked.connect(
|
28
|
+
lambda: self.updateCalculation(),
|
29
|
+
)
|
30
|
+
self.question: ParametricQuestion
|
31
|
+
|
32
|
+
def updateCalculation(self) -> None:
|
33
|
+
equation = self.ui.equationText.toPlainText()
|
34
|
+
results: list[float] = []
|
35
|
+
firstResult = self.question.rawData.get(Tags.FIRSTRESULT)
|
36
|
+
for i in range(self.question.variants):
|
37
|
+
NFMQuestionParser.setupAstIntprt(self.question.variables, i)
|
38
|
+
results.append(float(NFMQuestionParser.astEval(equation)))
|
39
|
+
check: bool = False
|
40
|
+
self.ui.textResultsOutput.insertHtml(f"<hr><br><h2>{equation:^30}</h2><br>")
|
41
|
+
for i, calculation in enumerate(results):
|
42
|
+
if i == 0 and firstResult != 0:
|
43
|
+
check = bool(math.isclose(calculation, firstResult, rel_tol=0.01))
|
44
|
+
self.ui.lineCalculatedRes.setText(f"{calculation}")
|
45
|
+
self.ui.textResultsOutput.append(f"<h3>Result {check = }</h3><br>")
|
46
|
+
self.ui.textResultsOutput.append(
|
47
|
+
f"Ergebnis {i + 1}: \t{calculation}",
|
48
|
+
)
|
49
|
+
if check:
|
50
|
+
self.ui.lineCheckResult.setText("[OK]")
|
51
|
+
logger.info(
|
52
|
+
" [OK] The first calculated result matches 'firstResult'",
|
53
|
+
)
|
54
|
+
else:
|
55
|
+
self.ui.lineCheckResult.setText("[ERROR]")
|
56
|
+
logger.warning(
|
57
|
+
"The first calculated result does not match 'firstResult'",
|
58
|
+
)
|
59
|
+
|
60
|
+
def setup(self, question: ParametricQuestion) -> None:
|
61
|
+
self.question = question
|
62
|
+
self.ui.textResultsOutput.clear()
|
63
|
+
self.ui.equationText.clear()
|
64
|
+
bullets = question.rawData.get(Tags.BPOINTS)
|
65
|
+
firstResult = question.rawData.get(Tags.FIRSTRESULT)
|
66
|
+
self.ui.lineFirstResult.setText(str(firstResult))
|
67
|
+
self.ui.equationText.appendPlainText(question.rawData.get(Tags.EQUATION))
|
68
|
+
for bullet in bullets:
|
69
|
+
self.ui.textResultsOutput.append(bullet)
|
70
|
+
self.updateCalculation()
|
excel2moodle/ui/treewidget.py
CHANGED
@@ -2,11 +2,11 @@ from PySide6 import QtWidgets
|
|
2
2
|
from PySide6.QtCore import Qt
|
3
3
|
|
4
4
|
from excel2moodle.core.dataStructure import Category
|
5
|
-
from excel2moodle.core.question import Question
|
5
|
+
from excel2moodle.core.question import ParametricQuestion, Question
|
6
6
|
|
7
7
|
|
8
8
|
class QuestionItem(QtWidgets.QTreeWidgetItem):
|
9
|
-
def __init__(self, parent, question: Question) -> None:
|
9
|
+
def __init__(self, parent, question: Question | ParametricQuestion) -> None:
|
10
10
|
super().__init__(parent)
|
11
11
|
self.setData(2, Qt.UserRole, question)
|
12
12
|
self.setText(0, question.id)
|
@@ -15,7 +15,7 @@ class QuestionItem(QtWidgets.QTreeWidgetItem):
|
|
15
15
|
if hasattr(question, "variants") and question.variants is not None:
|
16
16
|
self.setText(3, str(question.variants))
|
17
17
|
|
18
|
-
def getQuestion(self) -> Question:
|
18
|
+
def getQuestion(self) -> Question | ParametricQuestion:
|
19
19
|
"""Return the question Object the QTreeWidgetItem represents."""
|
20
20
|
return self.data(2, Qt.UserRole)
|
21
21
|
|
@@ -40,7 +40,7 @@ class CategoryItem(QtWidgets.QTreeWidgetItem):
|
|
40
40
|
for child in self.iterateChildren():
|
41
41
|
q = child.getQuestion()
|
42
42
|
if hasattr(q, "variants") and q.variants is not None:
|
43
|
-
count = q.variants
|
43
|
+
count = max(q.variants, count)
|
44
44
|
return count
|
45
45
|
|
46
46
|
def getCategory(self) -> Category:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: excel2moodle
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.3
|
4
4
|
Summary: A package for converting questions from a spreadsheet, to valid moodle-xml
|
5
5
|
Author: Jakob Bosse
|
6
6
|
License-Expression: GPL-3.0-or-later
|
@@ -14,10 +14,9 @@ Description-Content-Type: text/markdown
|
|
14
14
|
License-File: LICENSE
|
15
15
|
Requires-Dist: pyside6>=6.8.0
|
16
16
|
Requires-Dist: pandas>=2.1.3
|
17
|
-
Requires-Dist: openpyxl>=3.1.5
|
18
17
|
Requires-Dist: lxml>=5.4.0
|
19
|
-
Requires-Dist: odfpy>=1.4.1
|
20
18
|
Requires-Dist: asteval>=1.0.6
|
19
|
+
Requires-Dist: python-calamine>=0.3.2
|
21
20
|
Dynamic: license-file
|
22
21
|
|
23
22
|
# excel 2 Moodle
|
@@ -0,0 +1,38 @@
|
|
1
|
+
excel2moodle/__init__.py,sha256=mnb-RWgmWIPSBk4S65a_jP6rxntAkTeYxN0ObUJalbQ,1801
|
2
|
+
excel2moodle/__main__.py,sha256=sG4ygwfVFskLQorBn-v98SvasNcPmwl_vLYpruT5Hk8,1175
|
3
|
+
excel2moodle/logger.py,sha256=S9tvSwsOx2xta_AhGKHPNgi5FaiycyUDtkzHlIlNAX8,3193
|
4
|
+
excel2moodle/core/__init__.py,sha256=87BwhtZse72Tk17Ib-V9X2k9wkhmtVnEj2ZmJ9JBAnI,63
|
5
|
+
excel2moodle/core/category.py,sha256=TzntDhEURshxWuI6qc_K_t5bSTLXn6s0n_RA56Basg8,1885
|
6
|
+
excel2moodle/core/dataStructure.py,sha256=Gg9dq4koJPAKj87YFItTCz8QlK743K8s_iflJjLWZyU,15535
|
7
|
+
excel2moodle/core/etHelpers.py,sha256=G37qplp8tPJxqHNCBrf2Wo0jJZ0aDbxE9slQavqYqd8,2293
|
8
|
+
excel2moodle/core/exceptions.py,sha256=9xfsaIcm6Yej6QAZga0d3DK3jLQejdfgJARuAaG-uZY,739
|
9
|
+
excel2moodle/core/globals.py,sha256=Zm1wcrzQTRnhjrkwgBvo7VjKCFdPMjh-VLSSI5_QCO8,2837
|
10
|
+
excel2moodle/core/numericMultiQ.py,sha256=vr-gYogu2sf2a_Bhvhnu1ZSZFZXM32MfhJesjTkoOQM,2618
|
11
|
+
excel2moodle/core/parser.py,sha256=Ec8bQ0CiiZCIdzQovfH2rce406wmyRmvhpDrCPeQfGU,8112
|
12
|
+
excel2moodle/core/question.py,sha256=nJDs8SPDRYP6xG4rvo8Bbh1734eQ96DZxVXb7yrT8LM,10802
|
13
|
+
excel2moodle/core/settings.py,sha256=JhcgZcOrgFC7P4h9fSXZAApEl_9dE643r5arFpU1HXQ,5808
|
14
|
+
excel2moodle/core/stringHelpers.py,sha256=OzFZ6Eu3PeBLKb61K-aeVfUZmVuBerr9KfyOsuNRd7Y,2403
|
15
|
+
excel2moodle/core/validator.py,sha256=RwDQ-9Fpc5i2Buy3oorWUAh5zsS5fCF-MjRT4CgcXhY,4698
|
16
|
+
excel2moodle/extra/__init__.py,sha256=PM-id60HD21A3IcGC_fCYFihS8osBGZMIJCcN-ZRsIM,293
|
17
|
+
excel2moodle/extra/equationVerification.py,sha256=GLJl1r90d8AAiNy0H2hooZrg3D6aEwNfifYKAe3aGxM,3921
|
18
|
+
excel2moodle/question_types/__init__.py,sha256=81mss0g7SVtnlb-WkydE28G_dEAAf6oT1uB8lpK2-II,1041
|
19
|
+
excel2moodle/question_types/cloze.py,sha256=hgyv244PChnl7FbxcAMQiC4yzBhV6J3Bg4PHgZQyRmQ,7677
|
20
|
+
excel2moodle/question_types/mc.py,sha256=rHKIKSNeHyto84bI9B3wMKzNJuluplsCmYM4k2HW3wQ,5213
|
21
|
+
excel2moodle/question_types/nf.py,sha256=bMP4IXrhnXmAI0NmjEc7DtX4xGaUbxzLicE2LjeaUho,1150
|
22
|
+
excel2moodle/question_types/nfm.py,sha256=VYrQmCsEZqfn0x_coBsDw3XvrUA4sy_yj0WS7Nsffqw,4950
|
23
|
+
excel2moodle/ui/UI_equationChecker.py,sha256=evQDlqCHeooJcAnYjhFCyjlPhfknr7ULGKQwMmqQeJ4,8947
|
24
|
+
excel2moodle/ui/UI_exportSettingsDialog.py,sha256=71xxXEqtewN0ReMfJ5t4gbrX_Bf0VEuxJ_DIV7ZtH94,6045
|
25
|
+
excel2moodle/ui/UI_mainWindow.py,sha256=asWUmKIYqufKUvRuCuA1JoMyv4qfRXyoR70F0331lww,19291
|
26
|
+
excel2moodle/ui/UI_variantDialog.py,sha256=snVaF3_YAc7NWjMRg7NzbjL_PzNbOpt4eiqElkE46io,5414
|
27
|
+
excel2moodle/ui/__init__.py,sha256=4EdGtpzwH3rgw4xW9E5x9kdPQYwKbo9rehHRZTNxCrQ,44
|
28
|
+
excel2moodle/ui/appUi.py,sha256=NXlBcjxHBeUzpU8rvqwN3wxad8AUgpMjXidwwVdC9GM,10863
|
29
|
+
excel2moodle/ui/dialogs.py,sha256=JbQ1y55wbzWVTY0nxdGrUm81AdOIY3PXKgET03Hc6Ys,6760
|
30
|
+
excel2moodle/ui/equationChecker.py,sha256=ANpN7S0llkp6pGL1sKHII1Jc8YUvgDR458UnGVnZZOo,2702
|
31
|
+
excel2moodle/ui/treewidget.py,sha256=az64swVj1yQUsioeaZys32AauvQDdC4EKcqdbbWgL6s,2489
|
32
|
+
excel2moodle/ui/windowDoc.py,sha256=WvzHj6F4JvHP82WlTsyFeOXW024Xq3BUqtp--T4twuI,661
|
33
|
+
excel2moodle-0.4.3.dist-info/licenses/LICENSE,sha256=ywQqe6Sitymkf2lV2NRcx_aGsaC-KbSl_EfEsRXmNRw,35135
|
34
|
+
excel2moodle-0.4.3.dist-info/METADATA,sha256=mFhUf8uf-GTxdpyOV1JJlb5bkA-fUqUYeHPea-LwMfw,2951
|
35
|
+
excel2moodle-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
36
|
+
excel2moodle-0.4.3.dist-info/entry_points.txt,sha256=myfMLDThuGgWHMJDPPfILiZqo_7D3fhmDdJGqWOAjPw,60
|
37
|
+
excel2moodle-0.4.3.dist-info/top_level.txt,sha256=5V1xRUQ9o7UmOCmNoWCZPAuy5nXp3Qbzyqch8fUGT_c,13
|
38
|
+
excel2moodle-0.4.3.dist-info/RECORD,,
|
@@ -1,115 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
################################################################################
|
4
|
-
## Form generated from reading UI file 'questionPreviewDialog.ui'
|
5
|
-
##
|
6
|
-
## Created by: Qt User Interface Compiler version 6.8.1
|
7
|
-
##
|
8
|
-
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
9
|
-
################################################################################
|
10
|
-
|
11
|
-
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
12
|
-
QMetaObject, QObject, QPoint, QRect,
|
13
|
-
QSize, QTime, QUrl, Qt)
|
14
|
-
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
15
|
-
QFont, QFontDatabase, QGradient, QIcon,
|
16
|
-
QImage, QKeySequence, QLinearGradient, QPainter,
|
17
|
-
QPalette, QPixmap, QRadialGradient, QTransform)
|
18
|
-
from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox,
|
19
|
-
QFormLayout, QFrame, QGraphicsView, QLabel,
|
20
|
-
QLineEdit, QSizePolicy, QVBoxLayout, QWidget)
|
21
|
-
|
22
|
-
class Ui_QuestionPrevDialog(object):
|
23
|
-
def setupUi(self, QuestionPrevDialog):
|
24
|
-
if not QuestionPrevDialog.objectName():
|
25
|
-
QuestionPrevDialog.setObjectName(u"QuestionPrevDialog")
|
26
|
-
QuestionPrevDialog.resize(577, 620)
|
27
|
-
self.verticalLayout = QVBoxLayout(QuestionPrevDialog)
|
28
|
-
self.verticalLayout.setObjectName(u"verticalLayout")
|
29
|
-
self.formLayout = QFormLayout()
|
30
|
-
self.formLayout.setObjectName(u"formLayout")
|
31
|
-
self.formLayout.setLabelAlignment(Qt.AlignmentFlag.AlignLeading|Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
32
|
-
self.formLayout.setHorizontalSpacing(20)
|
33
|
-
self.formLayout.setVerticalSpacing(5)
|
34
|
-
self.formLayout.setContentsMargins(10, 6, 10, -1)
|
35
|
-
self.questionNameLabel = QLabel(QuestionPrevDialog)
|
36
|
-
self.questionNameLabel.setObjectName(u"questionNameLabel")
|
37
|
-
|
38
|
-
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.questionNameLabel)
|
39
|
-
|
40
|
-
self.qNameLine = QLineEdit(QuestionPrevDialog)
|
41
|
-
self.qNameLine.setObjectName(u"qNameLine")
|
42
|
-
self.qNameLine.setReadOnly(True)
|
43
|
-
|
44
|
-
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.qNameLine)
|
45
|
-
|
46
|
-
self.label = QLabel(QuestionPrevDialog)
|
47
|
-
self.label.setObjectName(u"label")
|
48
|
-
|
49
|
-
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label)
|
50
|
-
|
51
|
-
self.qTypeLine = QLineEdit(QuestionPrevDialog)
|
52
|
-
self.qTypeLine.setObjectName(u"qTypeLine")
|
53
|
-
self.qTypeLine.setReadOnly(True)
|
54
|
-
|
55
|
-
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.qTypeLine)
|
56
|
-
|
57
|
-
|
58
|
-
self.verticalLayout.addLayout(self.formLayout)
|
59
|
-
|
60
|
-
self.line = QFrame(QuestionPrevDialog)
|
61
|
-
self.line.setObjectName(u"line")
|
62
|
-
self.line.setFrameShape(QFrame.Shape.HLine)
|
63
|
-
self.line.setFrameShadow(QFrame.Shadow.Sunken)
|
64
|
-
|
65
|
-
self.verticalLayout.addWidget(self.line)
|
66
|
-
|
67
|
-
self.questionText = QLabel(QuestionPrevDialog)
|
68
|
-
self.questionText.setObjectName(u"questionText")
|
69
|
-
self.questionText.setWordWrap(True)
|
70
|
-
self.questionText.setMargin(10)
|
71
|
-
|
72
|
-
self.verticalLayout.addWidget(self.questionText)
|
73
|
-
|
74
|
-
self.graphicsView = QGraphicsView(QuestionPrevDialog)
|
75
|
-
self.graphicsView.setObjectName(u"graphicsView")
|
76
|
-
brush = QBrush(QColor(231, 243, 245, 255))
|
77
|
-
brush.setStyle(Qt.SolidPattern)
|
78
|
-
self.graphicsView.setBackgroundBrush(brush)
|
79
|
-
|
80
|
-
self.verticalLayout.addWidget(self.graphicsView)
|
81
|
-
|
82
|
-
self.answersLabel = QLabel(QuestionPrevDialog)
|
83
|
-
self.answersLabel.setObjectName(u"answersLabel")
|
84
|
-
|
85
|
-
self.verticalLayout.addWidget(self.answersLabel)
|
86
|
-
|
87
|
-
self.answersFormLayout = QFormLayout()
|
88
|
-
self.answersFormLayout.setObjectName(u"answersFormLayout")
|
89
|
-
self.answersFormLayout.setContentsMargins(-1, 3, -1, -1)
|
90
|
-
|
91
|
-
self.verticalLayout.addLayout(self.answersFormLayout)
|
92
|
-
|
93
|
-
self.buttonBox = QDialogButtonBox(QuestionPrevDialog)
|
94
|
-
self.buttonBox.setObjectName(u"buttonBox")
|
95
|
-
self.buttonBox.setOrientation(Qt.Orientation.Horizontal)
|
96
|
-
self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close)
|
97
|
-
|
98
|
-
self.verticalLayout.addWidget(self.buttonBox)
|
99
|
-
|
100
|
-
|
101
|
-
self.retranslateUi(QuestionPrevDialog)
|
102
|
-
self.buttonBox.accepted.connect(QuestionPrevDialog.accept)
|
103
|
-
self.buttonBox.rejected.connect(QuestionPrevDialog.reject)
|
104
|
-
|
105
|
-
QMetaObject.connectSlotsByName(QuestionPrevDialog)
|
106
|
-
# setupUi
|
107
|
-
|
108
|
-
def retranslateUi(self, QuestionPrevDialog):
|
109
|
-
QuestionPrevDialog.setWindowTitle(QCoreApplication.translate("QuestionPrevDialog", u"Dialog", None))
|
110
|
-
self.questionNameLabel.setText(QCoreApplication.translate("QuestionPrevDialog", u"Question Name", None))
|
111
|
-
self.label.setText(QCoreApplication.translate("QuestionPrevDialog", u"Question Type", None))
|
112
|
-
self.questionText.setText(QCoreApplication.translate("QuestionPrevDialog", u"QuestionText", None))
|
113
|
-
self.answersLabel.setText(QCoreApplication.translate("QuestionPrevDialog", u"Answers", None))
|
114
|
-
# retranslateUi
|
115
|
-
|
@@ -1,37 +0,0 @@
|
|
1
|
-
excel2moodle/__init__.py,sha256=qdQJY0xbSiEhnmqbgJpqBe0kHec7yLOeAdcArScioE8,1925
|
2
|
-
excel2moodle/__main__.py,sha256=xnTzJuQL5uDWiwDGoU9vKY4hMSFZIaz0meognglUwxw,1189
|
3
|
-
excel2moodle/logger.py,sha256=e3i6ECB8x-qyR4mP5WhdDGs1WbFXma2tzBjKbMumfOw,3086
|
4
|
-
excel2moodle/core/__init__.py,sha256=H4Bt6u076RKb6BH5F58nHLQvYPDUoayosM_Onyr9yT0,398
|
5
|
-
excel2moodle/core/category.py,sha256=QIl8nh1ryvlVMtNy8hWRfhZZMgGOhQZ3rwDFqf4woa4,1809
|
6
|
-
excel2moodle/core/dataStructure.py,sha256=xEb24WHMSTXnR5JtpLeacfYyBkP418znQXYBTaUix6k,13209
|
7
|
-
excel2moodle/core/etHelpers.py,sha256=i8DAx7YBxrQqzbXFsU-pIvYMPHSRhYci-JvuzY1MzeI,2299
|
8
|
-
excel2moodle/core/exceptions.py,sha256=VgbxrnoR9RRnmDYK2rbB_Bv00r7NLWET6FgddPwo3uw,748
|
9
|
-
excel2moodle/core/globals.py,sha256=Dg46AveftuGTGpxaFdxF87Kc1Azf0dIFQy8dAdgy0cE,3293
|
10
|
-
excel2moodle/core/numericMultiQ.py,sha256=vr-gYogu2sf2a_Bhvhnu1ZSZFZXM32MfhJesjTkoOQM,2618
|
11
|
-
excel2moodle/core/parser.py,sha256=biXKznQdrK0_UNBB4TsV54RqTpAmEnGwZJVC5_wneA0,8549
|
12
|
-
excel2moodle/core/question.py,sha256=mr0T8qc7C-m-A8_A59JeCyu80SmruRB-iTV5JEAHjAk,8599
|
13
|
-
excel2moodle/core/settings.py,sha256=6Do6A1VWlVMJYgT0Je4YyFsIS8rEMcghu-MUXBGk1b0,6842
|
14
|
-
excel2moodle/core/stringHelpers.py,sha256=OzFZ6Eu3PeBLKb61K-aeVfUZmVuBerr9KfyOsuNRd7Y,2403
|
15
|
-
excel2moodle/core/validator.py,sha256=4U0HEJREtZ7d6K7b4F1NA7P_AC3_uv6Th_1YGLKJwgU,4969
|
16
|
-
excel2moodle/extra/__init__.py,sha256=PM-id60HD21A3IcGC_fCYFihS8osBGZMIJCcN-ZRsIM,293
|
17
|
-
excel2moodle/extra/equationVerification.py,sha256=GLJl1r90d8AAiNy0H2hooZrg3D6aEwNfifYKAe3aGxM,3921
|
18
|
-
excel2moodle/question_types/__init__.py,sha256=ZYGg_tYop9c5yUfN8St6FddeaDxbyE2hneKKUFVzcGM,955
|
19
|
-
excel2moodle/question_types/mc.py,sha256=DEloENXMME7zpHgUIdQlH_HKMyPbWdNs45r05nseQ8c,4804
|
20
|
-
excel2moodle/question_types/nf.py,sha256=QcLIGFLTOyZyTouOTbSb9oaqXZAo1wYJz-Ek9oqEVHc,773
|
21
|
-
excel2moodle/question_types/nfm.py,sha256=ndwZdsCb71MrdPGaftqWxD7IuWFNXKRIN7Qcxe1qTHM,3231
|
22
|
-
excel2moodle/ui/__init__.py,sha256=4EdGtpzwH3rgw4xW9E5x9kdPQYwKbo9rehHRZTNxCrQ,44
|
23
|
-
excel2moodle/ui/appUi.py,sha256=3uYIuuLJlUhud5yHo8Uiya3ZOlMUlyWVMtFxHU3ZATk,11284
|
24
|
-
excel2moodle/ui/dialogs.py,sha256=Xvhkvp4U-0yN5dWK9BaP6j3LzeNLd3YMiA1JvtyCZyw,5636
|
25
|
-
excel2moodle/ui/exportSettingsDialog.py,sha256=_BldaX74LsaAfy4rG6g7f55tra3OQETnfyRQ-wClvHU,3610
|
26
|
-
excel2moodle/ui/questionPreviewDialog.py,sha256=_rJvz1GM90aNnj3P6SugEezK7JW6m74ZALgkChohWLM,4980
|
27
|
-
excel2moodle/ui/treewidget.py,sha256=mTRqmZHMZT3QTTvt5Gw9L-yl4KdhhulkF7O1KBwW-_E,2449
|
28
|
-
excel2moodle/ui/variantDialog.py,sha256=snVaF3_YAc7NWjMRg7NzbjL_PzNbOpt4eiqElkE46io,5414
|
29
|
-
excel2moodle/ui/windowDoc.py,sha256=WvzHj6F4JvHP82WlTsyFeOXW024Xq3BUqtp--T4twuI,661
|
30
|
-
excel2moodle/ui/windowEquationChecker.py,sha256=fLyal3sbJwpthWCAxLB5vbSFOX23JoivoYksNp3mZVY,7925
|
31
|
-
excel2moodle/ui/windowMain.py,sha256=iHEq9HRRGduPIxV4QOYUkGgKkbmphJT1vKHsrokQbsM,19668
|
32
|
-
excel2moodle-0.4.1.dist-info/licenses/LICENSE,sha256=ywQqe6Sitymkf2lV2NRcx_aGsaC-KbSl_EfEsRXmNRw,35135
|
33
|
-
excel2moodle-0.4.1.dist-info/METADATA,sha256=wupC5jQBXubRzjlpK2YPXtJeI1Ng31xjG8lUF-khbZE,2972
|
34
|
-
excel2moodle-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
35
|
-
excel2moodle-0.4.1.dist-info/entry_points.txt,sha256=r6Dy9TGktIJUdr1QpKni_ANneugiuEtLYUbsKVMn96w,117
|
36
|
-
excel2moodle-0.4.1.dist-info/top_level.txt,sha256=5V1xRUQ9o7UmOCmNoWCZPAuy5nXp3Qbzyqch8fUGT_c,13
|
37
|
-
excel2moodle-0.4.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|