made ChoiceQuestions a bit more flexible

This commit is contained in:
Faraphel 2023-12-23 21:03:58 +01:00
parent f9953a3cbb
commit 025ee52946
3 changed files with 147 additions and 35 deletions

View file

@ -12,12 +12,16 @@ class MultipleChoiceQuestion(BaseSurvey):
self, self,
title: str, title: str,
choices: dict[Any, str], choices: dict[Any, str],
other_choice: bool = None, details_choice_enabled: bool = None,
details_choice_id: str = None,
details_choice_text: str = None,
signals: dict[str, pyqtSignal] = None signals: dict[str, pyqtSignal] = None
): ):
super().__init__() super().__init__()
self.other_choice = other_choice if other_choice is not None else None self.details_choice_enabled = details_choice_enabled if details_choice_enabled is not None else None
self.details_choice_id = details_choice_id if details_choice_id is not None else None
self.details_choice_text = details_choice_text if details_choice_text is not None else None
self.signals = signals if signals is not None else {} self.signals = signals if signals is not None else {}
# set layout # set layout
@ -55,11 +59,11 @@ class MultipleChoiceQuestion(BaseSurvey):
# save the button # save the button
self.button_responses[choice_id] = button self.button_responses[choice_id] = button
if self.other_choice: if self.details_choice_enabled:
self.button_response_other = QCheckBox() self.button_response_other = QCheckBox()
self._layout_responses.addWidget(self.button_response_other) self._layout_responses.addWidget(self.button_response_other)
self.button_response_other.setText("Autre") self.button_response_other.setText(self.details_choice_text)
self.button_response_other.clicked.connect(self._on_response_other_check) # NOQA: connect exist self.button_response_other.toggled.connect(self._on_response_other_check) # NOQA: connect exist
self.entry_response_other = QLineEdit() self.entry_response_other = QLineEdit()
self._layout_responses.addWidget(self.entry_response_other) self._layout_responses.addWidget(self.entry_response_other)
@ -70,7 +74,9 @@ class MultipleChoiceQuestion(BaseSurvey):
return cls( return cls(
title=data["title"], title=data["title"],
choices=data["choices"], choices=data["choices"],
other_choice=data.get("other_choice"), details_choice_enabled=data.get("details_choice_enabled"),
details_choice_id=data.get("details_choice_id"),
details_choice_text=data.get("details_choice_text"),
signals=signals, signals=signals,
) )
@ -85,10 +91,16 @@ class MultipleChoiceQuestion(BaseSurvey):
self.entry_response_other.setEnabled(self.button_response_other.isChecked()) self.entry_response_other.setEnabled(self.button_response_other.isChecked())
def get_collected_data(self) -> dict: def get_collected_data(self) -> dict:
return { collected_data = {
"choice": {choice_id: button.isChecked() for choice_id, button in self.button_responses.items()}, "choice": [
"other": ( choice_id
self.entry_response_other.text() if self.other_choice and self.button_response_other.isChecked() for choice_id, button in self.button_responses.items()
else None if button.isChecked()
) ]
} }
if self.details_choice_enabled:
collected_data["choice"].append(self.details_choice_id)
collected_data["other"] = self.entry_response_other.text()
return collected_data

View file

@ -2,15 +2,30 @@ from typing import Any
from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtCore import Qt, pyqtSignal
from PyQt6.QtGui import QFont from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import QFrame, QVBoxLayout, QLabel, QRadioButton, QButtonGroup from PyQt6.QtWidgets import QFrame, QVBoxLayout, QLabel, QRadioButton, QButtonGroup, QLineEdit, QAbstractButton
from source.survey.base import BaseSurvey from source.survey.base import BaseSurvey
class SingleChoiceQuestion(BaseSurvey): class SingleChoiceQuestion(BaseSurvey):
def __init__(self, title: str, choices: dict[Any, str], signals: dict[str, pyqtSignal]): def __init__(
self,
title: str,
details_choice_enabled: bool = None,
details_choice_id: str = None,
details_choice_text: str = None,
choices: dict[Any, str] = None,
signals: dict[str, pyqtSignal] = None
):
super().__init__() super().__init__()
self.details_choice_enabled = details_choice_enabled if details_choice_enabled is not None else None
self.details_choice_id = details_choice_id if details_choice_id is not None else None
self.details_choice_text = details_choice_text if details_choice_text is not None else None
choices = choices if choices is not None else {}
signals = signals if signals is not None else {}
# set layout # set layout
self._layout = QVBoxLayout() self._layout = QVBoxLayout()
self.setLayout(self._layout) self.setLayout(self._layout)
@ -39,7 +54,7 @@ class SingleChoiceQuestion(BaseSurvey):
# checking any button allow the user to go to the next step # checking any button allow the user to go to the next step
self.group_responses.buttonClicked.connect(signals["success"].emit) # NOQA: connect and emit exists self.group_responses.buttonClicked.connect(signals["success"].emit) # NOQA: connect and emit exists
self.button_responses_id: dict[QRadioButton, str] = {} self.button_responses_id: dict[QAbstractButton, str] = {}
for choice_id, choice_text in choices.items(): for choice_id, choice_text in choices.items():
# create a radio button for that choice # create a radio button for that choice
@ -53,16 +68,43 @@ class SingleChoiceQuestion(BaseSurvey):
self.group_responses.addButton(button) self.group_responses.addButton(button)
self.button_responses_id[button] = choice_id self.button_responses_id[button] = choice_id
if self.details_choice_enabled:
self.button_response_other = QRadioButton()
self._layout_responses.addWidget(self.button_response_other)
self.button_responses_id[self.button_response_other] = self.details_choice_id
self.button_response_other.setText(self.details_choice_text)
self.group_responses.addButton(self.button_response_other)
self.button_response_other.toggled.connect(self._on_response_other_check) # NOQA: connect exist
self.entry_response_other = QLineEdit()
self._layout_responses.addWidget(self.entry_response_other)
self.entry_response_other.setEnabled(False)
@classmethod @classmethod
def from_dict(cls, data: dict[str, Any], signals: dict[str, pyqtSignal]) -> "SingleChoiceQuestion": def from_dict(cls, data: dict[str, Any], signals: dict[str, pyqtSignal]) -> "SingleChoiceQuestion":
return cls( return cls(
title=data["title"], title=data["title"],
choices=data["choices"], choices=data["choices"],
details_choice_enabled=data.get("details_choice_enabled"),
details_choice_id=data.get("details_choice_id"),
details_choice_text=data.get("details_choice_text"),
signals=signals, signals=signals,
) )
def get_collected_data(self) -> dict: def get_collected_data(self) -> dict:
return { checked_button = self.group_responses.checkedButton()
"choice": self.button_responses_id[self.group_responses.checkedButton()]
collected_data = {
"choice": self.button_responses_id[checked_button] if checked_button is not None else None,
} }
if self.details_choice_enabled:
collected_data["other"] = self.entry_response_other.text()
return collected_data
def _on_response_other_check(self):
# refresh the other entry response status
self.entry_response_other.setEnabled(self.button_response_other.isChecked())

View file

@ -1,25 +1,66 @@
{ {
"surveys": { "surveys": {
"text-welcome": {
"welcome": {
"type": "text", "type": "text",
"title": "Bienvenue !", "title": "Bienvenue !",
"description": "Nous réalisons une étude sur le logiciel Steam afin de déterminer son ergonomie.\nVous serez invité à naviguer sur la plateforme Steam d'une page à l'autre.", "description": "Salut ...",
"abandonable": true "abandonable": true
}, },
"question-usage": { "age": {
"type": "question-integer",
"title": "Quel est votre âge ?",
"default": 30,
"minimum": 13,
"maximum": 150
},
"usage-steam": {
"type": "question-single-choice", "type": "question-single-choice",
"title": "A quel point êtes-vous familier avec Steam ?", "title": "Utilisez-vous Steam ?",
"choices": { "choices": {
"0": "Ne connait pas", "always": "Tout le temps",
"1": "Connait de nom", "often": "Souvent",
"2": "Utilisation rare", "sometime": "De temps en temps",
"3": "Utilisation moyenne", "rarely": "Rarement",
"4": "Utilisation fréquente" "never": "Jamais"
} }
}, },
"web-language": { "usage-concurrent": {
"type": "question-multiple-choice",
"title": "Quel autre plateforme de jeu en ligne utilisez-vous ?",
"choices": {
"epic": "Epic Games Store",
"gog": "GOG",
"origin": "Origin",
"uplay": "Uplay",
"battle": "Battle.net"
},
"details_choice_enabled": true,
"details_choice_id": "other",
"details_choice_text": "Autre"
},
"difficulty-before": {
"type": "question-single-choice",
"title": "Avez-vous déjà rencontré des difficultés particulières lors de votre utilisation de Steam ?",
"choices": {
"no": "Non"
},
"details_choice_enabled": true,
"details_choice_id": "yes",
"details_choice_text": "Oui"
},
"mission-explanation": {
"type": "text",
"title": "Explication de l'Evaluation",
"description": "Vous allez devoir naviguer dans steam ..."
},
"mission-language": {
"type": "mission-web", "type": "mission-web",
"title": "Changer la langue en français.", "title": "Changer la langue en français.",
"url": "https://steampowered.com/", "url": "https://steampowered.com/",
@ -27,18 +68,35 @@
"skip_time": 60 "skip_time": 60
}, },
"web-point-shop": {
"type": "mission-web",
"title": "Rendez-vous sur la boutique des points.",
"url": "https://steampowered.com/",
"check": "true",
"skip_time": 90
},
"question-experience": { "question-experience": {
"type": "question-text", "type": "question-text",
"title": "Qu'avez vous pensé de l'interface de Steam ?" "title": "Qu'avez vous pensé de l'interface de Steam ?"
},
"difficulty-after": {
"type": "question-single-choice",
"title": "Avez-vous rencontré des difficultés particulières lors de ce test ?",
"choices": {
"no": "Non"
},
"details_choice_enabled": true,
"details_choice_id": "yes",
"details_choice_text": "Oui"
},
"hardest-mission": {
"type": "question-single-choice",
"title": "Parmi les tâches, laquelle avez-vous trouvée la plus difficile ?",
"choices": {
"mission-language": "Changer la langue"
}
},
"comment": {
"type": "question-text",
"title": "Vous pouvez laisser un commentaire sur votre ressenti général (optionnel)"
} }
} }
} }