1 /***************************************************************************
2 subactivitiesform.cpp - description
3 -------------------
4 begin : 2009
5 copyright : (C) 2009 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 "timetable_defs.h"
19 #include "fet.h"
20 #include "timetable.h"
21
22 #include "studentsset.h"
23
24 #include "subactivitiesform.h"
25 #include "modifysubactivityform.h"
26
27 #include <QString>
28 #include <QMessageBox>
29
30 #include <QListWidget>
31 #include <QScrollBar>
32
33 #include <QAbstractItemView>
34
35 #include "longtextmessagebox.h"
36
37 #include <QBrush>
38 #include <QPalette>
39
40 #include <QSplitter>
41 #include <QSettings>
42 #include <QObject>
43 #include <QMetaObject>
44
45 extern const QString COMPANY;
46 extern const QString PROGRAM;
47
SubactivitiesForm(QWidget * parent,const QString & teacherName,const QString & studentsSetName,const QString & subjectName,const QString & activityTagName)48 SubactivitiesForm::SubactivitiesForm(QWidget* parent, const QString& teacherName, const QString& studentsSetName, const QString& subjectName, const QString& activityTagName): QDialog(parent)
49 {
50 setupUi(this);
51
52 subactivityTextEdit->setReadOnly(true);
53
54 modifySubactivityPushButton->setDefault(true);
55
56 subactivitiesListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
57
58 centerWidgetOnScreen(this);
59 restoreFETDialogGeometry(this);
60 //restore splitter state
61 QSettings settings(COMPANY, PROGRAM);
62 if(settings.contains(this->metaObject()->className()+QString("/splitter-state")))
63 splitter->restoreState(settings.value(this->metaObject()->className()+QString("/splitter-state")).toByteArray());
64 showRelatedCheckBox->setChecked(settings.value(this->metaObject()->className()+QString("/show-related-check-box-state"), "false").toBool());
65
66 connect(subactivitiesListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(subactivityChanged()));
67 connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
68
69 connect(modifySubactivityPushButton, SIGNAL(clicked()), this, SLOT(modifySubactivity()));
70 connect(subactivitiesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(modifySubactivity()));
71 connect(showRelatedCheckBox, SIGNAL(toggled(bool)), this, SLOT(studentsFilterChanged()));
72 connect(helpPushButton, SIGNAL(clicked()), this, SLOT(help()));
73 connect(commentsPushButton, SIGNAL(clicked()), this, SLOT(subactivityComments()));
74
75 QSize tmp1=teachersComboBox->minimumSizeHint();
76 Q_UNUSED(tmp1);
77 QSize tmp2=studentsComboBox->minimumSizeHint();
78 Q_UNUSED(tmp2);
79 QSize tmp3=subjectsComboBox->minimumSizeHint();
80 Q_UNUSED(tmp3);
81 QSize tmp4=activityTagsComboBox->minimumSizeHint();
82 Q_UNUSED(tmp4);
83
84 teachersComboBox->addItem("");
85 int cit=0;
86 for(int i=0; i<gt.rules.teachersList.size(); i++){
87 Teacher* tch=gt.rules.teachersList[i];
88 teachersComboBox->addItem(tch->name);
89 if(tch->name==teacherName)
90 cit=i+1;
91 }
92 teachersComboBox->setCurrentIndex(cit);
93
94 subjectsComboBox->addItem("");
95 int cisu=0;
96 for(int i=0; i<gt.rules.subjectsList.size(); i++){
97 Subject* sb=gt.rules.subjectsList[i];
98 subjectsComboBox->addItem(sb->name);
99 if(sb->name==subjectName)
100 cisu=i+1;
101 }
102 subjectsComboBox->setCurrentIndex(cisu);
103
104 activityTagsComboBox->addItem("");
105 int ciat=0;
106 for(int i=0; i<gt.rules.activityTagsList.size(); i++){
107 ActivityTag* st=gt.rules.activityTagsList[i];
108 activityTagsComboBox->addItem(st->name);
109 if(st->name==activityTagName)
110 ciat=i+1;
111 }
112 activityTagsComboBox->setCurrentIndex(ciat);
113
114 int cist=populateStudentsComboBox(studentsComboBox, studentsSetName, true);
115 if(studentsSetName==""){
116 assert(cist==0);
117 studentsComboBox->setCurrentIndex(0);
118
119 showedStudents.clear();
120 showedStudents.insert("");
121
122 this->filterChanged();
123 }
124 else{
125 assert(cist!=0);
126
127 if(cist==-1){
128 studentsComboBox->setCurrentIndex(0);
129
130 showWarningForInvisibleSubgroupActivity(parent, studentsSetName);
131
132 showedStudents.clear();
133 showedStudents.insert("");
134
135 this->filterChanged();
136 }
137 else{
138 studentsComboBox->setCurrentIndex(cist);
139
140 this->studentsFilterChanged();
141 }
142 }
143
144 /*studentsComboBox->setCurrentIndex(cist);
145
146 if(studentsSetName!=""){
147 if(cist==0){
148 showWarningForInvisibleSubgroupActivity(parent, studentsSetName);
149
150 showedStudents.clear();
151 showedStudents.insert("");
152
153 this->filterChanged();
154 }
155 else{
156 this->studentsFilterChanged();
157 }
158 }
159 else{
160 showedStudents.clear();
161 showedStudents.insert("");
162
163 this->filterChanged();
164 }*/
165
166 connect(teachersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
167 connect(studentsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(studentsFilterChanged()));
168 connect(subjectsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
169 connect(activityTagsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
170 }
171
~SubactivitiesForm()172 SubactivitiesForm::~SubactivitiesForm()
173 {
174 saveFETDialogGeometry(this);
175 //save splitter state
176 QSettings settings(COMPANY, PROGRAM);
177 settings.setValue(this->metaObject()->className()+QString("/splitter-state"), splitter->saveState());
178
179 settings.setValue(this->metaObject()->className()+QString("/show-related-check-box-state"), showRelatedCheckBox->isChecked());
180 }
181
filterOk(Activity * act)182 bool SubactivitiesForm::filterOk(Activity* act)
183 {
184 QString tn=teachersComboBox->currentText();
185 QString stn=studentsComboBox->currentText();
186 QString sbn=subjectsComboBox->currentText();
187 QString atn=activityTagsComboBox->currentText();
188 int ok=true;
189
190 //teacher
191 if(tn!=""){
192 bool ok2=false;
193 for(QStringList::const_iterator it=act->teachersNames.constBegin(); it!=act->teachersNames.constEnd(); it++)
194 if(*it == tn){
195 ok2=true;
196 break;
197 }
198 if(!ok2)
199 ok=false;
200 }
201
202 //subject
203 if(sbn!="" && sbn!=act->subjectName)
204 ok=false;
205
206 //activity tag
207 if(atn!="" && !act->activityTagsNames.contains(atn))
208 ok=false;
209
210 //students
211 if(stn!=""){
212 bool ok2=false;
213 for(QStringList::const_iterator it=act->studentsNames.constBegin(); it!=act->studentsNames.constEnd(); it++)
214 if(showedStudents.contains(*it)){
215 //if(*it == stn){
216 ok2=true;
217 break;
218 }
219 if(!ok2)
220 ok=false;
221 }
222 else{
223 assert(showedStudents.count()==1);
224 assert(showedStudents.contains(""));
225 }
226
227 return ok;
228 }
229
studentsFilterChanged()230 void SubactivitiesForm::studentsFilterChanged()
231 {
232 bool showRelated=showRelatedCheckBox->isChecked();
233
234 showedStudents.clear();
235
236 if(!showRelated){
237 showedStudents.insert(studentsComboBox->currentText());
238 }
239 else{
240 if(studentsComboBox->currentText()=="")
241 showedStudents.insert("");
242 else{
243 //down
244 StudentsSet* studentsSet=gt.rules.searchStudentsSet(studentsComboBox->currentText());
245 assert(studentsSet!=nullptr);
246 if(studentsSet->type==STUDENTS_YEAR){
247 StudentsYear* year=(StudentsYear*)studentsSet;
248 showedStudents.insert(year->name);
249 for(StudentsGroup* group : qAsConst(year->groupsList)){
250 showedStudents.insert(group->name);
251 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
252 showedStudents.insert(subgroup->name);
253 }
254 }
255 else if(studentsSet->type==STUDENTS_GROUP){
256 StudentsGroup* group=(StudentsGroup*)studentsSet;
257 showedStudents.insert(group->name);
258 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList))
259 showedStudents.insert(subgroup->name);
260 }
261 else if(studentsSet->type==STUDENTS_SUBGROUP){
262 StudentsSubgroup* subgroup=(StudentsSubgroup*)studentsSet;
263 showedStudents.insert(subgroup->name);
264 }
265 else
266 assert(0);
267
268 //up
269 QString crt=studentsComboBox->currentText();
270 for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
271 for(StudentsGroup* group : qAsConst(year->groupsList)){
272 if(group->name==crt){
273 showedStudents.insert(year->name);
274 }
275 for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
276 if(subgroup->name==crt){
277 showedStudents.insert(year->name);
278 showedStudents.insert(group->name);
279 }
280 }
281 }
282 }
283 }
284 }
285
286 filterChanged();
287 }
288
filterChanged()289 void SubactivitiesForm::filterChanged()
290 {
291 int nacts=0, nsubacts=0, nh=0;
292 int ninact=0, ninacth=0;
293
294 QString s;
295 subactivitiesListWidget->clear();
296 visibleSubactivitiesList.clear();
297
298 int k=0;
299 for(int i=0; i<gt.rules.activitiesList.size(); i++){
300 Activity* act=gt.rules.activitiesList[i];
301 if(this->filterOk(act)){
302 s=act->getDescription(gt.rules);
303 visibleSubactivitiesList.append(act);
304 subactivitiesListWidget->addItem(s);
305 k++;
306
307 if(USE_GUI_COLORS && !act->active)
308 subactivitiesListWidget->item(k-1)->setBackground(subactivitiesListWidget->palette().alternateBase());
309
310 if(act->id==act->activityGroupId || act->activityGroupId==0)
311 nacts++;
312 nsubacts++;
313
314 nh+=act->duration;
315
316 if(!act->active){
317 ninact++;
318 ninacth+=act->duration;
319 }
320 }
321 }
322
323 assert(nsubacts-ninact>=0);
324 assert(nh-ninacth>=0);
325 activeTextLabel->setText(tr("No: %1 / %2", "No means number, %1 is the number of active subactivities, %2 is the total number of subactivities."
326 "Please leave space between fields, so that they are better visible").arg(nsubacts-ninact).arg(nsubacts));
327 totalTextLabel->setText(tr("Dur: %1 / %2", "Dur means duration, %1 is the duration of active subactivities, %2 is the total duration of subactivities."
328 "Please leave space between fields, so that they are better visible").arg(nh-ninacth).arg(nh));
329
330 if(subactivitiesListWidget->count()>0)
331 subactivitiesListWidget->setCurrentRow(0);
332 else
333 subactivityTextEdit->setPlainText(QString(""));
334 }
335
modifySubactivity()336 void SubactivitiesForm::modifySubactivity()
337 {
338 int ind=subactivitiesListWidget->currentRow();
339 if(ind<0){
340 QMessageBox::information(this, tr("FET information"), tr("Invalid selected subactivity"));
341 return;
342 }
343
344 assert(ind<visibleSubactivitiesList.count());
345
346 int valv=subactivitiesListWidget->verticalScrollBar()->value();
347 int valh=subactivitiesListWidget->horizontalScrollBar()->value();
348
349 Activity* act=visibleSubactivitiesList[ind];
350 assert(act!=nullptr);
351
352 ModifySubactivityForm modifySubactivityForm(this, act->id, act->activityGroupId);
353 int t;
354 setParentAndOtherThings(&modifySubactivityForm, this);
355 t=modifySubactivityForm.exec();
356
357 if(t==QDialog::Accepted){
358 //cout<<"Acc"<<endl;
359 filterChanged();
360
361 subactivitiesListWidget->verticalScrollBar()->setValue(valv);
362 subactivitiesListWidget->horizontalScrollBar()->setValue(valh);
363
364 if(ind>=subactivitiesListWidget->count())
365 ind=subactivitiesListWidget->count()-1;
366 if(ind>=0)
367 subactivitiesListWidget->setCurrentRow(ind);
368 }
369 else{
370 //cout<<"Rej"<<endl;
371 assert(t==QDialog::Rejected);
372 }
373 }
374
subactivityChanged()375 void SubactivitiesForm::subactivityChanged()
376 {
377 int index=subactivitiesListWidget->currentRow();
378
379 if(index<0){
380 subactivityTextEdit->setPlainText(QString(""));
381 return;
382 }
383 if(index>=visibleSubactivitiesList.count()){
384 subactivityTextEdit->setPlainText(QString("Invalid subactivity"));
385 return;
386 }
387
388 QString s;
389 Activity* act=visibleSubactivitiesList[index];
390
391 assert(act!=nullptr);
392 s=act->getDetailedDescriptionWithConstraints(gt.rules);
393 subactivityTextEdit->setPlainText(s);
394 }
395
help()396 void SubactivitiesForm::help()
397 {
398 QString s;
399
400 s+=tr("Useful instructions/tips:");
401 s+="\n\n";
402
403 s+=tr("Above the (sub)activities list, we have 2 labels, containing 4 numbers. The first label contains text: No: a / b. The first number a is the"
404 " number of active (sub)activities (we number each individual subactivity as 1), while the second number b is the number of total (sub)activities."
405 " The second label contains text: Dur: c / d. The third number c is the duration of active (sub)activities, in periods"
406 " (or FET hours), while the fourth number d is the duration of total (sub)activities, in periods (or FET hours)."
407 " So, No means number and Dur means duration.");
408 s+="\n\n";
409 s+=tr("Example: No: 100 / 102, Dur: 114 / 117. They represent: 100 - the number of active (sub)activities,"
410 " then 102 - the number of total (sub)activities,"
411 " 114 - the duration of active activities (in periods or FET hours) and 117 - the duration of total activities"
412 " (in periods or FET hours). In this example we have 2 inactive activities with their combined duration being 3 periods.");
413
414 s+="\n\n";
415 s+=tr("Explanation of the short description of an activity: first comes the id."
416 " If the activity is inactive, an X follows. Then the duration. Then, if the activity is split, a slash and the total duration."
417 " Then teachers, subject, activity tag (if it is not void) and students. Then the number of students (if specified).");
418 s+="\n\n";
419 s+=tr("The activities which are inactive:");
420 s+="\n";
421 s+=" -";
422 s+=tr("have an X mark after the id.");
423 s+="\n";
424 /* s+=" -";
425 s+=tr("are shown with lowercase letters.");
426 s+="\n";*/
427 s+=" -";
428 s+=tr("if you use colors in interface (see Settings/Interface menu), they will appear with different background color.");
429 s+="\n\n";
430 s+=tr("To modify a subactivity, you can also double click it.");
431 s+="\n\n";
432 s+=tr("Show related: if you select this, there will be listed subactivities for groups and subgroups contained also in the current set (if the current set"
433 " is a year or a group) and also higher ranked year or group (if the current set is a group or a subgroup).");
434
435 LongTextMessageBox::largeInformation(this, tr("FET Help"), s);
436 }
437
subactivityComments()438 void SubactivitiesForm::subactivityComments()
439 {
440 int ind=subactivitiesListWidget->currentRow();
441 if(ind<0){
442 QMessageBox::information(this, tr("FET information"), tr("Invalid selected subactivity"));
443 return;
444 }
445
446 assert(ind<visibleSubactivitiesList.count());
447
448 Activity* act=visibleSubactivitiesList[ind];
449 assert(act!=nullptr);
450
451 QDialog getCommentsDialog(this);
452
453 getCommentsDialog.setWindowTitle(tr("Subactivity comments"));
454
455 QPushButton* okPB=new QPushButton(tr("OK"));
456 okPB->setDefault(true);
457 QPushButton* cancelPB=new QPushButton(tr("Cancel"));
458
459 connect(okPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(accept()));
460 connect(cancelPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(reject()));
461
462 QHBoxLayout* hl=new QHBoxLayout();
463 hl->addStretch();
464 hl->addWidget(okPB);
465 hl->addWidget(cancelPB);
466
467 QVBoxLayout* vl=new QVBoxLayout();
468
469 QPlainTextEdit* commentsPT=new QPlainTextEdit();
470 commentsPT->setPlainText(act->comments);
471 commentsPT->selectAll();
472 commentsPT->setFocus();
473
474 vl->addWidget(commentsPT);
475 vl->addLayout(hl);
476
477 getCommentsDialog.setLayout(vl);
478
479 const QString settingsName=QString("SubactivityCommentsDialog");
480
481 getCommentsDialog.resize(500, 320);
482 centerWidgetOnScreen(&getCommentsDialog);
483 restoreFETDialogGeometry(&getCommentsDialog, settingsName);
484
485 int t=getCommentsDialog.exec();
486 saveFETDialogGeometry(&getCommentsDialog, settingsName);
487
488 if(t==QDialog::Accepted){
489 act->comments=commentsPT->toPlainText();
490
491 gt.rules.internalStructureComputed=false;
492 setRulesModifiedAndOtherThings(>.rules);
493
494 subactivitiesListWidget->currentItem()->setText(act->getDescription(gt.rules));
495 subactivityChanged();
496 }
497 }
498