excel2moodle 0.4.2__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/core/dataStructure.py +35 -8
- excel2moodle/core/question.py +8 -8
- excel2moodle/core/settings.py +46 -78
- excel2moodle/logger.py +5 -2
- excel2moodle/question_types/cloze.py +1 -1
- excel2moodle/question_types/nfm.py +4 -4
- excel2moodle/ui/appUi.py +35 -24
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/METADATA +1 -1
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/RECORD +14 -14
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/WHEEL +0 -0
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/entry_points.txt +0 -0
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/licenses/LICENSE +0 -0
- {excel2moodle-0.4.2.dist-info → excel2moodle-0.4.3.dist-info}/top_level.txt +0 -0
excel2moodle/__init__.py
CHANGED
@@ -76,7 +76,18 @@ class QuestionDB:
|
|
76
76
|
self.categoriesMetaData: pd.DataFrame
|
77
77
|
self.categories: dict[str, Category]
|
78
78
|
|
79
|
-
|
79
|
+
@property
|
80
|
+
def spreadsheet(self) -> Path:
|
81
|
+
return self._spreadsheet
|
82
|
+
|
83
|
+
@spreadsheet.setter
|
84
|
+
def spreadsheet(self, sheet) -> None:
|
85
|
+
self.settings.clear()
|
86
|
+
self._spreadsheet = sheet
|
87
|
+
self.settings.set(Tags.SPREADSHEETPATH, sheet)
|
88
|
+
logger.info("saved new spreadsheet %s", sheet)
|
89
|
+
|
90
|
+
def readCategoriesMetadata(self, sheetPath: Path | None = None) -> pd.DataFrame:
|
80
91
|
"""Read the metadata and questions from the spreadsheet.
|
81
92
|
|
82
93
|
Get the category data from the spreadsheet and stores it in the
|
@@ -84,6 +95,7 @@ class QuestionDB:
|
|
84
95
|
Setup the categories and store them in ``self.categories = {}``
|
85
96
|
Pass the question data to the categories.
|
86
97
|
"""
|
98
|
+
sheetPath = sheetPath if sheetPath else self.spreadsheet
|
87
99
|
logger.info("Start Parsing the Excel Metadata Sheet\n")
|
88
100
|
with Path(sheetPath).open("rb") as f:
|
89
101
|
settingDf = pd.read_excel(
|
@@ -111,17 +123,28 @@ class QuestionDB:
|
|
111
123
|
) -> None:
|
112
124
|
settings = self.harmonizeDFIndex(settings)
|
113
125
|
for tag, value in settings.iterrows():
|
114
|
-
|
115
|
-
|
116
|
-
|
126
|
+
value = value.iloc[0]
|
127
|
+
if tag == Tags.TOLERANCE:
|
128
|
+
tol = value if value <= 1 else value / 100
|
129
|
+
self.settings.set(Tags.TOLERANCE, tol)
|
130
|
+
else:
|
131
|
+
self.settings.set(tag, value)
|
132
|
+
if Tags.IMPORTMODULE in settings.index:
|
117
133
|
logger.warning(
|
118
134
|
"Appending: %s to sys.path. All names defined by it will be usable",
|
119
135
|
mainPath,
|
120
136
|
)
|
121
137
|
sys.path.append(str(mainPath))
|
138
|
+
imgFolder = self.settings.get(Tags.SPREADSHEETPATH).parent / self.settings.get(
|
139
|
+
Tags.PICTURESUBFOLDER
|
140
|
+
)
|
141
|
+
if Tags.PICTURESUBFOLDER not in settings.index:
|
142
|
+
logger.warning("You didn't specify an image Folder. This may cause errors.")
|
143
|
+
self.settings.set(Tags.PICTUREFOLDER, imgFolder.resolve())
|
122
144
|
|
123
|
-
def initAllCategories(self, sheetPath: Path) -> None:
|
145
|
+
def initAllCategories(self, sheetPath: Path | None = None) -> None:
|
124
146
|
"""Read all category sheets and initialize all Categories."""
|
147
|
+
sheetPath = sheetPath if sheetPath else self.spreadsheet
|
125
148
|
if not hasattr(self, "categoriesMetaData"):
|
126
149
|
logger.error("Can't process the Categories without Metadata")
|
127
150
|
return
|
@@ -133,14 +156,15 @@ class QuestionDB:
|
|
133
156
|
for categoryName in excelFile.sheet_names:
|
134
157
|
logger.debug("Starting to read category %s", categoryName)
|
135
158
|
if categoryName in self.categoriesMetaData.index:
|
136
|
-
self.initCategory(
|
159
|
+
self.initCategory(categoryName, sheetPath=sheetPath)
|
137
160
|
|
138
|
-
def asyncInitAllCategories(self, sheetPath: Path) -> None:
|
161
|
+
def asyncInitAllCategories(self, sheetPath: Path | None = None) -> None:
|
139
162
|
"""Read all category sheets asynchron and initialize all Categories.
|
140
163
|
|
141
164
|
It does the same as `initAllCategories` but the parsing of the excelfile
|
142
165
|
is done asynchron via `concurrent.futures.ProcessPoolExecutor`
|
143
166
|
"""
|
167
|
+
sheetPath = sheetPath if sheetPath else self.spreadsheet
|
144
168
|
if not hasattr(self, "categoriesMetaData"):
|
145
169
|
logger.error("Can't process the Categories without Metadata")
|
146
170
|
return
|
@@ -171,10 +195,13 @@ class QuestionDB:
|
|
171
195
|
logger.exception("Error processing sheet %s: %s", categoryName, e)
|
172
196
|
logger.debug("Future exception: %s", future.exception())
|
173
197
|
|
174
|
-
def initCategory(
|
198
|
+
def initCategory(
|
199
|
+
self, categoryName: str, sheetPath: Path | None = None
|
200
|
+
) -> bool | Category:
|
175
201
|
"""Read `categoryName` from the ``sheetPath`` and initialize the category.
|
176
202
|
Returns the Category and appends it to `self.categories`.
|
177
203
|
"""
|
204
|
+
sheetPath = sheetPath if sheetPath else self.spreadsheet
|
178
205
|
katDf = pd.read_excel(
|
179
206
|
sheetPath,
|
180
207
|
sheet_name=str(categoryName),
|
excel2moodle/core/question.py
CHANGED
@@ -139,12 +139,12 @@ class Question:
|
|
139
139
|
def assemble(self, variant=0) -> None:
|
140
140
|
"""Assemble the question to the valid xml Tree."""
|
141
141
|
mainText = self._getTextElement()
|
142
|
-
textParts = self._assembleMainTextParts()
|
143
142
|
self.logger.debug("Starting assembly")
|
144
|
-
if hasattr(self, "picture") and self.picture.ready:
|
145
|
-
self._appendPicture(textParts, mainText)
|
146
|
-
self.logger.debug("inserted MainText to element")
|
147
143
|
self._setAnswerElement(variant=variant)
|
144
|
+
textParts = self._assembleMainTextParts()
|
145
|
+
if hasattr(self, "picture") and self.picture.ready:
|
146
|
+
mainText.append(self.picture.element)
|
147
|
+
self.logger.debug("Appended Picture element to text")
|
148
148
|
mainText.append(etHelpers.getCdatTxtElement(textParts))
|
149
149
|
|
150
150
|
def _assembleMainTextParts(self, variant=0) -> list[ET.Element]:
|
@@ -152,11 +152,15 @@ class Question:
|
|
152
152
|
|
153
153
|
Intended for the cloze question, where the answers parts are part of the text.
|
154
154
|
"""
|
155
|
+
self.logger.debug("inserting MainText to element")
|
155
156
|
textParts: list[ET.Element] = []
|
156
157
|
textParts.extend(self.qtextParagraphs)
|
157
158
|
bullets = self._getBPoints(variant=variant)
|
158
159
|
if bullets is not None:
|
159
160
|
textParts.append(bullets)
|
161
|
+
if hasattr(self, "picture") and self.picture.ready:
|
162
|
+
textParts.append(self.picture.htmlTag)
|
163
|
+
self.logger.debug("Appended Picture html to text")
|
160
164
|
return textParts
|
161
165
|
|
162
166
|
def _getTextElement(self) -> ET.Element:
|
@@ -171,10 +175,6 @@ class Question:
|
|
171
175
|
msg = "Cant assamble, if element is none"
|
172
176
|
raise QNotParsedException(msg, self.id)
|
173
177
|
|
174
|
-
def _appendPicture(self, textParts: list[ET.Element], mainText: ET.Element) -> None:
|
175
|
-
textParts.append(self.picture.htmlTag)
|
176
|
-
mainText.append(self.picture.element)
|
177
|
-
|
178
178
|
def _getBPoints(self, variant: int = 0) -> ET.Element:
|
179
179
|
if hasattr(self, "bulletList"):
|
180
180
|
return self.bulletList
|
excel2moodle/core/settings.py
CHANGED
@@ -5,10 +5,6 @@ from enum import StrEnum
|
|
5
5
|
from pathlib import Path
|
6
6
|
from typing import ClassVar, Literal, overload
|
7
7
|
|
8
|
-
from PySide6.QtCore import QSettings, QTimer, Signal
|
9
|
-
|
10
|
-
import excel2moodle
|
11
|
-
|
12
8
|
logger = logging.getLogger(__name__)
|
13
9
|
|
14
10
|
|
@@ -64,7 +60,7 @@ class Tags(StrEnum):
|
|
64
60
|
"""Get type of the keys data."""
|
65
61
|
return self._typ_
|
66
62
|
|
67
|
-
QUESTIONVARIANT = "defaultQuestionVariant", int,
|
63
|
+
QUESTIONVARIANT = "defaultQuestionVariant", int, 1, "testgen"
|
68
64
|
INCLUDEINCATS = "includeCats", bool, False, "testgen"
|
69
65
|
TOLERANCE = "tolerance", float, 0.01, "parser/nf"
|
70
66
|
PICTUREFOLDER = "pictureFolder", Path, None, "core"
|
@@ -83,7 +79,7 @@ class Tags(StrEnum):
|
|
83
79
|
NAME = "name", str, None
|
84
80
|
RESULT = "result", float, None
|
85
81
|
EQUATION = "formula", str, None
|
86
|
-
PICTURE = "picture", str,
|
82
|
+
PICTURE = "picture", str, None
|
87
83
|
NUMBER = "number", int, None
|
88
84
|
ANSTYPE = "answertype", str, None
|
89
85
|
QUESTIONPART = "part", list, None
|
@@ -93,36 +89,26 @@ class Tags(StrEnum):
|
|
93
89
|
PICTUREWIDTH = "imgwidth", int, 500
|
94
90
|
ANSPICWIDTH = "answerimgwidth", int, 120
|
95
91
|
WRONGSIGNPERCENT = "wrongsignpercentage", int, 50
|
96
|
-
FIRSTRESULT = "firstresult", float,
|
97
|
-
|
92
|
+
FIRSTRESULT = "firstresult", float, 0
|
98
93
|
|
99
|
-
class Settings(QSettings):
|
100
|
-
"""Settings for Excel2moodle."""
|
101
94
|
|
102
|
-
|
103
|
-
|
95
|
+
class Settings:
|
96
|
+
values: ClassVar[dict[str, str | float | Path]] = {}
|
104
97
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
if excel2moodle.isMainState():
|
109
|
-
logger.info("Settings are stored under: %s", self.fileName())
|
110
|
-
if self.contains(Tags.SPREADSHEETPATH.full):
|
111
|
-
self.sheet = self.get(Tags.SPREADSHEETPATH)
|
112
|
-
if self.sheet.is_file():
|
113
|
-
QTimer.singleShot(300, self._emitSpreadsheetChanged)
|
114
|
-
|
115
|
-
def _emitSpreadsheetChanged(self) -> None:
|
116
|
-
self.shPathChanged.emit(self.sheet)
|
98
|
+
@classmethod
|
99
|
+
def clear(cls) -> None:
|
100
|
+
cls.values.clear()
|
117
101
|
|
118
102
|
@overload
|
103
|
+
@classmethod
|
119
104
|
def get(
|
120
|
-
|
105
|
+
cls,
|
121
106
|
key: Literal[Tags.POINTS],
|
122
107
|
) -> float: ...
|
123
108
|
@overload
|
109
|
+
@classmethod
|
124
110
|
def get(
|
125
|
-
|
111
|
+
cls,
|
126
112
|
key: Literal[
|
127
113
|
Tags.QUESTIONVARIANT,
|
128
114
|
Tags.TOLERANCE,
|
@@ -133,10 +119,12 @@ class Settings(QSettings):
|
|
133
119
|
],
|
134
120
|
) -> int: ...
|
135
121
|
@overload
|
136
|
-
|
122
|
+
@classmethod
|
123
|
+
def get(cls, key: Literal[Tags.INCLUDEINCATS]) -> bool: ...
|
137
124
|
@overload
|
125
|
+
@classmethod
|
138
126
|
def get(
|
139
|
-
|
127
|
+
cls,
|
140
128
|
key: Literal[
|
141
129
|
Tags.PICTURESUBFOLDER,
|
142
130
|
Tags.LOGLEVEL,
|
@@ -146,26 +134,28 @@ class Settings(QSettings):
|
|
146
134
|
],
|
147
135
|
) -> str: ...
|
148
136
|
@overload
|
137
|
+
@classmethod
|
149
138
|
def get(
|
150
|
-
|
139
|
+
cls,
|
151
140
|
key: Literal[Tags.PICTUREFOLDER, Tags.SPREADSHEETPATH],
|
152
141
|
) -> Path: ...
|
153
142
|
|
154
|
-
|
143
|
+
@classmethod
|
144
|
+
def get(cls, key: Tags):
|
155
145
|
"""Get the typesafe settings value.
|
156
146
|
|
157
|
-
If local Settings are stored, they are returned.
|
158
147
|
If no setting is made, the default value is returned.
|
159
148
|
"""
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
149
|
+
try:
|
150
|
+
raw = cls.values[key]
|
151
|
+
except KeyError:
|
152
|
+
default = key.default
|
153
|
+
if default is None:
|
154
|
+
return None
|
155
|
+
logger.info("Returning the default value for %s", key)
|
156
|
+
return default
|
167
157
|
if key.typ() is Path:
|
168
|
-
path: Path =
|
158
|
+
path: Path = Path(raw)
|
169
159
|
try:
|
170
160
|
path.resolve(strict=True)
|
171
161
|
except ValueError:
|
@@ -175,10 +165,7 @@ class Settings(QSettings):
|
|
175
165
|
return key.default
|
176
166
|
logger.debug("Returning path setting: %s = %s", key, path)
|
177
167
|
return path
|
178
|
-
raw = self.value(key.full, defaultValue=key.default, type=key.typ())
|
179
|
-
logger.debug("read a settings Value: %s of type: %s", key, key.typ())
|
180
168
|
try:
|
181
|
-
logger.debug("Returning global setting: %s = %s", key, raw)
|
182
169
|
return key.typ()(raw)
|
183
170
|
except (ValueError, TypeError):
|
184
171
|
logger.warning(
|
@@ -186,44 +173,25 @@ class Settings(QSettings):
|
|
186
173
|
)
|
187
174
|
return key.default
|
188
175
|
|
176
|
+
@classmethod
|
189
177
|
def set(
|
190
|
-
|
178
|
+
cls,
|
191
179
|
key: Tags | str,
|
192
180
|
value: float | bool | Path | str,
|
193
|
-
local: bool = False,
|
194
181
|
) -> None:
|
195
|
-
"""Set the setting to value.
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
if local:
|
208
|
-
if key in Tags:
|
209
|
-
type(self).localSettings[key] = value
|
210
|
-
logger.info("Saved the project setting %s = %s", key, value)
|
211
|
-
else:
|
212
|
-
logger.warning("got invalid local Setting %s = %s", key, value)
|
213
|
-
return
|
214
|
-
if not local and isinstance(key, Tags):
|
215
|
-
if not isinstance(value, key.typ()):
|
216
|
-
logger.error("trying to save setting with wrong type not possible")
|
182
|
+
"""Set the setting to value."""
|
183
|
+
if key in Tags:
|
184
|
+
tag = Tags(key) if not isinstance(key, Tags) else key
|
185
|
+
try:
|
186
|
+
cls.values[tag] = tag.typ()(value)
|
187
|
+
except TypeError:
|
188
|
+
logger.exception(
|
189
|
+
"trying to save %s = %s %s with wrong type not possible.",
|
190
|
+
tag,
|
191
|
+
value,
|
192
|
+
type(value),
|
193
|
+
)
|
217
194
|
return
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
def setSpreadsheet(self, sheet: Path) -> None:
|
222
|
-
"""Save spreadsheet path and emit the changed event."""
|
223
|
-
if isinstance(sheet, Path):
|
224
|
-
self.sheet = sheet.resolve(strict=True)
|
225
|
-
logpath = str(self.sheet.parent / "excel2moodleLogFile.log")
|
226
|
-
self.set(Tags.LOGFILE, logpath)
|
227
|
-
self.set(Tags.SPREADSHEETPATH, self.sheet)
|
228
|
-
self.shPathChanged.emit(sheet)
|
229
|
-
return
|
195
|
+
logger.info("Saved %s = %s, type %s", key, value, tag.typ())
|
196
|
+
else:
|
197
|
+
logger.warning("got invalid local Setting %s = %s", key, value)
|
excel2moodle/logger.py
CHANGED
@@ -6,10 +6,11 @@ This includes emitting the signals for the main Window, to fast forward all logs
|
|
6
6
|
|
7
7
|
import logging
|
8
8
|
|
9
|
-
from PySide6.QtCore import QObject, Signal
|
9
|
+
from PySide6.QtCore import QObject, QSettings, Signal
|
10
10
|
|
11
11
|
from excel2moodle.core.settings import Settings, Tags
|
12
12
|
|
13
|
+
qSettings = QSettings("jbosse3", "excel2moodle")
|
13
14
|
settings = Settings()
|
14
15
|
|
15
16
|
loggerConfig = {
|
@@ -36,7 +37,9 @@ loggerConfig = {
|
|
36
37
|
"formatter": "file",
|
37
38
|
"class": "logging.FileHandler",
|
38
39
|
# "class": "logging.handlers.TimedRotatingFileHandler",
|
39
|
-
"filename":
|
40
|
+
"filename": qSettings.value(
|
41
|
+
Tags.LOGFILE, defaultValue=Tags.LOGFILE.default
|
42
|
+
),
|
40
43
|
# "when": "M",
|
41
44
|
# "interval": 1,
|
42
45
|
# "backupCount": "3",
|
@@ -32,7 +32,7 @@ class ClozeQuestion(ParametricQuestion):
|
|
32
32
|
|
33
33
|
def _setAnswerElement(self, variant: int = 1) -> None:
|
34
34
|
for part, ans in self.answerVariants.items():
|
35
|
-
result = ans[variant]
|
35
|
+
result = ans[variant - 1]
|
36
36
|
if self.answerTypes.get(part, None) == "MC":
|
37
37
|
ansStr = ClozeQuestionParser.getMCAnsStr(answers)
|
38
38
|
else:
|
@@ -45,15 +45,15 @@ class NFMQuestionParser(QuestionParser):
|
|
45
45
|
super().__init__()
|
46
46
|
self.genFeedbacks = [XMLTags.GENFEEDB]
|
47
47
|
self.question: NFMQuestion
|
48
|
-
|
49
|
-
def setup(self, question: NFMQuestion) -> None:
|
50
|
-
self.question: NFMQuestion = question
|
51
|
-
super().setup(question)
|
52
48
|
module = self.settings.get(Tags.IMPORTMODULE)
|
53
49
|
if module and not type(self).astEval.symtable.get(module):
|
54
50
|
type(self).astEval(f"import {module}")
|
55
51
|
self.logger.warning("Imported '%s' to Asteval symtable", module)
|
56
52
|
|
53
|
+
def setup(self, question: NFMQuestion) -> None:
|
54
|
+
self.question: NFMQuestion = question
|
55
|
+
super().setup(question)
|
56
|
+
|
57
57
|
def _parseAnswers(self) -> None:
|
58
58
|
equation = self.rawInput.get(Tags.EQUATION)
|
59
59
|
bps = self.rawInput.get(Tags.BPOINTS)
|
excel2moodle/ui/appUi.py
CHANGED
@@ -8,7 +8,7 @@ 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
|
@@ -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()
|
@@ -43,16 +46,16 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
43
46
|
self.questionPreview = dialogs.QuestionPreview(self)
|
44
47
|
self.eqChecker = EqCheckerWindow()
|
45
48
|
self.connectEvents()
|
46
|
-
logger.info("Settings are stored under: %s", self.
|
49
|
+
logger.info("Settings are stored under: %s", self.qSettings.fileName())
|
47
50
|
self.ui.treeWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
48
51
|
self.ui.treeWidget.header().setSectionResizeMode(
|
49
52
|
QtWidgets.QHeaderView.ResizeToContents,
|
50
53
|
)
|
51
54
|
self.exportDialog.ui.checkBoxIncludeCategories.setChecked(
|
52
|
-
self.
|
55
|
+
self.qSettings.value(Tags.INCLUDEINCATS, defaultValue=True, type=bool)
|
53
56
|
)
|
54
57
|
self.exportDialog.ui.spinBoxDefaultQVariant.setValue(
|
55
|
-
self.
|
58
|
+
self.qSettings.value(Tags.QUESTIONVARIANT, defaultValue=1, type=int)
|
56
59
|
)
|
57
60
|
self.ui.pointCounter.setReadOnly(True)
|
58
61
|
self.ui.questionCounter.setReadOnly(True)
|
@@ -60,11 +63,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
60
63
|
"Wählen Sie eine Excel Tabelle mit den Fragen aus",
|
61
64
|
)
|
62
65
|
try:
|
63
|
-
self.resize(self.
|
64
|
-
self.move(self.
|
66
|
+
self.resize(self.qSettings.value("windowSize"))
|
67
|
+
self.move(self.qSettings.value("windowPosition"))
|
65
68
|
except Exception:
|
66
69
|
pass
|
67
70
|
self.threadPool = QThreadPool()
|
71
|
+
if self.qSettings.contains(Tags.SPREADSHEETPATH.full):
|
72
|
+
sheet = self.qSettings.value(Tags.SPREADSHEETPATH.full)
|
73
|
+
self.setSheetPath(sheet)
|
68
74
|
|
69
75
|
def connectEvents(self) -> None:
|
70
76
|
self.ui.treeWidget.itemSelectionChanged.connect(self.onSelectionChanged)
|
@@ -85,7 +91,6 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
85
91
|
self.ui.treeWidget.itemClicked.connect(self.updateQuestionPreview)
|
86
92
|
self.ui.actionAbout.triggered.connect(self.openAboutDlg)
|
87
93
|
self.ui.actionDocumentation.triggered.connect(self.openDocumentation)
|
88
|
-
self.settings.shPathChanged.connect(self.onSheetPathChanged)
|
89
94
|
self.exportDialog.ui.spinBoxDefaultQVariant.valueChanged.connect(
|
90
95
|
self.setQVariantDefault
|
91
96
|
)
|
@@ -103,19 +108,23 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
103
108
|
If successful it prints out a list of all exported Questions
|
104
109
|
"""
|
105
110
|
self.ui.treeWidget.clear()
|
111
|
+
self.testDB.readCategoriesMetadata()
|
106
112
|
process = ParseAllThread(self.testDB, self)
|
107
113
|
self.threadPool.start(process)
|
108
114
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
113
122
|
self.mainPath = sheet.parent
|
114
|
-
svgFolder = self.mainPath / self.settings.get(Tags.PICTURESUBFOLDER)
|
115
|
-
svgFolder.resolve()
|
116
|
-
self.settings.set(Tags.PICTUREFOLDER, svgFolder)
|
117
123
|
self.ui.buttonSpreadsheet.setText(f"../{sheet.name}")
|
124
|
+
self.testDB.spreadsheet = sheet
|
125
|
+
self.qSettings.setValue(Tags.SPREADSHEETPATH.full, sheet)
|
118
126
|
self.parseSpreadsheetAll()
|
127
|
+
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
119
128
|
|
120
129
|
def updateLog(self, log) -> None:
|
121
130
|
self.ui.loggerWindow.append(log)
|
@@ -127,8 +136,16 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
127
136
|
self.settings.set(Tags.INCLUDEINCATS, False)
|
128
137
|
|
129
138
|
def closeEvent(self, event) -> None:
|
130
|
-
|
131
|
-
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
|
+
)
|
132
149
|
|
133
150
|
@QtCore.Slot()
|
134
151
|
def onSelectionChanged(self, **args) -> None:
|
@@ -178,12 +195,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
178
195
|
selectedFilter=("*.ods"),
|
179
196
|
)
|
180
197
|
path = Path(file[0]).resolve(strict=True)
|
181
|
-
|
182
|
-
self.excelPath = path
|
183
|
-
self.settings.setSpreadsheet(self.excelPath)
|
184
|
-
self.setStatus("[OK] Excel Tabelle wurde eingelesen")
|
185
|
-
else:
|
186
|
-
self.setStatus("[ERROR] keine Tabelle angegeben")
|
198
|
+
self.setSheetPath(path)
|
187
199
|
|
188
200
|
@QtCore.Slot(Category)
|
189
201
|
def treeRefreshCategory(self, cat: Category) -> None:
|
@@ -247,7 +259,6 @@ class ParseAllThread(QRunnable):
|
|
247
259
|
|
248
260
|
@QtCore.Slot()
|
249
261
|
def run(self) -> None:
|
250
|
-
self.testDB.
|
251
|
-
self.testDB.asyncInitAllCategories(self.mainApp.spreadSheetPath)
|
262
|
+
self.testDB.asyncInitAllCategories(self.mainApp.excelPath)
|
252
263
|
self.mainApp.setStatus("[OK] Tabellen wurde eingelesen")
|
253
264
|
self.testDB.parseAllQuestions()
|
@@ -1,38 +1,38 @@
|
|
1
|
-
excel2moodle/__init__.py,sha256=
|
1
|
+
excel2moodle/__init__.py,sha256=mnb-RWgmWIPSBk4S65a_jP6rxntAkTeYxN0ObUJalbQ,1801
|
2
2
|
excel2moodle/__main__.py,sha256=sG4ygwfVFskLQorBn-v98SvasNcPmwl_vLYpruT5Hk8,1175
|
3
|
-
excel2moodle/logger.py,sha256=
|
3
|
+
excel2moodle/logger.py,sha256=S9tvSwsOx2xta_AhGKHPNgi5FaiycyUDtkzHlIlNAX8,3193
|
4
4
|
excel2moodle/core/__init__.py,sha256=87BwhtZse72Tk17Ib-V9X2k9wkhmtVnEj2ZmJ9JBAnI,63
|
5
5
|
excel2moodle/core/category.py,sha256=TzntDhEURshxWuI6qc_K_t5bSTLXn6s0n_RA56Basg8,1885
|
6
|
-
excel2moodle/core/dataStructure.py,sha256=
|
6
|
+
excel2moodle/core/dataStructure.py,sha256=Gg9dq4koJPAKj87YFItTCz8QlK743K8s_iflJjLWZyU,15535
|
7
7
|
excel2moodle/core/etHelpers.py,sha256=G37qplp8tPJxqHNCBrf2Wo0jJZ0aDbxE9slQavqYqd8,2293
|
8
8
|
excel2moodle/core/exceptions.py,sha256=9xfsaIcm6Yej6QAZga0d3DK3jLQejdfgJARuAaG-uZY,739
|
9
9
|
excel2moodle/core/globals.py,sha256=Zm1wcrzQTRnhjrkwgBvo7VjKCFdPMjh-VLSSI5_QCO8,2837
|
10
10
|
excel2moodle/core/numericMultiQ.py,sha256=vr-gYogu2sf2a_Bhvhnu1ZSZFZXM32MfhJesjTkoOQM,2618
|
11
11
|
excel2moodle/core/parser.py,sha256=Ec8bQ0CiiZCIdzQovfH2rce406wmyRmvhpDrCPeQfGU,8112
|
12
|
-
excel2moodle/core/question.py,sha256=
|
13
|
-
excel2moodle/core/settings.py,sha256=
|
12
|
+
excel2moodle/core/question.py,sha256=nJDs8SPDRYP6xG4rvo8Bbh1734eQ96DZxVXb7yrT8LM,10802
|
13
|
+
excel2moodle/core/settings.py,sha256=JhcgZcOrgFC7P4h9fSXZAApEl_9dE643r5arFpU1HXQ,5808
|
14
14
|
excel2moodle/core/stringHelpers.py,sha256=OzFZ6Eu3PeBLKb61K-aeVfUZmVuBerr9KfyOsuNRd7Y,2403
|
15
15
|
excel2moodle/core/validator.py,sha256=RwDQ-9Fpc5i2Buy3oorWUAh5zsS5fCF-MjRT4CgcXhY,4698
|
16
16
|
excel2moodle/extra/__init__.py,sha256=PM-id60HD21A3IcGC_fCYFihS8osBGZMIJCcN-ZRsIM,293
|
17
17
|
excel2moodle/extra/equationVerification.py,sha256=GLJl1r90d8AAiNy0H2hooZrg3D6aEwNfifYKAe3aGxM,3921
|
18
18
|
excel2moodle/question_types/__init__.py,sha256=81mss0g7SVtnlb-WkydE28G_dEAAf6oT1uB8lpK2-II,1041
|
19
|
-
excel2moodle/question_types/cloze.py,sha256=
|
19
|
+
excel2moodle/question_types/cloze.py,sha256=hgyv244PChnl7FbxcAMQiC4yzBhV6J3Bg4PHgZQyRmQ,7677
|
20
20
|
excel2moodle/question_types/mc.py,sha256=rHKIKSNeHyto84bI9B3wMKzNJuluplsCmYM4k2HW3wQ,5213
|
21
21
|
excel2moodle/question_types/nf.py,sha256=bMP4IXrhnXmAI0NmjEc7DtX4xGaUbxzLicE2LjeaUho,1150
|
22
|
-
excel2moodle/question_types/nfm.py,sha256=
|
22
|
+
excel2moodle/question_types/nfm.py,sha256=VYrQmCsEZqfn0x_coBsDw3XvrUA4sy_yj0WS7Nsffqw,4950
|
23
23
|
excel2moodle/ui/UI_equationChecker.py,sha256=evQDlqCHeooJcAnYjhFCyjlPhfknr7ULGKQwMmqQeJ4,8947
|
24
24
|
excel2moodle/ui/UI_exportSettingsDialog.py,sha256=71xxXEqtewN0ReMfJ5t4gbrX_Bf0VEuxJ_DIV7ZtH94,6045
|
25
25
|
excel2moodle/ui/UI_mainWindow.py,sha256=asWUmKIYqufKUvRuCuA1JoMyv4qfRXyoR70F0331lww,19291
|
26
26
|
excel2moodle/ui/UI_variantDialog.py,sha256=snVaF3_YAc7NWjMRg7NzbjL_PzNbOpt4eiqElkE46io,5414
|
27
27
|
excel2moodle/ui/__init__.py,sha256=4EdGtpzwH3rgw4xW9E5x9kdPQYwKbo9rehHRZTNxCrQ,44
|
28
|
-
excel2moodle/ui/appUi.py,sha256=
|
28
|
+
excel2moodle/ui/appUi.py,sha256=NXlBcjxHBeUzpU8rvqwN3wxad8AUgpMjXidwwVdC9GM,10863
|
29
29
|
excel2moodle/ui/dialogs.py,sha256=JbQ1y55wbzWVTY0nxdGrUm81AdOIY3PXKgET03Hc6Ys,6760
|
30
30
|
excel2moodle/ui/equationChecker.py,sha256=ANpN7S0llkp6pGL1sKHII1Jc8YUvgDR458UnGVnZZOo,2702
|
31
31
|
excel2moodle/ui/treewidget.py,sha256=az64swVj1yQUsioeaZys32AauvQDdC4EKcqdbbWgL6s,2489
|
32
32
|
excel2moodle/ui/windowDoc.py,sha256=WvzHj6F4JvHP82WlTsyFeOXW024Xq3BUqtp--T4twuI,661
|
33
|
-
excel2moodle-0.4.
|
34
|
-
excel2moodle-0.4.
|
35
|
-
excel2moodle-0.4.
|
36
|
-
excel2moodle-0.4.
|
37
|
-
excel2moodle-0.4.
|
38
|
-
excel2moodle-0.4.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|