excel2moodle 0.5.1__py3-none-any.whl → 0.6.0__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/ui/appUi.py CHANGED
@@ -7,13 +7,23 @@ It needs to be seperated from ``windowMain.py`` because that file will be change
7
7
  import logging
8
8
  from pathlib import Path
9
9
 
10
- from PySide6 import QtCore, QtWidgets
11
- from PySide6.QtCore import QRunnable, QSettings, Qt, QThreadPool
10
+ from PySide6.QtCore import QRunnable, QSettings, Qt, QThreadPool, QUrl, Slot
11
+ from PySide6.QtGui import QDesktopServices
12
+ from PySide6.QtWidgets import (
13
+ QAbstractItemView,
14
+ QApplication,
15
+ QFileDialog,
16
+ QHeaderView,
17
+ QMainWindow,
18
+ QMessageBox,
19
+ )
12
20
 
13
- from excel2moodle import mainLogger
21
+ from excel2moodle import e2mMetadata, mainLogger
14
22
  from excel2moodle.core.category import Category
15
23
  from excel2moodle.core.dataStructure import QuestionDB
24
+ from excel2moodle.core.question import ParametricQuestion
16
25
  from excel2moodle.core.settings import Settings, Tags
26
+ from excel2moodle.extra.variableGenerator import VariableGeneratorDialog
17
27
  from excel2moodle.logger import LogWindowHandler
18
28
  from excel2moodle.question_types.mc import MCQuestion
19
29
  from excel2moodle.question_types.nf import NFQuestion
@@ -21,7 +31,6 @@ from excel2moodle.ui import dialogs
21
31
  from excel2moodle.ui.equationChecker import EqCheckerWindow
22
32
  from excel2moodle.ui.treewidget import CategoryItem, QuestionItem
23
33
  from excel2moodle.ui.UI_mainWindow import Ui_MoodleTestGenerator
24
- from excel2moodle.ui.windowDoc import DocumentationWindow
25
34
 
26
35
  logger = logging.getLogger(__name__)
27
36
 
@@ -29,7 +38,7 @@ loggerSignal = LogWindowHandler()
29
38
  mainLogger.addHandler(loggerSignal)
30
39
 
31
40
 
32
- class MainWindow(QtWidgets.QMainWindow):
41
+ class MainWindow(QMainWindow):
33
42
  def __init__(self, settings: Settings, testDB: QuestionDB) -> None:
34
43
  super().__init__()
35
44
  self.settings = settings
@@ -47,27 +56,31 @@ class MainWindow(QtWidgets.QMainWindow):
47
56
  self.eqChecker = EqCheckerWindow()
48
57
  self.connectEvents()
49
58
  logger.info("Settings are stored under: %s", self.qSettings.fileName())
50
- self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
59
+ self.ui.treeWidget.setSelectionMode(QAbstractItemView.MultiSelection)
51
60
  self.ui.treeWidget.header().setSectionResizeMode(
52
- QtWidgets.QHeaderView.ResizeToContents,
61
+ QHeaderView.ResizeToContents,
53
62
  )
63
+ self.ui.pointCounter.setReadOnly(True)
64
+ self.ui.questionCounter.setReadOnly(True)
65
+ self.setStatus(
66
+ "Wählen Sie eine Excel Tabelle mit den Fragen aus",
67
+ )
68
+ self.threadPool = QThreadPool()
69
+ self._restoreSettings()
70
+
71
+ def _restoreSettings(self) -> None:
72
+ """Restore the settings from the last session, if they exist."""
54
73
  self.exportDialog.ui.checkBoxIncludeCategories.setChecked(
55
74
  self.qSettings.value(Tags.INCLUDEINCATS, defaultValue=True, type=bool)
56
75
  )
57
76
  self.exportDialog.ui.spinBoxDefaultQVariant.setValue(
58
77
  self.qSettings.value(Tags.QUESTIONVARIANT, defaultValue=1, type=int)
59
78
  )
60
- self.ui.pointCounter.setReadOnly(True)
61
- self.ui.questionCounter.setReadOnly(True)
62
- self.setStatus(
63
- "Wählen Sie eine Excel Tabelle mit den Fragen aus",
64
- )
65
79
  try:
66
80
  self.resize(self.qSettings.value("windowSize"))
67
81
  self.move(self.qSettings.value("windowPosition"))
68
82
  except Exception:
69
83
  pass
70
- self.threadPool = QThreadPool()
71
84
  if self.qSettings.contains(Tags.SPREADSHEETPATH.full):
72
85
  sheet = self.qSettings.value(Tags.SPREADSHEETPATH.full)
73
86
  self.setSheetPath(sheet)
@@ -79,9 +92,6 @@ class MainWindow(QtWidgets.QMainWindow):
79
92
  )
80
93
  loggerSignal.emitter.signal.connect(self.updateLog)
81
94
  self.ui.actionEquationChecker.triggered.connect(self.openEqCheckerDlg)
82
- self.exportDialog.ui.checkBoxIncludeCategories.checkStateChanged.connect(
83
- self.setIncludeCategoriesSetting,
84
- )
85
95
  self.ui.actionParseAll.triggered.connect(self.parseSpreadsheetAll)
86
96
  self.testDB.signals.categoryQuestionsReady.connect(self.treeRefreshCategory)
87
97
  self.ui.actionSpreadsheet.triggered.connect(self.actionSpreadsheet)
@@ -91,15 +101,13 @@ class MainWindow(QtWidgets.QMainWindow):
91
101
  self.ui.treeWidget.itemClicked.connect(self.updateQuestionPreview)
92
102
  self.ui.actionAbout.triggered.connect(self.openAboutDlg)
93
103
  self.ui.actionDocumentation.triggered.connect(self.openDocumentation)
94
- self.exportDialog.ui.spinBoxDefaultQVariant.valueChanged.connect(
95
- self.setQVariantDefault
104
+ self.ui.actionGenerateVariables.triggered.connect(self.openVariableGeneratorDlg)
105
+ self.ui.actionCopyVariables.triggered.connect(self.copyVariablesToClipboard)
106
+ self.ui.actionOpenSpreadsheetExternal.triggered.connect(
107
+ self.openSpreadsheetExternally
96
108
  )
97
109
 
98
- @QtCore.Slot()
99
- def setQVariantDefault(self, value: int) -> None:
100
- self.settings.set(Tags.QUESTIONVARIANT, value)
101
-
102
- @QtCore.Slot()
110
+ @Slot()
103
111
  def parseSpreadsheetAll(self) -> None:
104
112
  """Event triggered by the *Tools/Parse all Questions* Event.
105
113
 
@@ -128,12 +136,6 @@ class MainWindow(QtWidgets.QMainWindow):
128
136
  def updateLog(self, log) -> None:
129
137
  self.ui.loggerWindow.append(log)
130
138
 
131
- def setIncludeCategoriesSetting(self) -> None:
132
- if self.exportDialog.ui.checkBoxIncludeCategories.isChecked():
133
- self.settings.set(Tags.INCLUDEINCATS, True)
134
- else:
135
- self.settings.set(Tags.INCLUDEINCATS, False)
136
-
137
139
  def closeEvent(self, event) -> None:
138
140
  logger.info("Closing. Saving window stats.")
139
141
  self.qSettings.setValue("windowSize", self.size())
@@ -146,7 +148,7 @@ class MainWindow(QtWidgets.QMainWindow):
146
148
  self.settings.get(Tags.QUESTIONVARIANT),
147
149
  )
148
150
 
149
- @QtCore.Slot()
151
+ @Slot()
150
152
  def onSelectionChanged(self, **args) -> None:
151
153
  """Whenever the selection changes the total of selected points needs to be recalculated."""
152
154
  count: int = 0
@@ -160,7 +162,7 @@ class MainWindow(QtWidgets.QMainWindow):
160
162
  if self.eqChecker.isVisible():
161
163
  self.openEqCheckerDlg()
162
164
 
163
- @QtCore.Slot()
165
+ @Slot()
164
166
  def toggleQuestionSelectionState(self, state) -> None:
165
167
  setter = state == Qt.Checked
166
168
  root = self.ui.treeWidget.invisibleRootItem()
@@ -170,7 +172,7 @@ class MainWindow(QtWidgets.QMainWindow):
170
172
  for q in range(qs):
171
173
  root.child(i).child(q).setSelected(setter)
172
174
 
173
- @QtCore.Slot()
175
+ @Slot()
174
176
  def onButGenTest(self) -> None:
175
177
  """Open a file Dialog so the export file may be choosen."""
176
178
  selection: list[QuestionItem] = self.ui.treeWidget.selectedItems()
@@ -179,14 +181,22 @@ class MainWindow(QtWidgets.QMainWindow):
179
181
  self.exportDialog.ui.pointCount.setValue(self.ui.pointCounter.value())
180
182
  if self.exportDialog.exec():
181
183
  self.exportFile = self.exportDialog.exportFile
184
+ self.settings.set(
185
+ Tags.INCLUDEINCATS,
186
+ self.exportDialog.ui.checkBoxIncludeCategories.isChecked(),
187
+ )
188
+ self.settings.set(
189
+ Tags.QUESTIONVARIANT,
190
+ self.exportDialog.ui.spinBoxDefaultQVariant.value(),
191
+ )
182
192
  logger.info("New Export File is set %s", self.exportFile)
183
193
  self.testDB.appendQuestions(selection, self.exportFile)
184
194
  else:
185
195
  logger.info("Aborting Export")
186
196
 
187
- @QtCore.Slot()
197
+ @Slot()
188
198
  def actionSpreadsheet(self) -> None:
189
- file = QtWidgets.QFileDialog.getOpenFileName(
199
+ file = QFileDialog.getOpenFileName(
190
200
  self,
191
201
  self.tr("Open Spreadsheet"),
192
202
  dir=str(self.mainPath),
@@ -196,7 +206,7 @@ class MainWindow(QtWidgets.QMainWindow):
196
206
  path = Path(file[0]).resolve(strict=True)
197
207
  self.setSheetPath(path)
198
208
 
199
- @QtCore.Slot(Category)
209
+ @Slot(Category)
200
210
  def treeRefreshCategory(self, cat: Category) -> None:
201
211
  """Append Category with its Questions to the treewidget."""
202
212
  catItem = CategoryItem(self.ui.treeWidget, cat)
@@ -205,7 +215,7 @@ class MainWindow(QtWidgets.QMainWindow):
205
215
  QuestionItem(catItem, q)
206
216
  self.ui.treeWidget.sortItems(0, Qt.SortOrder.AscendingOrder)
207
217
 
208
- @QtCore.Slot()
218
+ @Slot()
209
219
  def updateQuestionPreview(self) -> None:
210
220
  item = self.ui.treeWidget.currentItem()
211
221
  if isinstance(item, QuestionItem):
@@ -217,7 +227,7 @@ class MainWindow(QtWidgets.QMainWindow):
217
227
  self.ui.statusbar.clearMessage()
218
228
  self.ui.statusbar.showMessage(self.tr(status))
219
229
 
220
- @QtCore.Slot()
230
+ @Slot()
221
231
  def openEqCheckerDlg(self) -> None:
222
232
  item = self.ui.treeWidget.currentItem()
223
233
  if isinstance(item, QuestionItem):
@@ -231,18 +241,71 @@ class MainWindow(QtWidgets.QMainWindow):
231
241
  else:
232
242
  logger.debug("No Question Item selected: %s", type(item))
233
243
 
234
- @QtCore.Slot()
244
+ @Slot()
235
245
  def openAboutDlg(self) -> None:
236
246
  about = dialogs.AboutDialog(self)
237
247
  about.exec()
238
248
 
239
- @QtCore.Slot()
249
+ @Slot()
240
250
  def openDocumentation(self) -> None:
241
- if hasattr(self, "documentationWindow"):
242
- self.documentationWindow.show()
251
+ url = QUrl(e2mMetadata["documentation"])
252
+ QDesktopServices.openUrl(url)
253
+
254
+ @Slot()
255
+ def openVariableGeneratorDlg(self) -> None:
256
+ item = self.ui.treeWidget.currentItem()
257
+ if isinstance(item, QuestionItem):
258
+ question = item.getQuestion()
259
+ if isinstance(question, ParametricQuestion):
260
+ dialog = VariableGeneratorDialog(self, parametrics=question.parametrics)
261
+ if dialog.exec():
262
+ self.questionPreview.setupQuestion(question)
263
+ logger.info("Updated QuestionItem display for %s", question.id)
264
+ self.copyVariablesToClipboard(
265
+ variables=question.parametrics.variables
266
+ )
267
+ else:
268
+ logger.warning("No variable sets were generated.")
269
+ else:
270
+ logger.info("Selected item is not a ParametricQuestion.")
243
271
  else:
244
- self.documentationWindow = DocumentationWindow(self)
245
- self.documentationWindow.show()
272
+ logger.info("No Question Item selected.")
273
+
274
+ @Slot()
275
+ def copyVariablesToClipboard(
276
+ self, variables: dict[str, list[float | int]] | None = None
277
+ ) -> None:
278
+ if variables is None:
279
+ variables = {}
280
+ if not variables:
281
+ item = self.ui.treeWidget.currentItem()
282
+ if isinstance(item, QuestionItem):
283
+ question = item.getQuestion()
284
+ if isinstance(question, ParametricQuestion):
285
+ variables = question.parametrics.variables
286
+ varsList = [
287
+ f"{name}\t{'; '.join(map(str, vals))}"
288
+ for name, vals in variables.items()
289
+ ]
290
+ clipb = QApplication.clipboard()
291
+ variablesStr = "\n".join(varsList)
292
+ clipb.setText(variablesStr)
293
+ logger.info("Copied all variables to the clipboard")
294
+ QMessageBox.information(
295
+ self,
296
+ "Variables Copied.",
297
+ """All variables from the parametric Question are saved to the system clipboard.\n
298
+ You can paste them into the spreadsheet.
299
+ Make sure to import them with 'Tab' as the seperator.""",
300
+ )
301
+
302
+ @Slot()
303
+ def openSpreadsheetExternally(self) -> None:
304
+ if self.excelPath is None:
305
+ return
306
+ spreadsheetPath = QUrl(f"file://{self.excelPath.absolute()}")
307
+ logger.info("Opening: %s", spreadsheetPath)
308
+ QDesktopServices.openUrl(spreadsheetPath)
246
309
 
247
310
 
248
311
  class ParseAllThread(QRunnable):
@@ -256,7 +319,7 @@ class ParseAllThread(QRunnable):
256
319
  self.testDB = questionDB
257
320
  self.mainApp = mainApp
258
321
 
259
- @QtCore.Slot()
322
+ @Slot()
260
323
  def run(self) -> None:
261
324
  self.testDB.readCategoriesMetadata()
262
325
  self.testDB.asyncInitAllCategories(self.mainApp.excelPath)
@@ -5,12 +5,13 @@ from pathlib import Path
5
5
  from typing import TYPE_CHECKING
6
6
 
7
7
  import lxml.etree as ET
8
- from PySide6 import QtGui, QtWidgets
9
- from PySide6.QtSvgWidgets import QGraphicsSvgItem
8
+ from PySide6.QtWidgets import QDialog, QFileDialog, QMessageBox, QWidget
10
9
 
11
10
  from excel2moodle import e2mMetadata
12
11
  from excel2moodle.core.globals import XMLTags
13
- from excel2moodle.core.question import Question
12
+ from excel2moodle.core.question import ParametricQuestion, Question
13
+ from excel2moodle.core.settings import Tags
14
+ from excel2moodle.extra import variableGenerator
14
15
  from excel2moodle.ui.UI_exportSettingsDialog import Ui_ExportDialog
15
16
  from excel2moodle.ui.UI_variantDialog import Ui_Dialog
16
17
 
@@ -20,11 +21,11 @@ if TYPE_CHECKING:
20
21
  logger = logging.getLogger(__name__)
21
22
 
22
23
 
23
- class QuestionVariantDialog(QtWidgets.QDialog):
24
- def __init__(self, parent, question: Question) -> None:
24
+ class QuestionVariantDialog(QDialog):
25
+ def __init__(self, parent, question: ParametricQuestion) -> None:
25
26
  super().__init__(parent)
26
27
  self.setWindowTitle("Question Variant Dialog")
27
- self.maxVal = question.variants
28
+ self.maxVal = question.parametrics.variants
28
29
  self.ui = Ui_Dialog()
29
30
  self.ui.setupUi(self)
30
31
  self.ui.spinBox.setRange(1, self.maxVal)
@@ -41,7 +42,7 @@ class QuestionVariantDialog(QtWidgets.QDialog):
41
42
  return self.ui.checkBox.isChecked()
42
43
 
43
44
 
44
- class ExportDialog(QtWidgets.QDialog):
45
+ class ExportDialog(QDialog):
45
46
  def __init__(self, parent) -> None:
46
47
  super().__init__(parent)
47
48
  self.setWindowTitle("Export question Selection")
@@ -62,7 +63,7 @@ class ExportDialog(QtWidgets.QDialog):
62
63
  )
63
64
 
64
65
  def getExportFile(self) -> None:
65
- path = QtWidgets.QFileDialog.getSaveFileName(
66
+ path = QFileDialog.getSaveFileName(
66
67
  self,
67
68
  "Select Output File",
68
69
  dir=str(self.exportFile),
@@ -83,85 +84,51 @@ class QuestionPreview:
83
84
  self.ui = parent.ui
84
85
  self.parent = parent
85
86
 
87
+ def _replaceImgPlaceholder(self, elementStr: str) -> str:
88
+ """Replaces '@@PLUGINFILE@@' with the questions Img Folder path."""
89
+ return elementStr.replace(
90
+ "@@PLUGINFILE@@",
91
+ f"{self.pictureFolder}/{self.question.category.NAME}",
92
+ )
93
+
86
94
  def setupQuestion(self, question: Question) -> None:
95
+ self.pictureFolder = self.parent.settings.get(Tags.PICTUREFOLDER)
96
+ self.ui.previewTextEdit.clear()
87
97
  self.question: Question = question
88
98
  self.ui.qNameLine.setText(f"{self.question.qtype} - {self.question.name}")
89
- self.picScene = QtWidgets.QGraphicsScene(self.parent)
90
- self.ui.graphicsView.setScene(self.picScene)
91
- self.setText()
99
+ self.ui.previewTextEdit.append(
100
+ self._replaceImgPlaceholder(
101
+ ET.tostring(self.question.htmlRoot, encoding="unicode")
102
+ )
103
+ )
104
+ self.parent.ui.tableVariables.hide()
92
105
  self.setAnswers()
93
- if hasattr(self, "picItem") and self.picItem.scene() == self.picScene:
94
- logger.debug("removing Previous picture")
95
- self.picScene.removeItem(self.picItem)
96
- del self.picItem
97
- self.setPicture()
98
-
99
- def setPicture(self) -> None:
100
- if hasattr(self.question, "picture") and self.question.picture.ready:
101
- path = self.question.picture.path
102
- if path.suffix == ".svg":
103
- self.picItem = QGraphicsSvgItem(str(path))
104
- else:
105
- pic = QtGui.QPixmap(str(path))
106
- self.picItem = QtWidgets.QGraphicsPixmapItem(pic)
107
- if pic.isNull():
108
- logger.warning("Picture null")
109
- scale = self._getImgFittingScale()
110
- self.picItem.setScale(scale)
111
- self.picScene.addItem(self.picItem)
112
-
113
- def _getImgFittingScale(self) -> float:
114
- view_size = self.ui.graphicsView.viewport().size()
115
- view_width = view_size.width()
116
- view_height = view_size.height()
117
- if isinstance(self.picItem, QtWidgets.QGraphicsPixmapItem):
118
- original_size = self.picItem.pixmap().size()
119
- elif isinstance(self.picItem, QGraphicsSvgItem):
120
- original_size = self.picItem.renderer().defaultSize()
121
- else:
122
- return 1 # Unknown item type
123
- scale_x = view_width / original_size.width()
124
- scale_y = view_height / original_size.height()
125
- return min(scale_x, scale_y)
126
-
127
- def setText(self) -> None:
128
- t = []
129
- for text in self.question.qtextParagraphs:
130
- t.append(ET.tostring(text, encoding="unicode"))
131
- if self.question.bulletList is not None:
132
- t.append(ET.tostring(self.question.bulletList, encoding="unicode"))
133
- self.ui.questionText.setText("\n".join(t))
134
106
 
135
107
  def setAnswers(self) -> None:
136
- if self.question.qtype == "NFM":
137
- list = ET.Element("ol")
138
- for ans in self.question.answerVariants:
139
- textEle = ET.Element("li")
140
- textEle.text = f"Result: {ans.find('text').text}"
141
- list.append(textEle)
142
- self.ui.answersLabel.setText(ET.tostring(list, encoding="unicode"))
108
+ if isinstance(self.question, ParametricQuestion):
109
+ variableGenerator.populateDataSetTable(
110
+ self.parent.ui.tableVariables, parametrics=self.question.parametrics
111
+ )
112
+ self.parent.ui.tableVariables.show()
143
113
  elif self.question.qtype == "NF":
144
- ans = self.question.element.find(XMLTags.ANSWER)
145
- self.ui.answersLabel.setText(f" Result: {ans.find('text').text}")
114
+ ans = self.question._element.find(XMLTags.ANSWER)
115
+ self.ui.previewTextEdit.append(f" Result: {ans.find('text').text}")
146
116
  elif self.question.qtype == "MC":
147
- list = ET.Element("ol")
148
- for ans in self.question.element.findall(XMLTags.ANSWER):
149
- textEle = ET.Element("li")
150
- pEle = ans.find("text").text
151
- frac = ans.get("fraction")
152
- anstext = ET.fromstring(pEle).text
153
- text = f"Fraction {frac}: {anstext}"
154
- textEle.text = text
155
- list.append(textEle)
156
- self.ui.answersLabel.setText(ET.tostring(list, encoding="unicode"))
157
-
158
-
159
- class AboutDialog(QtWidgets.QMessageBox):
160
- def __init__(self, parent: QtWidgets.QWidget) -> None:
117
+ for n, ans in enumerate(self.question._element.findall(XMLTags.ANSWER)):
118
+ self.ui.previewTextEdit.append(
119
+ f"<b>Answer {n + 1}, Fraction {ans.get('fraction')}:</b>"
120
+ )
121
+ self.ui.previewTextEdit.append(
122
+ self._replaceImgPlaceholder(ans.find("text").text)
123
+ )
124
+
125
+
126
+ class AboutDialog(QMessageBox):
127
+ def __init__(self, parent: QWidget) -> None:
161
128
  super().__init__(parent)
162
129
  self.setWindowTitle(f"About {e2mMetadata['name']}")
163
- self.setIcon(QtWidgets.QMessageBox.Information)
164
- self.setStandardButtons(QtWidgets.QMessageBox.StandardButton.Close)
130
+ self.setIcon(QMessageBox.Information)
131
+ self.setStandardButtons(QMessageBox.StandardButton.Close)
165
132
 
166
133
  self.aboutMessage: str = f"""
167
134
  <h1> About {e2mMetadata["name"]} v{e2mMetadata["version"]}</h1><br>
@@ -2,7 +2,7 @@ import logging
2
2
  import math
3
3
  from pathlib import Path
4
4
 
5
- from PySide6 import QtWidgets
5
+ from PySide6.QtWidgets import QWidget
6
6
 
7
7
  from excel2moodle import mainLogger
8
8
  from excel2moodle.core.question import ParametricQuestion
@@ -18,7 +18,7 @@ loggerSignal = LogWindowHandler()
18
18
  mainLogger.addHandler(loggerSignal)
19
19
 
20
20
 
21
- class EqCheckerWindow(QtWidgets.QWidget):
21
+ class EqCheckerWindow(QWidget):
22
22
  def __init__(self) -> None:
23
23
  super().__init__()
24
24
  self.excelFile = Path()
@@ -1,11 +1,17 @@
1
- from PySide6 import QtWidgets
1
+ """The `treewidget` Module provides the `QuestionItem` and the `CategoryItem` item.
2
+
3
+ Those two are subclasses of `QTreeWidgetItem`, to provide an easy interface
4
+ of accessing the corresponding questions from the items.
5
+ """
6
+
2
7
  from PySide6.QtCore import Qt
8
+ from PySide6.QtWidgets import QTreeWidgetItem
3
9
 
4
10
  from excel2moodle.core.dataStructure import Category
5
11
  from excel2moodle.core.question import ParametricQuestion, Question
6
12
 
7
13
 
8
- class QuestionItem(QtWidgets.QTreeWidgetItem):
14
+ class QuestionItem(QTreeWidgetItem):
9
15
  def __init__(self, parent, question: Question | ParametricQuestion) -> None:
10
16
  super().__init__(parent)
11
17
  self.setData(2, Qt.UserRole, question)
@@ -20,7 +26,7 @@ class QuestionItem(QtWidgets.QTreeWidgetItem):
20
26
  return self.data(2, Qt.UserRole)
21
27
 
22
28
 
23
- class CategoryItem(QtWidgets.QTreeWidgetItem):
29
+ class CategoryItem(QTreeWidgetItem):
24
30
  def __init__(self, parent, category: Category) -> None:
25
31
  super().__init__(parent)
26
32
  self.setData(2, Qt.UserRole, category)
@@ -45,24 +51,3 @@ class CategoryItem(QtWidgets.QTreeWidgetItem):
45
51
 
46
52
  def getCategory(self) -> Category:
47
53
  return self.data(2, Qt.UserRole)
48
-
49
-
50
- # class SpinBoxDelegate(QtWidgets.QStyledItemDelegate):
51
- # def __init__(self, parent=None):
52
- # super().__init__(parent)
53
- #
54
- # def createEditor(self, parent, option, index):
55
- # # Create a QSpinBox when the item is being edited
56
- # spinbox = QtWidgets.QSpinBox(parent)
57
- # spinbox.setMinimum(0)
58
- # spinbox.setMaximum(100)
59
- # return spinbox
60
- #
61
- # def setEditorData(self, editor, index):
62
- # # Set the current value of the QSpinBox based on the item's data
63
- # value = index.model().data(index, Qt.EditRole)
64
- # editor.setValue(value)
65
- #
66
- # def setModelData(self, editor, model, index):
67
- # # When editing is done, update the model data with the QSpinBox value
68
- # model.setData(index, editor.value(), Qt.EditRole)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: excel2moodle
3
- Version: 0.5.1
3
+ Version: 0.6.0
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
@@ -12,11 +12,11 @@ Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.10
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
- Requires-Dist: pyside6>=6.8.0
16
15
  Requires-Dist: pandas>=2.1.3
17
16
  Requires-Dist: lxml>=5.4.0
18
17
  Requires-Dist: asteval>=1.0.6
19
18
  Requires-Dist: python-calamine>=0.3.2
19
+ Requires-Dist: pyside6-essentials>=6.8.0
20
20
  Dynamic: license-file
21
21
 
22
22
  # excel 2 Moodle
@@ -81,6 +81,71 @@ If You want to support my work as well, you can by me a [coffee](https://ko-fi.c
81
81
 
82
82
  # Changelogs
83
83
 
84
+ ## 0.6.0 (2025-07-12)
85
+ Added variable generator and other architechtural improvements
86
+
87
+ ### documentation (1 change)
88
+
89
+ - [Documenting variable generator usage](https://gitlab.com/jbosse3/excel2moodle/-/commit/3e4d3019b29872b5cfddf5539d5ebe7638bca049)
90
+
91
+ ### feature (5 changes)
92
+
93
+ - [Opening spreadsheet file works from within excel2moodle](https://gitlab.com/jbosse3/excel2moodle/-/commit/9470f12ea5f098745a3210b281a5144a938ae8b5)
94
+ - [Variables are copied to clipboard](https://gitlab.com/jbosse3/excel2moodle/-/commit/87a7e5ec75f899b293e89ad3c1742567e3ec1c29)
95
+ - [Removed dependence on pyside6-addons](https://gitlab.com/jbosse3/excel2moodle/-/commit/2b3a7cf48581c14bd9cb570cd61d1d41aa410e11)
96
+ - [Var Generator ready](https://gitlab.com/jbosse3/excel2moodle/-/commit/ea97f0639dc35a4c99a64ae3976ccc8a0ac5d109)
97
+ - [Merge development of BulletsObj, Parametrization and VarGenerator](https://gitlab.com/jbosse3/excel2moodle/-/commit/40b46f3c143e082f1bb985d6c8c4e68bb6b6a7a8)
98
+
99
+ ### improvement (7 changes)
100
+
101
+ - [Adapted Param. Parser to use bullet Obj](https://gitlab.com/jbosse3/excel2moodle/-/commit/194cab7cc6aecb2d25d1cb9c1538ed7d607dd9e1)
102
+ - [Added bulleList Object](https://gitlab.com/jbosse3/excel2moodle/-/commit/4ea982b8d8dc270675d2cb059c59fa980ce38894)
103
+ - [Parametrics in beta stage](https://gitlab.com/jbosse3/excel2moodle/-/commit/7d04d8ef2fc603c1b12b6934c827ce079df5d540)
104
+ - [Refactor parse() method, to construct complete xml-Tree](https://gitlab.com/jbosse3/excel2moodle/-/commit/8dc4bea9aa0673d39357115254dd55b02c04114e)
105
+ - [Refactored question assembly to only update fields.](https://gitlab.com/jbosse3/excel2moodle/-/commit/d7accb69be3b4a1e65f59eeecfb463f2663fabd4)
106
+ - [Adapted NFM Question to parametricResult](https://gitlab.com/jbosse3/excel2moodle/-/commit/fe552cd2b538ca8886415c200e4a2a3ecc1fbb2f) ([merge request](https://gitlab.com/jbosse3/excel2moodle/-/merge_requests/5))
107
+ - [Implemented ParametricResult Object](https://gitlab.com/jbosse3/excel2moodle/-/commit/e36d025955f1cab8e0542d66263ab70e3d8980df) ([merge request](https://gitlab.com/jbosse3/excel2moodle/-/merge_requests/5))
108
+
109
+ ## 0.5.2 (2025-06-30)
110
+ Extended Documentation and bugfix for import Module
111
+
112
+ ### bugfix (2 changes)
113
+
114
+ - [Default question variant saved and reused.](https://gitlab.com/jbosse3/excel2moodle/-/commit/097705ba83727463a9b27cd76e99814a7ecf28df)
115
+ - [bugfix: Import module working again](https://gitlab.com/jbosse3/excel2moodle/-/commit/5f293970bcdac3858911cdcc102b72714af057bd)
116
+
117
+ ### documentation (1 change)
118
+
119
+ - [documentation: Added how to build question database](https://gitlab.com/jbosse3/excel2moodle/-/commit/71ceb122aa37e8bf2735b659359ae37d81017599)
120
+
121
+ ### feature (1 change)
122
+
123
+ - [Implemented MC question string method](https://gitlab.com/jbosse3/excel2moodle/-/commit/c4f2081d0000ee60322fe8eec8468fa3317ce7be)
124
+
125
+ ### improvement (1 change)
126
+
127
+ - [Implemented ClozePart object](https://gitlab.com/jbosse3/excel2moodle/-/commit/878f90f45e37421384c4f8f602115e7596b4ceb9)
128
+
129
+ ## 0.5.2 (2025-06-30)
130
+ Extended Documentation and bugfix for import Module
131
+
132
+ ### bugfix (2 changes)
133
+
134
+ - [Default question variant saved and reused.](https://gitlab.com/jbosse3/excel2moodle/-/commit/097705ba83727463a9b27cd76e99814a7ecf28df)
135
+ - [bugfix: Import module working again](https://gitlab.com/jbosse3/excel2moodle/-/commit/5f293970bcdac3858911cdcc102b72714af057bd)
136
+
137
+ ### documentation (1 change)
138
+
139
+ - [documentation: Added how to build question database](https://gitlab.com/jbosse3/excel2moodle/-/commit/71ceb122aa37e8bf2735b659359ae37d81017599)
140
+
141
+ ### feature (1 change)
142
+
143
+ - [Implemented MC question string method](https://gitlab.com/jbosse3/excel2moodle/-/commit/c4f2081d0000ee60322fe8eec8468fa3317ce7be)
144
+
145
+ ### improvement (1 change)
146
+
147
+ - [Implemented ClozePart object](https://gitlab.com/jbosse3/excel2moodle/-/commit/878f90f45e37421384c4f8f602115e7596b4ceb9)
148
+
84
149
  ## 0.5.1 (2025-06-24)
85
150
  Minor docs improvement and question variant bugfix
86
151