1 /***************************************************************************
2 studentsstatisticform.cpp - description
3 -------------------
4 begin : March 25, 2006
5 copyright : (C) 2006 by Lalescu Liviu
6 email : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software: you can redistribute it and/or modify *
12 * it under the terms of the GNU Affero General Public License as *
13 * published by the Free Software Foundation, either version 3 of the *
14 * License, or (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "studentsstatisticsform.h"
19
20 #include "timetable_defs.h"
21 #include "timetable.h"
22
23 #include "fet.h"
24
25 #include "messageboxes.h"
26
27 #include "longtextmessagebox.h"
28
29 #include <Qt>
30
31 #include <QString>
32 #include <QStringList>
33
34 #include <QHash>
35
36 #include <QProgressDialog>
37
38 #include <QMessageBox>
39 #include <QApplication>
40
41 #include <QHeaderView>
42 #include <QTableWidget>
43
44 extern QApplication* pqapplication;
45
StudentsStatisticsForm(QWidget * parent)46 StudentsStatisticsForm::StudentsStatisticsForm(QWidget* parent): QDialog(parent)
47 {
48 setupUi(this);
49
50 closeButton->setDefault(true);
51
52 connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
53
54 tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
55 tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
56
57 centerWidgetOnScreen(this);
58 restoreFETDialogGeometry(this);
59
60 connect(showYearsCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxesModified()));
61 connect(showGroupsCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxesModified()));
62 connect(showSubgroupsCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxesModified()));
63
64 connect(showCompleteStructureCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkBoxesModified()));
65
66 //2014-12-18
67 QSet<StudentsYear*> allYears;
68 QSet<StudentsGroup*> allGroups;
69 QSet<StudentsSubgroup*> allSubgroups;
70
71 QHash<QString, StudentsYear*> yearsHash;
72 QHash<QString, StudentsGroup*> groupsHash;
73 QHash<QString, StudentsSubgroup*> subgroupsHash;
74
75 QHash<StudentsYear*, QSet<Activity*>> activitiesForYear;
76 QHash<StudentsGroup*, QSet<Activity*>> activitiesForGroup;
77 QHash<StudentsSubgroup*, QSet<Activity*>> activitiesForSubgroup;
78
79 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
80 yearsHash.insert(year->name, year);
81
82 allYears.insert(year);
83
84 for(StudentsGroup* group : qAsConst(year->groupsList)){
85 groupsHash.insert(group->name, group);
86
87 allGroups.insert(group);
88
89 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
90 subgroupsHash.insert(subgroup->name, subgroup);
91
92 allSubgroups.insert(subgroup);
93 }
94 }
95 }
96
97 QString warnings=QString("");
98 for(Activity* act : qAsConst(gt.rules.activitiesList))
99 if(act->active){
100 for(const QString& sts : qAsConst(act->studentsNames)){
101 if(yearsHash.contains(sts)){
102 StudentsYear* year=yearsHash.value(sts);
103
104 QSet<Activity*> acts=activitiesForYear.value(year, QSet<Activity*>());
105 acts.insert(act);
106 activitiesForYear.insert(year, acts);
107 }
108 else if(groupsHash.contains(sts)){
109 StudentsGroup* group=groupsHash.value(sts);
110
111 QSet<Activity*> acts=activitiesForGroup.value(group, QSet<Activity*>());
112 acts.insert(act);
113 activitiesForGroup.insert(group, acts);
114 }
115 else if(subgroupsHash.contains(sts)){
116 StudentsSubgroup* subgroup=subgroupsHash.value(sts);
117
118 QSet<Activity*> acts=activitiesForSubgroup.value(subgroup, QSet<Activity*>());
119 acts.insert(act);
120 activitiesForSubgroup.insert(subgroup, acts);
121 }
122 else
123 warnings+=tr("Students set %1 from activity with id %2 is inexistent in the students list. Please correct this.").arg(sts).arg(act->id)+QString("\n");
124 }
125 }
126 if(!warnings.isEmpty())
127 FetMessage::warning(this, tr("FET warning"), warnings);
128
129 //phase 1a
130 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
131 QSet<Activity*> actsYear=activitiesForYear.value(year, QSet<Activity*>());
132 for(StudentsGroup* group : qAsConst(year->groupsList)){
133 QSet<Activity*> actsGroup=activitiesForGroup.value(group, QSet<Activity*>());
134 actsGroup.unite(actsYear);
135 activitiesForGroup.insert(group, actsGroup);
136 }
137 }
138 //phase 1b
139 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
140 for(StudentsGroup* group : qAsConst(year->groupsList)){
141 QSet<Activity*> actsGroup=activitiesForGroup.value(group, QSet<Activity*>());
142 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
143 QSet<Activity*> actsSubgroup=activitiesForSubgroup.value(subgroup, QSet<Activity*>());
144 actsSubgroup.unite(actsGroup);
145 activitiesForSubgroup.insert(subgroup, actsSubgroup);
146 }
147 }
148 }
149 //phase 2a
150 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
151 for(StudentsGroup* group : qAsConst(year->groupsList)){
152 QSet<Activity*> actsGroup=activitiesForGroup.value(group, QSet<Activity*>());
153 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
154 QSet<Activity*> actsSubgroup=activitiesForSubgroup.value(subgroup, QSet<Activity*>());
155 actsGroup.unite(actsSubgroup);
156 }
157 activitiesForGroup.insert(group, actsGroup);
158 }
159 }
160 //phase 2b
161 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
162 QSet<Activity*> actsYear=activitiesForYear.value(year, QSet<Activity*>());
163 for(StudentsGroup* group : qAsConst(year->groupsList)){
164 QSet<Activity*> actsGroup=activitiesForGroup.value(group, QSet<Activity*>());
165 actsYear.unite(actsGroup);
166 }
167 activitiesForYear.insert(year, actsYear);
168 }
169
170 allActivities.clear();
171 allHours.clear();
172
173 for(StudentsYear* year : qAsConst(allYears)){
174 QSet<Activity*> acts=activitiesForYear.value(year, QSet<Activity*>());
175 int n=0, d=0;
176 for(Activity* act : qAsConst(acts)){
177 n++;
178 d+=act->duration;
179 }
180 assert(!allActivities.contains(year->name));
181 assert(!allHours.contains(year->name));
182 allActivities.insert(year->name, n);
183 allHours.insert(year->name, d);
184 }
185
186 for(StudentsGroup* group : qAsConst(allGroups)){
187 QSet<Activity*> acts=activitiesForGroup.value(group, QSet<Activity*>());
188 int n=0, d=0;
189 for(Activity* act : qAsConst(acts)){
190 n++;
191 d+=act->duration;
192 }
193 assert(!allActivities.contains(group->name));
194 assert(!allHours.contains(group->name));
195 allActivities.insert(group->name, n);
196 allHours.insert(group->name, d);
197 }
198
199 for(StudentsSubgroup* subgroup : qAsConst(allSubgroups)){
200 QSet<Activity*> acts=activitiesForSubgroup.value(subgroup, QSet<Activity*>());
201 int n=0, d=0;
202 for(Activity* act : qAsConst(acts)){
203 n++;
204 d+=act->duration;
205 }
206 assert(!allActivities.contains(subgroup->name));
207 assert(!allHours.contains(subgroup->name));
208 allActivities.insert(subgroup->name, n);
209 allHours.insert(subgroup->name, d);
210 }
211
212 checkBoxesModified();
213 }
214
~StudentsStatisticsForm()215 StudentsStatisticsForm::~StudentsStatisticsForm()
216 {
217 saveFETDialogGeometry(this);
218 }
219
checkBoxesModified()220 void StudentsStatisticsForm::checkBoxesModified()
221 {
222 bool complete=showCompleteStructureCheckBox->isChecked();
223
224 QSet<QString> setOfStudents;
225
226 setOfStudents.clear();
227 int nStudentsSets=0;
228 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
229 bool sy=true;
230 if(!complete){
231 if(setOfStudents.contains(year->name))
232 sy=false;
233 else
234 setOfStudents.insert(year->name);
235 }
236 if(showYearsCheckBox->isChecked() && sy)
237 nStudentsSets++;
238 for(StudentsGroup* group : qAsConst(year->groupsList)){
239 bool sg=true;
240 if(!complete){
241 if(setOfStudents.contains(group->name))
242 sg=false;
243 else
244 setOfStudents.insert(group->name);
245 }
246 if(showGroupsCheckBox->isChecked() && sg)
247 nStudentsSets++;
248 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
249 bool ss=true;
250 if(!complete){
251 if(setOfStudents.contains(subgroup->name))
252 ss=false;
253 else
254 setOfStudents.insert(subgroup->name);
255 }
256 if(showSubgroupsCheckBox->isChecked() && ss)
257 nStudentsSets++;
258 }
259 }
260 }
261
262 tableWidget->clear();
263 tableWidget->setColumnCount(3);
264 tableWidget->setRowCount(nStudentsSets);
265
266 QStringList columns;
267 columns<<tr("Students set");
268 columns<<tr("No. of activities");
269 columns<<tr("Duration");
270
271 tableWidget->setHorizontalHeaderLabels(columns);
272
273 setOfStudents.clear();
274
275 int currentStudentsSet=-1;
276 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
277 bool sy=true;
278 if(!complete){
279 if(setOfStudents.contains(year->name))
280 sy=false;
281 else
282 setOfStudents.insert(year->name);
283 }
284
285 if(showYearsCheckBox->isChecked() && sy){
286 currentStudentsSet++;
287 insertStudentsSet(year, currentStudentsSet);
288 }
289
290 for(StudentsGroup* group : qAsConst(year->groupsList)){
291 bool sg=true;
292 if(!complete){
293 if(setOfStudents.contains(group->name))
294 sg=false;
295 else
296 setOfStudents.insert(group->name);
297 }
298
299 if(showGroupsCheckBox->isChecked() && sg){
300 currentStudentsSet++;
301 insertStudentsSet(group, currentStudentsSet);
302 }
303
304 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
305 bool ss=true;
306 if(!complete){
307 if(setOfStudents.contains(subgroup->name))
308 ss=false;
309 else
310 setOfStudents.insert(subgroup->name);
311 }
312
313 if(showSubgroupsCheckBox->isChecked() && ss){
314 currentStudentsSet++;
315 insertStudentsSet(subgroup, currentStudentsSet);
316 }
317 }
318 }
319 }
320
321 tableWidget->resizeColumnsToContents();
322 tableWidget->resizeRowsToContents();
323 }
324
insertStudentsSet(StudentsSet * studentsSet,int row)325 void StudentsStatisticsForm::insertStudentsSet(StudentsSet* studentsSet, int row)
326 {
327 QTableWidgetItem* newItem=new QTableWidgetItem(studentsSet->name);
328 newItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
329 tableWidget->setItem(row, 0, newItem);
330
331 int nSubActivities=0;
332 int nHours=0;
333
334 if(allHours.contains(studentsSet->name))
335 nHours=allHours.value(studentsSet->name);
336 else
337 assert(0);
338
339 if(allActivities.contains(studentsSet->name))
340 nSubActivities=allActivities.value(studentsSet->name);
341 else
342 assert(0);
343
344 newItem=new QTableWidgetItem(CustomFETString::number(nSubActivities));
345 newItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
346 tableWidget->setItem(row, 1, newItem);
347
348 newItem=new QTableWidgetItem(CustomFETString::number(nHours));
349 newItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
350 tableWidget->setItem(row, 2, newItem);
351 }
352
on_helpPushButton_clicked()353 void StudentsStatisticsForm::on_helpPushButton_clicked()
354 {
355 QString s;
356
357 s+=tr("The check boxes '%1', '%2' and '%3': they permit you to show/hide information related to years, groups or subgroups")
358 .arg(tr("Show years"))
359 .arg(tr("Show groups"))
360 .arg(tr("Show subgroups"));
361
362 s+="\n\n";
363
364 s+=tr("The check box '%1': it has effect only if you have overlapping groups/years, and means that FET will show the complete tree structure"
365 ", even if that means that some subgroups/groups will appear twice or more in the table, with the same information."
366 " For instance, if you have year Y1, groups G1 and G2, subgroups S1, S2, S3, with structure: Y1 (G1 (S1, S2), G2 (S1, S3)),"
367 " S1 will appear twice in the table with the same information attached").arg(tr("Show duplicates"));
368
369 LongTextMessageBox::largeInformation(this, tr("FET help"), s);
370 }
371