Skip to content
This repository was archived by the owner on Aug 29, 2024. It is now read-only.

Commit 2c7f444

Browse files
committed
Calculate results from grades panel & previous gpa and display them
1 parent 18c202f commit 2c7f444

File tree

5 files changed

+137
-29
lines changed

5 files changed

+137
-29
lines changed

moadaly/common_conversions.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,41 @@
11
"""Some common conversions."""
2+
from gettext import gettext as _
3+
4+
5+
grades = [
6+
_("Undefined"),
7+
_("A+"),
8+
_("A"),
9+
_("B+"),
10+
_("B"),
11+
_("C+"),
12+
_("C"),
13+
_("D+"),
14+
_("D"),
15+
_("F"),
16+
]
17+
18+
19+
def get_grade_from_gpa(gpa: float) -> str:
20+
"""Convert the gpa to a grade."""
21+
if gpa >= 4.75:
22+
return grades[1]
23+
elif gpa >= 4.5:
24+
return grades[2]
25+
elif gpa >= 4.0:
26+
return grades[3]
27+
elif gpa >= 3.5:
28+
return grades[4]
29+
elif gpa >= 3.0:
30+
return grades[5]
31+
elif gpa >= 2.5:
32+
return grades[6]
33+
elif gpa >= 2.0:
34+
return grades[7]
35+
elif gpa >= 1.0:
36+
return grades[8]
37+
else:
38+
return grades[9]
239

340

441
def get_grade_from_score(score: float) -> int:

moadaly/ui/grades_panel.py

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,17 @@
1010
class GradesPanel(QtWidgets.QWidget):
1111
"""A panel to display semesters, and to handle the addition of new semesters."""
1212

13+
panel_calculation_changed = QtCore.Signal()
14+
1315
def __init__(self):
1416
"""Initialize base components of the panel."""
1517
super().__init__()
1618

1719
self.semesters = []
1820

21+
self.total_points = 0.0
22+
self.total_credits = 0
23+
1924
self.layout = QtWidgets.QVBoxLayout(self)
2025

2126
self.scroll_area = QtWidgets.QScrollArea()
@@ -38,16 +43,31 @@ def __init__(self):
3843
self.scroll_area.setFixedHeight(500)
3944
self.scroll_area.setWidget(self)
4045

46+
def calculate_panel(self) -> None:
47+
"""Calculate the sum of the semesters points and credit units."""
48+
self.total_points = 0.0
49+
self.total_credits = 0
50+
51+
for semester in self.semesters:
52+
self.total_points += semester.total_points
53+
self.total_credits += semester.total_credits
54+
55+
# Send a signal with the new points and credits to be displayed.
56+
self.panel_calculation_changed.emit()
57+
4158
def add_new_semester(self):
4259
"""Add new semester widget to the grades panel."""
43-
widget = SemesterWidget(self)
44-
self.semesters.append(widget)
45-
self.layout.insertWidget(len(self.semesters) - 1, widget)
60+
semester = SemesterWidget(self)
61+
semester.semester_calculation_updated.connect(self.calculate_panel)
62+
self.semesters.append(semester)
63+
self.layout.insertWidget(len(self.semesters) - 1, semester)
4664

4765

4866
class SemesterWidget(QtWidgets.QWidget):
4967
"""A semester that contain a list of corses, to be added to the grades panel."""
5068

69+
semester_calculation_updated = QtCore.Signal()
70+
5171
def __init__(self, parent_panel):
5272
"""Initialize a new semester and it's base components."""
5373
super().__init__()
@@ -56,6 +76,9 @@ def __init__(self, parent_panel):
5676
self.semester_id: str = uuid4().hex
5777
self.courses = []
5878

79+
self.total_points = 0.0
80+
self.total_credits = 0
81+
5982
self.layout = QtWidgets.QVBoxLayout(self)
6083

6184
# Create the semester title bar.
@@ -117,6 +140,19 @@ def __init__(self, parent_panel):
117140
add_course_button.clicked.connect(self.add_new_course)
118141
self.layout.addWidget(add_course_button)
119142

143+
def calculate_semester(self) -> None:
144+
"""Calculate the sum of points and the sum of credits in the semester."""
145+
self.total_points = 0.0
146+
self.total_credits = 0
147+
148+
# TODO Display the semester GPA, credit units and points in the GUI.
149+
for course in self.courses:
150+
self.total_points += course.points.value()
151+
self.total_credits += course.credit.value()
152+
153+
# Send signal to recalculate panel.
154+
self.semester_calculation_updated.emit()
155+
120156
def delete_semester(self):
121157
"""Remove a specified semester from the grades panel."""
122158
semester_index = self.parent_panel.semesters.index(self)
@@ -126,16 +162,23 @@ def delete_semester(self):
126162
for i in range(semester_index, len(self.parent_panel.semesters)):
127163
self.parent_panel.semesters[i].title.setText(_("Semester %d") % (i + 1))
128164

165+
# Send signal to recalculate panel.
166+
# FIXME When it is the last semester in the panel, results will not be updated.
167+
self.semester_calculation_updated.emit()
168+
129169
def add_new_course(self):
130170
"""Add new course widget to the semester."""
131-
widget = CourseWidget(self)
132-
self.courses.append(widget)
133-
self.layout.insertWidget(len(self.courses) + 1, widget)
171+
course = CourseWidget(self)
172+
course.points_changed.connect(self.calculate_semester)
173+
self.courses.append(course)
174+
self.layout.insertWidget(len(self.courses) + 1, course)
134175

135176

136177
class CourseWidget(QtWidgets.QWidget):
137178
"""A course that can be added inside a semester."""
138179

180+
points_changed = QtCore.Signal()
181+
139182
def __init__(self, parent_semester):
140183
"""Initialize a new course and it's components."""
141184
super().__init__()
@@ -172,28 +215,15 @@ def __init__(self, parent_semester):
172215
self.layout.addWidget(self.credit)
173216

174217
self.grade = QtWidgets.QComboBox()
175-
self.grade.addItems(
176-
[
177-
_("Undefined"),
178-
_("A+"),
179-
_("A"),
180-
_("B+"),
181-
_("B"),
182-
_("C+"),
183-
_("C"),
184-
_("D+"),
185-
_("D"),
186-
_("F"),
187-
]
188-
)
218+
self.grade.addItems(common_conversions.grades)
189219
self.grade.currentIndexChanged.connect(self.grade_changed)
190220
self.layout.addWidget(self.grade)
191221

192222
self.points = QtWidgets.QDoubleSpinBox()
193223
self.points.setReadOnly(True)
194224
self.points.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
195225
self.points.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
196-
self.points.setMaximum(1000)
226+
self.points.setMaximum(10000)
197227
self.layout.addWidget(self.points)
198228

199229
self.delete_course_button = QtWidgets.QPushButton(
@@ -210,6 +240,9 @@ def update_points(self) -> None:
210240
* self.credit.value()
211241
)
212242

243+
# Send signal to recalculate semester.
244+
self.points_changed.emit()
245+
213246
def score_changed(self) -> None:
214247
"""Change the grade when the score is changed."""
215248
try:
@@ -245,3 +278,7 @@ def delete_course(self):
245278

246279
for i in range(course_index, len(self.parent_semester.courses)):
247280
self.parent_semester.courses[i].title.setText(_("Course %d") % (i + 1))
281+
282+
# Send signal to recalculate semester.
283+
# FIXME When it is the last course in the semester, results will not be updated.
284+
self.points_changed.emit()

moadaly/ui/main.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,19 @@ def __init__(self):
3636

3737
# Create main window widgets.
3838
self.result_box = result_box.ResultBox()
39-
self.previous_gpa_box = previous_cgpa_box.PreviousCGPABox()
39+
self.previous_cgpa_box = previous_cgpa_box.PreviousCGPABox()
4040
self.calculation_system_box = (
4141
calculation_system_options_box.CalculationSystemBox()
4242
)
4343
self.grades_panel = grades_panel.GradesPanel()
4444

45+
# Listen to signals when the calculation is updated.
46+
self.grades_panel.panel_calculation_changed.connect(self.update_results)
47+
self.previous_cgpa_box.previous_points_changed.connect(self.update_results)
48+
4549
# Add main components to the main window layout.
4650
top_panel_layout.addWidget(self.result_box)
47-
top_panel_layout.addWidget(self.previous_gpa_box)
51+
top_panel_layout.addWidget(self.previous_cgpa_box)
4852
top_panel_layout.addWidget(self.calculation_system_box)
4953
bottom_panel_layout.addWidget(self.grades_panel.scroll_area)
5054

@@ -58,6 +62,16 @@ def __init__(self):
5862

5963
self.create_menu_bar()
6064

65+
def update_results(self):
66+
"""Update the results in the result widget."""
67+
# Get the results from the grades panel and the previous gpa widget.
68+
self.result_box.display_new_calculation(
69+
self.grades_panel.total_points
70+
+ self.previous_cgpa_box.previous_points.value(),
71+
self.grades_panel.total_credits
72+
+ self.previous_cgpa_box.previous_credit.value(),
73+
)
74+
6175
def create_menu_bar(self):
6276
"""Create all the menu bar components and actions."""
6377
self.menu_bar = self.menuBar()

moadaly/ui/previous_cgpa_box.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
class PreviousCGPABox(QtWidgets.QWidget):
88
"""A Group Box where you can specify a previous CGPA, to add it to the calculation."""
99

10+
previous_points_changed = QtCore.Signal()
11+
1012
def __init__(self):
1113
"""Initialize components of the previous CGPA widget."""
1214
super().__init__()
@@ -42,6 +44,7 @@ def __init__(self):
4244
self.previous_points.setReadOnly(True)
4345
self.previous_points.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
4446
self.previous_points.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
47+
self.previous_points.setMaximum(10000)
4548
self.previous_points.setDecimals(3)
4649
group_box_layout.addRow(
4750
QtWidgets.QLabel(_("Previous Points")), self.previous_points
@@ -52,3 +55,5 @@ def update_previous_points(self) -> None:
5255
self.previous_points.setValue(
5356
self.previous_cgpa.value() * self.previous_credit.value()
5457
)
58+
59+
self.previous_points_changed.emit()

moadaly/ui/result_box.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
from PySide6 import QtCore, QtWidgets
55

6+
from .. import common_conversions
7+
68

79
class ResultBox(QtWidgets.QWidget):
810
"""A Group Box where the results are displayed, such as, GPA, grade, total hours and points."""
@@ -30,16 +32,18 @@ def __init__(self):
3032
group_box_layout.addRow(QtWidgets.QLabel(_("CGPA:")), self.result_gpa)
3133

3234
# Result hours.
33-
self.result_hours = QtWidgets.QSpinBox()
34-
self.result_hours.setReadOnly(True)
35-
self.result_hours.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
36-
self.result_hours.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
37-
self.result_hours.setStyleSheet(
35+
self.result_credits = QtWidgets.QSpinBox()
36+
self.result_credits.setReadOnly(True)
37+
self.result_credits.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
38+
self.result_credits.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
39+
self.result_credits.setStyleSheet(
3840
"""
3941
font: bold;
4042
"""
4143
)
42-
group_box_layout.addRow(QtWidgets.QLabel(_("Hours:")), self.result_hours)
44+
group_box_layout.addRow(
45+
QtWidgets.QLabel(_("Credit Units:")), self.result_credits
46+
)
4347

4448
# Result points.
4549
self.result_points = QtWidgets.QDoubleSpinBox()
@@ -66,3 +70,14 @@ def __init__(self):
6670
group_box_layout.addRow(QtWidgets.QLabel(_("Grade:")), self.result_grade)
6771

6872
group_box.setLayout(group_box_layout)
73+
74+
def display_new_calculation(self, points, credits) -> None:
75+
"""Display the new results."""
76+
if credits:
77+
cgpa = points / credits
78+
self.result_gpa.setValue(cgpa)
79+
self.result_credits.setValue(credits)
80+
self.result_points.setValue(points)
81+
# FIXME The grade is displayed "A+" while it should be "A"
82+
# when the points are exactly 4.75 and the credits are 1.
83+
self.result_grade.setText(common_conversions.get_grade_from_gpa(cgpa))

0 commit comments

Comments
 (0)