excel2moodle 0.3.3__py3-none-any.whl → 0.3.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- excel2moodle/__init__.py +38 -96
- excel2moodle/__main__.py +5 -5
- excel2moodle/core/__init__.py +1 -3
- excel2moodle/core/category.py +67 -47
- excel2moodle/core/dataStructure.py +89 -73
- excel2moodle/core/etHelpers.py +26 -26
- excel2moodle/core/exceptions.py +12 -5
- excel2moodle/core/globals.py +43 -29
- excel2moodle/core/numericMultiQ.py +28 -24
- excel2moodle/core/parser.py +228 -147
- excel2moodle/core/question.py +100 -69
- excel2moodle/core/questionValidator.py +56 -54
- excel2moodle/core/questionWriter.py +232 -139
- excel2moodle/core/stringHelpers.py +38 -34
- excel2moodle/extra/__init__.py +1 -3
- excel2moodle/extra/equationVerification.py +37 -33
- excel2moodle/logger.py +102 -0
- excel2moodle/ui/appUi.py +133 -125
- excel2moodle/ui/dialogs.py +71 -18
- excel2moodle/ui/settings.py +108 -21
- excel2moodle/ui/treewidget.py +13 -10
- excel2moodle/ui/windowMain.py +18 -57
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/METADATA +4 -3
- excel2moodle-0.3.5.dist-info/RECORD +33 -0
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/WHEEL +1 -1
- excel2moodle-0.3.5.dist-info/entry_points.txt +2 -0
- excel2moodle-0.3.3.dist-info/RECORD +0 -31
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/licenses/LICENSE +0 -0
- {excel2moodle-0.3.3.dist-info → excel2moodle-0.3.5.dist-info}/top_level.txt +0 -0
excel2moodle/ui/dialogs.py
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
"""This Module hosts the various Dialog Classes, that can be shown from main Window
|
2
|
-
|
3
|
-
from PySide6 import QtWidgets, QtGui
|
1
|
+
"""This Module hosts the various Dialog Classes, that can be shown from main Window."""
|
2
|
+
|
4
3
|
import lxml.etree as ET
|
4
|
+
from PySide6 import QtGui, QtWidgets
|
5
5
|
from PySide6.QtSvgWidgets import QGraphicsSvgItem
|
6
6
|
|
7
|
+
from excel2moodle import e2mMetadata
|
8
|
+
from excel2moodle.core.globals import XMLTags
|
7
9
|
from excel2moodle.core.question import Question
|
8
|
-
from excel2moodle.ui.variantDialog import Ui_Dialog
|
9
10
|
from excel2moodle.ui.questionPreviewDialog import Ui_QuestionPrevDialog
|
11
|
+
from excel2moodle.ui.variantDialog import Ui_Dialog
|
10
12
|
|
11
13
|
|
12
14
|
class QuestionVariantDialog(QtWidgets.QDialog):
|
13
|
-
def __init__(self,
|
15
|
+
def __init__(self, parent, question: Question) -> None:
|
14
16
|
super().__init__(parent)
|
15
17
|
self.setWindowTitle("Question Variant Dialog")
|
16
18
|
self.maxVal = question.variants
|
@@ -31,50 +33,101 @@ class QuestionVariantDialog(QtWidgets.QDialog):
|
|
31
33
|
|
32
34
|
|
33
35
|
class QuestinoPreviewDialog(QtWidgets.QDialog):
|
34
|
-
def __init__(self, parent: QtWidgets.QWidget, question:Question) -> None:
|
36
|
+
def __init__(self, parent: QtWidgets.QWidget, question: Question) -> None:
|
35
37
|
super().__init__(parent)
|
36
38
|
self.question = question
|
37
39
|
self.ui = Ui_QuestionPrevDialog()
|
38
40
|
self.ui.setupUi(self)
|
41
|
+
self.setModal(True)
|
39
42
|
self.setWindowTitle(f"Question - {question.id} - Preview")
|
40
43
|
self.setupQuestion()
|
41
44
|
|
42
|
-
def setupQuestion(self)->None:
|
45
|
+
def setupQuestion(self) -> None:
|
43
46
|
self.ui.qNameLine.setText(self.question.name)
|
44
47
|
self.ui.qTypeLine.setText(self.question.qtype)
|
45
48
|
self.setText()
|
46
49
|
self.setAnswers()
|
47
50
|
self.setPicture()
|
48
51
|
|
49
|
-
def setPicture(self)->None:
|
52
|
+
def setPicture(self) -> None:
|
50
53
|
if hasattr(self.question, "picture") and self.question.picture.ready:
|
51
54
|
self.picScene = QtWidgets.QGraphicsScene(self)
|
52
55
|
self.ui.graphicsView.setScene(self.picScene)
|
53
56
|
path = self.question.picture.path
|
54
|
-
if path.suffix ==
|
57
|
+
if path.suffix == ".svg":
|
55
58
|
picItem = QGraphicsSvgItem(str(self.question.picture.path))
|
56
59
|
else:
|
57
60
|
pic = QtGui.QPixmap(self.question.picture.path)
|
58
61
|
aspRat = pic.height() // pic.width()
|
59
62
|
width = 400
|
60
63
|
scaleHeight = aspRat * width
|
61
|
-
picItem = QtWidgets.QGraphicsPixmapItem(
|
64
|
+
picItem = QtWidgets.QGraphicsPixmapItem(
|
65
|
+
pic.scaled(
|
66
|
+
width, scaleHeight, QtGui.Qt.AspectRatioMode.KeepAspectRatio
|
67
|
+
)
|
68
|
+
)
|
62
69
|
self.picScene.addItem(picItem)
|
63
70
|
else:
|
64
71
|
self.ui.graphicsView.setFixedHeight(1)
|
65
72
|
|
66
|
-
def setText(self)->None:
|
73
|
+
def setText(self) -> None:
|
67
74
|
t = []
|
68
75
|
for text in self.question.qtextParagraphs:
|
69
|
-
t.append(ET.tostring(text, encoding=
|
70
|
-
|
76
|
+
t.append(ET.tostring(text, encoding="unicode"))
|
77
|
+
if self.question.bulletList is not None:
|
78
|
+
t.append(ET.tostring(self.question.bulletList, encoding="unicode"))
|
71
79
|
self.ui.questionText.setText("\n".join(t))
|
72
80
|
|
73
|
-
def setAnswers(self)->None:
|
81
|
+
def setAnswers(self) -> None:
|
74
82
|
if self.question.qtype == "NFM":
|
75
|
-
for i,ans in enumerate(self.question.answerVariants):
|
76
|
-
a = ans.find(
|
77
|
-
text = QtWidgets.QLineEdit(a, self
|
78
|
-
self.ui.answersFormLayout.addRow(f
|
83
|
+
for i, ans in enumerate(self.question.answerVariants):
|
84
|
+
a = ans.find("text").text
|
85
|
+
text = QtWidgets.QLineEdit(a, self)
|
86
|
+
self.ui.answersFormLayout.addRow(f"Answer {i + 1}", text)
|
87
|
+
|
88
|
+
elif self.question.qtype == "NF":
|
89
|
+
ans = self.question.element.find(XMLTags.ANSWER)
|
90
|
+
a = ans.find("text").text
|
91
|
+
text = QtWidgets.QLineEdit(a, self)
|
92
|
+
self.ui.answersFormLayout.addRow("Result", text)
|
93
|
+
|
94
|
+
elif self.question.qtype == "MC":
|
95
|
+
for i, ans in enumerate(self.question.element.findall(XMLTags.ANSWER)):
|
96
|
+
a = ans.find("text").text
|
97
|
+
frac = ans.get("fraction")
|
98
|
+
text = QtWidgets.QLineEdit(a, self)
|
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)
|
79
108
|
|
109
|
+
self.aboutMessage: str = f"""
|
110
|
+
<h1> About {e2mMetadata["name"]}</h1><br>
|
111
|
+
<p style="text-align:center">
|
80
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)
|
excel2moodle/ui/settings.py
CHANGED
@@ -1,35 +1,122 @@
|
|
1
|
-
|
1
|
+
"""Settings module provides the adjusted subclass of ``PySide6.QtCore.QSettings``."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from enum import StrEnum
|
2
5
|
from pathlib import Path
|
6
|
+
from typing import Literal, overload
|
7
|
+
|
8
|
+
from PySide6.QtCore import QSettings, QTimer, Signal
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class SettingsKey(StrEnum):
|
14
|
+
def __new__(
|
15
|
+
cls,
|
16
|
+
key: str,
|
17
|
+
typ: type,
|
18
|
+
default: str | float | Path | bool | None,
|
19
|
+
):
|
20
|
+
"""Define new settings class."""
|
21
|
+
obj = str.__new__(cls, key)
|
22
|
+
obj._value_ = key
|
23
|
+
obj._default_ = default
|
24
|
+
obj._typ_ = typ
|
25
|
+
return obj
|
26
|
+
|
27
|
+
@property
|
28
|
+
def default(self) -> str | int | float | Path | bool | None:
|
29
|
+
"""Get default value for the key."""
|
30
|
+
return self._default_
|
31
|
+
|
32
|
+
def typ(self) -> type:
|
33
|
+
"""Get default value for the key."""
|
34
|
+
return self._typ_
|
35
|
+
|
36
|
+
QUESTIONVARIANT = "testgen/defaultQuestionVariant", int, 0
|
37
|
+
INCLUDEINCATS = "testgen/includeCats", bool, False
|
38
|
+
PARSERNF_TOLERANCE = "parser/nf/tolerance", int, 1
|
39
|
+
PICTURESUBFOLDER = "core/pictureSubFolder", str, "Abbildungen"
|
40
|
+
PICTUREFOLDER = "core/pictureFolder", Path, None
|
41
|
+
SPREADSHEETFOLDER = "core/spreadsheetFolder", Path, None
|
42
|
+
LOGLEVEL = "core/loglevel", str, "INFO"
|
43
|
+
LOGFILE = "core/logfile", str, "excel2moodleLogFile.log"
|
44
|
+
|
3
45
|
|
4
46
|
class Settings(QSettings):
|
47
|
+
"""Settings for Excel2moodle."""
|
48
|
+
|
5
49
|
shPathChanged = Signal(Path)
|
6
|
-
|
50
|
+
|
51
|
+
def __init__(self) -> None:
|
52
|
+
"""Instantiate the settings."""
|
7
53
|
super().__init__("jbosse3", "excel2moodle")
|
8
|
-
if self.contains(
|
9
|
-
self.sheet = self.
|
10
|
-
|
11
|
-
self.
|
12
|
-
if self.sheet.is_file():
|
13
|
-
QTimer.singleShot(0,self._emitSpreadsheetChanged)
|
14
|
-
except Exception:
|
15
|
-
return None
|
54
|
+
if self.contains(SettingsKey.SPREADSHEETFOLDER):
|
55
|
+
self.sheet = self.get(SettingsKey.SPREADSHEETFOLDER)
|
56
|
+
if self.sheet.is_file():
|
57
|
+
QTimer.singleShot(0, self._emitSpreadsheetChanged)
|
16
58
|
|
17
|
-
def _emitSpreadsheetChanged(self)->None:
|
59
|
+
def _emitSpreadsheetChanged(self) -> None:
|
18
60
|
self.shPathChanged.emit(self.sheet)
|
19
|
-
print("Emitting Spreadsheet Changed Event")
|
20
|
-
|
21
61
|
|
22
|
-
|
23
|
-
|
62
|
+
@overload
|
63
|
+
def get(
|
64
|
+
self,
|
65
|
+
value: Literal[SettingsKey.QUESTIONVARIANT, SettingsKey.PARSERNF_TOLERANCE],
|
66
|
+
) -> int: ...
|
67
|
+
@overload
|
68
|
+
def get(self, value: Literal[SettingsKey.INCLUDEINCATS]) -> bool: ...
|
69
|
+
@overload
|
70
|
+
def get(
|
71
|
+
self,
|
72
|
+
value: Literal[
|
73
|
+
SettingsKey.PICTURESUBFOLDER, SettingsKey.LOGLEVEL, SettingsKey.LOGFILE
|
74
|
+
],
|
75
|
+
) -> str: ...
|
76
|
+
@overload
|
77
|
+
def get(
|
78
|
+
self,
|
79
|
+
value: Literal[SettingsKey.PICTUREFOLDER, SettingsKey.SPREADSHEETFOLDER],
|
80
|
+
) -> Path: ...
|
24
81
|
|
82
|
+
def get(self, value: SettingsKey):
|
83
|
+
"""Get the typesafe settings value."""
|
84
|
+
logger.debug("entering get method. searched typ: %s", value.typ())
|
85
|
+
if value.typ() is Path:
|
86
|
+
logger.debug("trying to acess a path object from settings")
|
87
|
+
path = self.value(value, defaultValue=value.default)
|
88
|
+
try:
|
89
|
+
path.resolve(strict=True)
|
90
|
+
except ValueError:
|
91
|
+
logger.warning(
|
92
|
+
f"The settingsvalue {value} couldn't be fetched with correct typ",
|
93
|
+
)
|
94
|
+
return value.default
|
95
|
+
return path
|
96
|
+
raw = self.value(value, defaultValue=value.default, type=value.typ())
|
97
|
+
logger.debug("read a settings Value: %s of type: %s", value, value.typ())
|
98
|
+
try:
|
99
|
+
return value.typ()(raw)
|
100
|
+
except (ValueError, TypeError):
|
101
|
+
logger.warning(
|
102
|
+
f"The settingsvalue {value} couldn't be fetched with correct typ",
|
103
|
+
)
|
104
|
+
return value.default
|
25
105
|
|
26
|
-
def set(self,
|
27
|
-
|
106
|
+
def set(self, settingKey: SettingsKey, value: float | bool | Path | str) -> None:
|
107
|
+
"""Set the setting to value."""
|
108
|
+
# if isinstance(value, SettingsKey.type):
|
109
|
+
self.setValue(settingKey, value)
|
110
|
+
logger.info("Saved the Setting %s = %s", settingKey, value)
|
111
|
+
# else:
|
112
|
+
# logger.error("trying to save setting with wrong type not possible")
|
28
113
|
|
29
|
-
def setSpreadsheet(self, sheet:Path)->None:
|
114
|
+
def setSpreadsheet(self, sheet: Path) -> None:
|
115
|
+
"""Save spreadsheet path and emit the changed event."""
|
30
116
|
if isinstance(sheet, Path):
|
31
117
|
self.sheet = sheet.resolve(strict=True)
|
32
|
-
self.
|
118
|
+
logpath = str(self.sheet.parent / "excel2moodleLogFile.log")
|
119
|
+
self.set(SettingsKey.LOGFILE, logpath)
|
120
|
+
self.set(SettingsKey.SPREADSHEETFOLDER, self.sheet)
|
33
121
|
self.shPathChanged.emit(sheet)
|
34
|
-
return
|
35
|
-
|
122
|
+
return
|
excel2moodle/ui/treewidget.py
CHANGED
@@ -1,24 +1,27 @@
|
|
1
1
|
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
|
6
|
+
|
5
7
|
|
6
8
|
class QuestionItem(QtWidgets.QTreeWidgetItem):
|
7
|
-
def __init__(self, parent, question:Question)->None:
|
9
|
+
def __init__(self, parent, question: Question) -> None:
|
8
10
|
super().__init__(parent)
|
9
|
-
self.setData(2,Qt.UserRole, question)
|
11
|
+
self.setData(2, Qt.UserRole, question)
|
10
12
|
self.setText(0, question.id)
|
11
13
|
self.setText(1, question.name)
|
12
14
|
self.setText(2, str(question.points))
|
13
15
|
if hasattr(question, "variants") and question.variants is not None:
|
14
16
|
self.setText(3, str(question.variants))
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
+
def getQuestion(self) -> Question:
|
19
|
+
"""Return the question Object the QTreeWidgetItem represents."""
|
18
20
|
return self.data(2, Qt.UserRole)
|
19
21
|
|
22
|
+
|
20
23
|
class CategoryItem(QtWidgets.QTreeWidgetItem):
|
21
|
-
def __init__(self, parent, category:Category)->None:
|
24
|
+
def __init__(self, parent, category: Category) -> None:
|
22
25
|
super().__init__(parent)
|
23
26
|
self.setData(2, Qt.UserRole, category)
|
24
27
|
self.setText(0, category.NAME)
|
@@ -32,17 +35,17 @@ class CategoryItem(QtWidgets.QTreeWidgetItem):
|
|
32
35
|
for child in range(self.childCount()):
|
33
36
|
yield self.child(child)
|
34
37
|
|
35
|
-
def getMaxVariants(self)->int:
|
36
|
-
count:int=0
|
38
|
+
def getMaxVariants(self) -> int:
|
39
|
+
count: int = 0
|
37
40
|
for child in self.iterateChildren():
|
38
41
|
q = child.getQuestion()
|
39
42
|
if hasattr(q, "variants") and q.variants is not None:
|
40
43
|
count = q.variants if count <= q.variants else count
|
41
44
|
return count
|
42
45
|
|
46
|
+
def getCategory(self) -> Category:
|
47
|
+
return self.data(2, Qt.UserRole)
|
43
48
|
|
44
|
-
def getCategory(self)->Category:
|
45
|
-
return self.data(2,Qt.UserRole)
|
46
49
|
|
47
50
|
# class SpinBoxDelegate(QtWidgets.QStyledItemDelegate):
|
48
51
|
# def __init__(self, parent=None):
|
excel2moodle/ui/windowMain.py
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
################################################################################
|
4
4
|
## Form generated from reading UI file 'mainWindow.ui'
|
5
5
|
##
|
6
|
-
## Created by: Qt User Interface Compiler version 6.
|
6
|
+
## Created by: Qt User Interface Compiler version 6.9.0
|
7
7
|
##
|
8
8
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
9
9
|
################################################################################
|
@@ -52,9 +52,6 @@ class Ui_MoodleTestGenerator(object):
|
|
52
52
|
self.actionAbout.setObjectName(u"actionAbout")
|
53
53
|
icon5 = QIcon(QIcon.fromTheme(u"help-about"))
|
54
54
|
self.actionAbout.setIcon(icon5)
|
55
|
-
self.actionDocumentation = QAction(MoodleTestGenerator)
|
56
|
-
self.actionDocumentation.setObjectName(u"actionDocumentation")
|
57
|
-
self.actionDocumentation.setIcon(icon5)
|
58
55
|
self.actionSetting = QAction(MoodleTestGenerator)
|
59
56
|
self.actionSetting.setObjectName(u"actionSetting")
|
60
57
|
icon6 = QIcon(QIcon.fromTheme(u"preferences-system"))
|
@@ -136,7 +133,7 @@ class Ui_MoodleTestGenerator(object):
|
|
136
133
|
self.label_6 = QLabel(self.mainWidget)
|
137
134
|
self.label_6.setObjectName(u"label_6")
|
138
135
|
|
139
|
-
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label_6)
|
136
|
+
self.formLayout.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_6)
|
140
137
|
|
141
138
|
self.pointCounter = QDoubleSpinBox(self.mainWidget)
|
142
139
|
self.pointCounter.setObjectName(u"pointCounter")
|
@@ -156,12 +153,12 @@ class Ui_MoodleTestGenerator(object):
|
|
156
153
|
self.pointCounter.setDecimals(1)
|
157
154
|
self.pointCounter.setMaximum(999.899999999999977)
|
158
155
|
|
159
|
-
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.pointCounter)
|
156
|
+
self.formLayout.setWidget(0, QFormLayout.ItemRole.FieldRole, self.pointCounter)
|
160
157
|
|
161
158
|
self.label_7 = QLabel(self.mainWidget)
|
162
159
|
self.label_7.setObjectName(u"label_7")
|
163
160
|
|
164
|
-
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_7)
|
161
|
+
self.formLayout.setWidget(1, QFormLayout.ItemRole.LabelRole, self.label_7)
|
165
162
|
|
166
163
|
self.questionCounter = QDoubleSpinBox(self.mainWidget)
|
167
164
|
self.questionCounter.setObjectName(u"questionCounter")
|
@@ -169,19 +166,7 @@ class Ui_MoodleTestGenerator(object):
|
|
169
166
|
self.questionCounter.setDecimals(0)
|
170
167
|
self.questionCounter.setMaximum(300.000000000000000)
|
171
168
|
|
172
|
-
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.questionCounter)
|
173
|
-
|
174
|
-
self.label_8 = QLabel(self.mainWidget)
|
175
|
-
self.label_8.setObjectName(u"label_8")
|
176
|
-
|
177
|
-
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_8)
|
178
|
-
|
179
|
-
self.categoriesCounter = QSpinBox(self.mainWidget)
|
180
|
-
self.categoriesCounter.setObjectName(u"categoriesCounter")
|
181
|
-
self.categoriesCounter.setFont(font2)
|
182
|
-
self.categoriesCounter.setMaximum(999)
|
183
|
-
|
184
|
-
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.categoriesCounter)
|
169
|
+
self.formLayout.setWidget(1, QFormLayout.ItemRole.FieldRole, self.questionCounter)
|
185
170
|
|
186
171
|
|
187
172
|
self.verticalLayout_2.addLayout(self.formLayout)
|
@@ -232,35 +217,25 @@ class Ui_MoodleTestGenerator(object):
|
|
232
217
|
self.formLayout_2 = QFormLayout()
|
233
218
|
self.formLayout_2.setObjectName(u"formLayout_2")
|
234
219
|
self.formLayout_2.setContentsMargins(5, 5, 5, 5)
|
235
|
-
self.
|
236
|
-
self.
|
237
|
-
|
238
|
-
self.formLayout_2.setWidget(2, QFormLayout.LabelRole, self.label_9)
|
239
|
-
|
240
|
-
self.checkBoxIncludeCategories = QCheckBox(self.mainWidget)
|
241
|
-
self.checkBoxIncludeCategories.setObjectName(u"checkBoxIncludeCategories")
|
220
|
+
self.label_10 = QLabel(self.mainWidget)
|
221
|
+
self.label_10.setObjectName(u"label_10")
|
242
222
|
|
243
|
-
self.formLayout_2.setWidget(
|
223
|
+
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.LabelRole, self.label_10)
|
244
224
|
|
245
225
|
self.spinBoxDefaultQVariant = QSpinBox(self.mainWidget)
|
246
226
|
self.spinBoxDefaultQVariant.setObjectName(u"spinBoxDefaultQVariant")
|
247
227
|
|
248
|
-
self.formLayout_2.setWidget(
|
249
|
-
|
250
|
-
self.checkBoxUseDefQVariant = QCheckBox(self.mainWidget)
|
251
|
-
self.checkBoxUseDefQVariant.setObjectName(u"checkBoxUseDefQVariant")
|
228
|
+
self.formLayout_2.setWidget(0, QFormLayout.ItemRole.FieldRole, self.spinBoxDefaultQVariant)
|
252
229
|
|
253
|
-
self.
|
254
|
-
|
255
|
-
self.label_10 = QLabel(self.mainWidget)
|
256
|
-
self.label_10.setObjectName(u"label_10")
|
230
|
+
self.label_9 = QLabel(self.mainWidget)
|
231
|
+
self.label_9.setObjectName(u"label_9")
|
257
232
|
|
258
|
-
self.formLayout_2.setWidget(1, QFormLayout.LabelRole, self.
|
233
|
+
self.formLayout_2.setWidget(1, QFormLayout.ItemRole.LabelRole, self.label_9)
|
259
234
|
|
260
|
-
self.
|
261
|
-
self.
|
235
|
+
self.checkBoxIncludeCategories = QCheckBox(self.mainWidget)
|
236
|
+
self.checkBoxIncludeCategories.setObjectName(u"checkBoxIncludeCategories")
|
262
237
|
|
263
|
-
self.formLayout_2.setWidget(
|
238
|
+
self.formLayout_2.setWidget(1, QFormLayout.ItemRole.FieldRole, self.checkBoxIncludeCategories)
|
264
239
|
|
265
240
|
|
266
241
|
self.verticalLayout_2.addLayout(self.formLayout_2)
|
@@ -333,14 +308,12 @@ class Ui_MoodleTestGenerator(object):
|
|
333
308
|
self.menuTools.addAction(self.actionParseAll)
|
334
309
|
self.menuTools.addAction(self.actionPreviewQ)
|
335
310
|
self.menuTools.addAction(self.actionSetting)
|
336
|
-
self.menuHelp.addAction(self.actionAbout)
|
337
|
-
self.menuHelp.addAction(self.actionDocumentation)
|
338
311
|
self.toolBar.addAction(self.actionInput_Spreadsheet)
|
339
312
|
self.toolBar.addAction(self.actionParseAll)
|
340
313
|
self.toolBar.addSeparator()
|
341
314
|
self.toolBar_3.addAction(self.actionEquationChecker)
|
342
315
|
self.toolBar_3.addAction(self.actionPreviewQ)
|
343
|
-
self.toolBar_2.addAction(self.
|
316
|
+
self.toolBar_2.addAction(self.actionAbout)
|
344
317
|
self.toolBar_2.addAction(self.actionSetting)
|
345
318
|
|
346
319
|
self.retranslateUi(MoodleTestGenerator)
|
@@ -368,15 +341,11 @@ class Ui_MoodleTestGenerator(object):
|
|
368
341
|
self.actionPreviewQ.setShortcut(QCoreApplication.translate("MoodleTestGenerator", u"Ctrl+P", None))
|
369
342
|
#endif // QT_CONFIG(shortcut)
|
370
343
|
self.actionAbout.setText(QCoreApplication.translate("MoodleTestGenerator", u"About", None))
|
371
|
-
self.actionDocumentation.setText(QCoreApplication.translate("MoodleTestGenerator", u"Documentation", None))
|
372
|
-
#if QT_CONFIG(shortcut)
|
373
|
-
self.actionDocumentation.setShortcut(QCoreApplication.translate("MoodleTestGenerator", u"F1", None))
|
374
|
-
#endif // QT_CONFIG(shortcut)
|
375
344
|
self.actionSetting.setText(QCoreApplication.translate("MoodleTestGenerator", u"Settings", None))
|
376
345
|
self.checkBoxQuestionListSelectAll.setText(QCoreApplication.translate("MoodleTestGenerator", u"Select all", None))
|
377
346
|
self.label.setText(QCoreApplication.translate("MoodleTestGenerator", u"Question List", None))
|
378
347
|
___qtreewidgetitem = self.treeWidget.headerItem()
|
379
|
-
___qtreewidgetitem.setText(3, QCoreApplication.translate("MoodleTestGenerator", u"
|
348
|
+
___qtreewidgetitem.setText(3, QCoreApplication.translate("MoodleTestGenerator", u"Variants", None));
|
380
349
|
___qtreewidgetitem.setText(2, QCoreApplication.translate("MoodleTestGenerator", u"Points", None));
|
381
350
|
___qtreewidgetitem.setText(1, QCoreApplication.translate("MoodleTestGenerator", u"Description", None));
|
382
351
|
___qtreewidgetitem.setText(0, QCoreApplication.translate("MoodleTestGenerator", u"Question ID", None));
|
@@ -385,23 +354,15 @@ class Ui_MoodleTestGenerator(object):
|
|
385
354
|
self.pointCounter.setPrefix("")
|
386
355
|
self.label_7.setText(QCoreApplication.translate("MoodleTestGenerator", u"Questions", None))
|
387
356
|
self.questionCounter.setPrefix("")
|
388
|
-
self.label_8.setText(QCoreApplication.translate("MoodleTestGenerator", u"Categories", None))
|
389
|
-
self.categoriesCounter.setSuffix("")
|
390
|
-
self.categoriesCounter.setPrefix("")
|
391
357
|
self.label_2.setText(QCoreApplication.translate("MoodleTestGenerator", u"Input", None))
|
392
358
|
self.buttonSpreadSheet.setText(QCoreApplication.translate("MoodleTestGenerator", u"Select spreadsheet", None))
|
393
359
|
self.label_3.setText(QCoreApplication.translate("MoodleTestGenerator", u"Output", None))
|
360
|
+
self.label_10.setText(QCoreApplication.translate("MoodleTestGenerator", u"Default Question Variant", None))
|
394
361
|
#if QT_CONFIG(tooltip)
|
395
362
|
self.label_9.setToolTip(QCoreApplication.translate("MoodleTestGenerator", u"If enabled, all questions will be categorized, when importing into moodle. Otherwise they will all be imported into one category", None))
|
396
363
|
#endif // QT_CONFIG(tooltip)
|
397
364
|
self.label_9.setText(QCoreApplication.translate("MoodleTestGenerator", u"Include Questions in Categories", None))
|
398
365
|
self.checkBoxIncludeCategories.setText("")
|
399
|
-
self.checkBoxUseDefQVariant.setText("")
|
400
|
-
self.label_10.setText(QCoreApplication.translate("MoodleTestGenerator", u"Default Question Variant", None))
|
401
|
-
#if QT_CONFIG(tooltip)
|
402
|
-
self.label_11.setToolTip(QCoreApplication.translate("MoodleTestGenerator", u"If enabled it will always use the question variant that is set below. If not, it will ask everytime, which question Variant should be used", None))
|
403
|
-
#endif // QT_CONFIG(tooltip)
|
404
|
-
self.label_11.setText(QCoreApplication.translate("MoodleTestGenerator", u"Use default question Variant", None))
|
405
366
|
self.buttonTestGen.setText(QCoreApplication.translate("MoodleTestGenerator", u"export selected Questions to examfile", None))
|
406
367
|
self.label_4.setText(QCoreApplication.translate("MoodleTestGenerator", u"Logger", None))
|
407
368
|
self.menuFile.setTitle(QCoreApplication.translate("MoodleTestGenerator", u"File", None))
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: excel2moodle
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.5
|
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
|
@@ -15,8 +15,9 @@ License-File: LICENSE
|
|
15
15
|
Requires-Dist: pyside6>=6.8.0
|
16
16
|
Requires-Dist: pandas>=2.1.3
|
17
17
|
Requires-Dist: openpyxl>=3.1.5
|
18
|
-
Requires-Dist:
|
19
|
-
Requires-Dist: odfpy
|
18
|
+
Requires-Dist: lxml>=5.4.0
|
19
|
+
Requires-Dist: odfpy>=1.4.1
|
20
|
+
Requires-Dist: asteval>=1.0.6
|
20
21
|
Dynamic: license-file
|
21
22
|
|
22
23
|
# excel 2 Moodle
|
@@ -0,0 +1,33 @@
|
|
1
|
+
excel2moodle/__init__.py,sha256=b5hZTSd7Ffy89ct8mGHQbplbqcylrLx3u2h__tyvhs0,2324
|
2
|
+
excel2moodle/__main__.py,sha256=8o3KK_RDgyTNW05cRL_iiu7BBHbIqWX9H878eHvf9Ag,544
|
3
|
+
excel2moodle/logger.py,sha256=Af4IuJ4bJUCGSNoABakgUzVrYLAD3n9YTQXEXHk4j5Q,3138
|
4
|
+
excel2moodle/core/__init__.py,sha256=H4Bt6u076RKb6BH5F58nHLQvYPDUoayosM_Onyr9yT0,398
|
5
|
+
excel2moodle/core/category.py,sha256=VunNsfRUv7O8L3XMe1BB2EFxtfCAJFaRafRYRKF15kE,3006
|
6
|
+
excel2moodle/core/dataStructure.py,sha256=1lZtV2CULCDbzmfgaFO_l4Jn0OJ6vYJ3hDN2oe81nfE,6215
|
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=OGBxkgD19etaMP6sTtsTZ_u8NXbnHYdCQYAu9E3pcgE,3692
|
10
|
+
excel2moodle/core/numericMultiQ.py,sha256=vr-gYogu2sf2a_Bhvhnu1ZSZFZXM32MfhJesjTkoOQM,2618
|
11
|
+
excel2moodle/core/parser.py,sha256=jsBMjluc5OICCkrtT4WNVwO26-MaBOTuiOUbQhN2d6g,15232
|
12
|
+
excel2moodle/core/question.py,sha256=ZubBhS3n7wRFgtcKZ4AoUBSsxLyIM1wsmzsBqbSab-I,6489
|
13
|
+
excel2moodle/core/questionValidator.py,sha256=a12bPd6hdE5vuj8aoXA0qXVZ0pI98X-uUBzF0oIbzYk,4810
|
14
|
+
excel2moodle/core/questionWriter.py,sha256=UiWbrtNSiQiYY_x3sF3nz6Ic0b_lL0uWHyeDNDtFvPM,10985
|
15
|
+
excel2moodle/core/stringHelpers.py,sha256=XZAyXKZcQT_bAQSb9tBQs5tMC5soJf_ZhYFHrDX9ck4,2994
|
16
|
+
excel2moodle/extra/__init__.py,sha256=PM-id60HD21A3IcGC_fCYFihS8osBGZMIJCcN-ZRsIM,293
|
17
|
+
excel2moodle/extra/equationVerification.py,sha256=GLJl1r90d8AAiNy0H2hooZrg3D6aEwNfifYKAe3aGxM,3921
|
18
|
+
excel2moodle/ui/__init__.py,sha256=4EdGtpzwH3rgw4xW9E5x9kdPQYwKbo9rehHRZTNxCrQ,44
|
19
|
+
excel2moodle/ui/appUi.py,sha256=axZ-DtP2ugz68CPWtqVKU81i5Wq8yG1df3tw3YatDvU,9991
|
20
|
+
excel2moodle/ui/dialogs.py,sha256=EgAKcydF4clyEweocjmtyCdsQJdQmvY-LVzOlu_cl_8,5320
|
21
|
+
excel2moodle/ui/questionPreviewDialog.py,sha256=_rJvz1GM90aNnj3P6SugEezK7JW6m74ZALgkChohWLM,4980
|
22
|
+
excel2moodle/ui/settings.py,sha256=pzYkMz1fBNW2t_H1KRBtcAqMxRbirj4aUY9yK5kuqIY,4288
|
23
|
+
excel2moodle/ui/treewidget.py,sha256=mTRqmZHMZT3QTTvt5Gw9L-yl4KdhhulkF7O1KBwW-_E,2449
|
24
|
+
excel2moodle/ui/variantDialog.py,sha256=snVaF3_YAc7NWjMRg7NzbjL_PzNbOpt4eiqElkE46io,5414
|
25
|
+
excel2moodle/ui/windowDoc.py,sha256=IciZpwrLnGzIQV1aCdKQBg6km3oufHGs8havTFzNJyU,1055
|
26
|
+
excel2moodle/ui/windowEquationChecker.py,sha256=fLyal3sbJwpthWCAxLB5vbSFOX23JoivoYksNp3mZVY,7925
|
27
|
+
excel2moodle/ui/windowMain.py,sha256=FsaApCyWgngnWPb46R8_01z8q4XeWxRFVqewSIt742c,19027
|
28
|
+
excel2moodle-0.3.5.dist-info/licenses/LICENSE,sha256=ywQqe6Sitymkf2lV2NRcx_aGsaC-KbSl_EfEsRXmNRw,35135
|
29
|
+
excel2moodle-0.3.5.dist-info/METADATA,sha256=MstfP8n_sfCdP2buwc8lmgX3C4cO9JzReftV-JMehJU,2945
|
30
|
+
excel2moodle-0.3.5.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
31
|
+
excel2moodle-0.3.5.dist-info/entry_points.txt,sha256=myfMLDThuGgWHMJDPPfILiZqo_7D3fhmDdJGqWOAjPw,60
|
32
|
+
excel2moodle-0.3.5.dist-info/top_level.txt,sha256=5V1xRUQ9o7UmOCmNoWCZPAuy5nXp3Qbzyqch8fUGT_c,13
|
33
|
+
excel2moodle-0.3.5.dist-info/RECORD,,
|
@@ -1,31 +0,0 @@
|
|
1
|
-
excel2moodle/__init__.py,sha256=dsK3KrorPt06FUp18_dw2m4p9P8E7rFf9I0BR-4I28k,4263
|
2
|
-
excel2moodle/__main__.py,sha256=SsulFcOSlRBF2tLTUIdFgB0EJdSLGBIQ_HO53S4Sih8,541
|
3
|
-
excel2moodle/core/__init__.py,sha256=E7smxf7ESHlucvho4Gb5oaTHA7IsOv9J-UDIsoKwp84,399
|
4
|
-
excel2moodle/core/category.py,sha256=rZsQW5-Ud182xCrS4R8B0vrPMrI-azwtfzlTdy89SR4,2982
|
5
|
-
excel2moodle/core/dataStructure.py,sha256=h82r4wO2PhhHA4EqROjfkqWGUpg6UKQhkyrdjdisLxg,6343
|
6
|
-
excel2moodle/core/etHelpers.py,sha256=_fd-fGMVNWt1l8FY7xcA2uXOBahxtq8ggYxRYm4SwdA,2354
|
7
|
-
excel2moodle/core/exceptions.py,sha256=3OLVHMCBgETiOxSsirlsCPvlMN5UgEQcMkRDkCfrUs4,675
|
8
|
-
excel2moodle/core/globals.py,sha256=9V9-KBSsHMdsRZWg2wGrvjAd6dc3XZG4pNPnun0AHGE,3595
|
9
|
-
excel2moodle/core/numericMultiQ.py,sha256=InBrn-tsCCYwDb78sGR3FyFxVeN0GfIg63JGtr_tqg4,2751
|
10
|
-
excel2moodle/core/parser.py,sha256=0bLP_bkTFu3URw08sn1zJCvA3YCKxDAC4a6I14koHho,13408
|
11
|
-
excel2moodle/core/question.py,sha256=zzdL_7BdWs0wUVl8-06gLkKu0Is3n0zU-2ZkaYhU504,5913
|
12
|
-
excel2moodle/core/questionValidator.py,sha256=taOrrR6pd5mN7SGpET9eLOvb1v5NWvg_VgMj8opQlZ4,4791
|
13
|
-
excel2moodle/core/questionWriter.py,sha256=kyUTrnjWrLEWdez5_7FPNJ0Cs_fF5d16oOQiVvHv3zA,10242
|
14
|
-
excel2moodle/core/stringHelpers.py,sha256=9BqR7yx2bL8WknVMPuNlmWz05bgi4qWjFYHsgaftpZw,3141
|
15
|
-
excel2moodle/extra/__init__.py,sha256=e70OmuW3j7N4ErIIHlK4vkmCKcpRbitJCdJvzjego8c,339
|
16
|
-
excel2moodle/extra/equationVerification.py,sha256=FOvVBQZ357fbA5nYkHjvvWWVP3pQpo4RK3H7vru9v3A,4278
|
17
|
-
excel2moodle/ui/__init__.py,sha256=4EdGtpzwH3rgw4xW9E5x9kdPQYwKbo9rehHRZTNxCrQ,44
|
18
|
-
excel2moodle/ui/appUi.py,sha256=TEqslEDExDOyYwCh7czg3YZggPdZewFiImbpzACLYLU,10533
|
19
|
-
excel2moodle/ui/dialogs.py,sha256=5dnzRN9cwaxjJsxA7I9v1imH4k6XVzzievYi3PR32XI,3038
|
20
|
-
excel2moodle/ui/questionPreviewDialog.py,sha256=_rJvz1GM90aNnj3P6SugEezK7JW6m74ZALgkChohWLM,4980
|
21
|
-
excel2moodle/ui/settings.py,sha256=PB0uBMCd8DIRSFfvUAPs5hK4UEcb0y7dG9ZJ--kOvuQ,1115
|
22
|
-
excel2moodle/ui/treewidget.py,sha256=xiYWhJeJ9o9Iubtr44HcyJas9v4m8aBsHNdokQAHi80,2357
|
23
|
-
excel2moodle/ui/variantDialog.py,sha256=snVaF3_YAc7NWjMRg7NzbjL_PzNbOpt4eiqElkE46io,5414
|
24
|
-
excel2moodle/ui/windowDoc.py,sha256=IciZpwrLnGzIQV1aCdKQBg6km3oufHGs8havTFzNJyU,1055
|
25
|
-
excel2moodle/ui/windowEquationChecker.py,sha256=fLyal3sbJwpthWCAxLB5vbSFOX23JoivoYksNp3mZVY,7925
|
26
|
-
excel2moodle/ui/windowMain.py,sha256=sB1ahkAwxFxO3EYP3X_MuB6ohgXwK5NUQHWeFo4eqrI,21062
|
27
|
-
excel2moodle-0.3.3.dist-info/licenses/LICENSE,sha256=ywQqe6Sitymkf2lV2NRcx_aGsaC-KbSl_EfEsRXmNRw,35135
|
28
|
-
excel2moodle-0.3.3.dist-info/METADATA,sha256=i7lC9k3j8ErKfWNnPAngdrnDAWIqC5V6egSB5uWivW8,2904
|
29
|
-
excel2moodle-0.3.3.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
30
|
-
excel2moodle-0.3.3.dist-info/top_level.txt,sha256=5V1xRUQ9o7UmOCmNoWCZPAuy5nXp3Qbzyqch8fUGT_c,13
|
31
|
-
excel2moodle-0.3.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|