1 /***************************************************************************
2 addconstraintmindaysbetweenactivitiesform.cpp - description
3 -------------------
4 begin : Feb 11, 2005
5 copyright : (C) 2005 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 <QMessageBox>
19
20 #include "longtextmessagebox.h"
21
22 #include "addconstraintmindaysbetweenactivitiesform.h"
23 #include "spaceconstraint.h"
24
25 #include <QListWidget>
26 #include <QAbstractItemView>
27 #include <QScrollBar>
28
AddConstraintMinDaysBetweenActivitiesForm(QWidget * parent)29 AddConstraintMinDaysBetweenActivitiesForm::AddConstraintMinDaysBetweenActivitiesForm(QWidget* parent): QDialog(parent)
30 {
31 setupUi(this);
32
33 addConstraintPushButton->setDefault(true);
34
35 allActivitiesListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
36 selectedActivitiesListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
37
38 connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
39 connect(addConstraintPushButton, SIGNAL(clicked()), this, SLOT(addConstraint()));
40 connect(allActivitiesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addActivity()));
41 connect(addAllActivitiesPushButton, SIGNAL(clicked()), this, SLOT(addAllActivities()));
42 connect(selectedActivitiesListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeActivity()));
43 connect(clearPushButton, SIGNAL(clicked()), this, SLOT(clear()));
44
45 centerWidgetOnScreen(this);
46 restoreFETDialogGeometry(this);
47
48 QSize tmp1=teachersComboBox->minimumSizeHint();
49 Q_UNUSED(tmp1);
50 QSize tmp2=studentsComboBox->minimumSizeHint();
51 Q_UNUSED(tmp2);
52 QSize tmp3=subjectsComboBox->minimumSizeHint();
53 Q_UNUSED(tmp3);
54 QSize tmp4=activityTagsComboBox->minimumSizeHint();
55 Q_UNUSED(tmp4);
56
57 if(gt.rules.mode!=MORNINGS_AFTERNOONS){
58 minDaysSpinBox->setMinimum(1);
59 minDaysSpinBox->setMaximum(gt.rules.nDaysPerWeek-1);
60 minDaysSpinBox->setValue(1);
61 }
62 else{
63 minDaysSpinBox->setMinimum(1);
64 minDaysSpinBox->setMaximum(gt.rules.nDaysPerWeek/2-1);
65 minDaysSpinBox->setValue(1);
66 }
67
68 teachersComboBox->addItem("");
69 for(int i=0; i<gt.rules.teachersList.size(); i++){
70 Teacher* tch=gt.rules.teachersList[i];
71 teachersComboBox->addItem(tch->name);
72 }
73 teachersComboBox->setCurrentIndex(0);
74
75 subjectsComboBox->addItem("");
76 for(int i=0; i<gt.rules.subjectsList.size(); i++){
77 Subject* sb=gt.rules.subjectsList[i];
78 subjectsComboBox->addItem(sb->name);
79 }
80 subjectsComboBox->setCurrentIndex(0);
81
82 activityTagsComboBox->addItem("");
83 for(int i=0; i<gt.rules.activityTagsList.size(); i++){
84 ActivityTag* st=gt.rules.activityTagsList[i];
85 activityTagsComboBox->addItem(st->name);
86 }
87 activityTagsComboBox->setCurrentIndex(0);
88
89 populateStudentsComboBox(studentsComboBox, QString(""), true);
90 studentsComboBox->setCurrentIndex(0);
91
92 selectedActivitiesListWidget->clear();
93 this->selectedActivitiesList.clear();
94
95 filterChanged();
96
97 connect(teachersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
98 connect(studentsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
99 connect(subjectsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
100 connect(activityTagsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
101 }
102
~AddConstraintMinDaysBetweenActivitiesForm()103 AddConstraintMinDaysBetweenActivitiesForm::~AddConstraintMinDaysBetweenActivitiesForm()
104 {
105 saveFETDialogGeometry(this);
106 }
107
filterOk(Activity * act)108 bool AddConstraintMinDaysBetweenActivitiesForm::filterOk(Activity* act)
109 {
110 QString tn=teachersComboBox->currentText();
111 QString stn=studentsComboBox->currentText();
112 QString sbn=subjectsComboBox->currentText();
113 QString atn=activityTagsComboBox->currentText();
114 int ok=true;
115
116 //teacher
117 if(tn!=""){
118 bool ok2=false;
119 for(QStringList::const_iterator it=act->teachersNames.constBegin(); it!=act->teachersNames.constEnd(); it++)
120 if(*it == tn){
121 ok2=true;
122 break;
123 }
124 if(!ok2)
125 ok=false;
126 }
127
128 //subject
129 if(sbn!="" && sbn!=act->subjectName)
130 ok=false;
131
132 //activity tag
133 if(atn!="" && !act->activityTagsNames.contains(atn))
134 ok=false;
135
136 //students
137 if(stn!=""){
138 bool ok2=false;
139 for(QStringList::const_iterator it=act->studentsNames.constBegin(); it!=act->studentsNames.constEnd(); it++)
140 if(*it == stn){
141 ok2=true;
142 break;
143 }
144 if(!ok2)
145 ok=false;
146 }
147
148 return ok;
149 }
150
filterChanged()151 void AddConstraintMinDaysBetweenActivitiesForm::filterChanged()
152 {
153 allActivitiesListWidget->clear();
154
155 this->activitiesList.clear();
156
157 for(int i=0; i<gt.rules.activitiesList.size(); i++){
158 Activity* ac=gt.rules.activitiesList[i];
159 if(filterOk(ac)){
160 allActivitiesListWidget->addItem(ac->getDescription(gt.rules));
161 this->activitiesList.append(ac->id);
162 }
163 }
164
165 int q=allActivitiesListWidget->verticalScrollBar()->minimum();
166 allActivitiesListWidget->verticalScrollBar()->setValue(q);
167 }
168
addConstraint()169 void AddConstraintMinDaysBetweenActivitiesForm::addConstraint()
170 {
171 TimeConstraint *ctr=nullptr;
172
173 double weight;
174 QString tmp=weightLineEdit->text();
175 weight_sscanf(tmp, "%lf", &weight);
176 if(weight<0.0 || weight>100){
177 QMessageBox::warning(this, tr("FET information"),
178 tr("Invalid weight (percentage)"));
179 return;
180 }
181
182 if(minDaysSpinBox->value()<=0){
183 QMessageBox::warning(this, tr("FET information"),
184 tr("Invalid number of min days between activities - it must be greater than 0."));
185 return;
186 }
187
188 if(this->selectedActivitiesList.count()==0){
189 QMessageBox::warning(this, tr("FET information"),
190 tr("Empty list of selected activities"));
191 return;
192 }
193 if(this->selectedActivitiesList.count()==1){
194 QMessageBox::warning(this, tr("FET information"),
195 tr("Only one selected activity"));
196 return;
197 }
198
199 #if 0
200 if(0 && this->selectedActivitiesList.size()>gt.rules.nDaysPerWeek){
201 QString s=tr("You want to add a constraint min days between activities for more activities than the number of days per week."
202 " This is a very bad practice from the way the algorithm of generation works (it slows down the generation and makes it harder to find a solution).")+
203 "\n\n"+
204 tr("The best way to add the activities would be:")+
205 "\n\n"+
206
207 tr("1. If you add 'force consecutive if same day', then couple extra activities in pairs to obtain a number of activities equal to the number of days per week"
208 ". Example: 7 activities with duration 1 in a 5 days week, then transform into 5 activities with durations: 2,2,1,1,1 and add a single container activity with these 5 components"
209 " (possibly raising the weight of added constraint min days between activities up to 100%)")+
210
211 "\n\n"+
212
213 tr("2. If you don't add 'force consecutive if same day', then add a larger activity split into a number of"
214 " activities equal with the number of days per week and the remaining components into other larger split activity."
215 " For example, suppose you need to add 7 activities with duration 1 in a 5 days week. Add 2 larger container activities,"
216 " first one split into 5 activities with duration 1 and second one split into 2 activities with duration 1"
217 " (possibly raising the weight of added constraints min days between activities for each of the 2 containers up to 100%)")+
218
219 "\n\n"+
220
221 tr("Do you want to add current constraint as it is now (not recommended) or cancel and edit as instructed?");
222
223 int t=QMessageBox::warning(this, tr("FET warning"), s,
224 QMessageBox::Yes, QMessageBox::Cancel);
225 if(t==QMessageBox::Cancel)
226 return;
227 }
228 #endif
229
230 QList<int> ids;
231 QList<int>::const_iterator it;
232 ids.clear();
233 for(it=this->selectedActivitiesList.constBegin(); it!=this->selectedActivitiesList.constEnd(); it++){
234 ids.append(*it);
235 }
236
237 ctr=new ConstraintMinDaysBetweenActivities(weight, consecutiveIfSameDayCheckBox->isChecked(), this->selectedActivitiesList.count(), ids, minDaysSpinBox->value());
238
239 bool tmp2=gt.rules.addTimeConstraint(ctr);
240
241 if(tmp2){
242 QString s=tr("Constraint added:");
243 s+="\n\n";
244 s+=ctr->getDetailedDescription(gt.rules);
245 LongTextMessageBox::information(this, tr("FET information"), s);
246 }
247 else{
248 QMessageBox::warning(this, tr("FET information"),
249 tr("Constraint NOT added - it must be a duplicate"));
250 delete ctr;
251 }
252 }
253
addActivity()254 void AddConstraintMinDaysBetweenActivitiesForm::addActivity()
255 {
256 if(allActivitiesListWidget->currentRow()<0)
257 return;
258 int tmp=allActivitiesListWidget->currentRow();
259 int _id=this->activitiesList.at(tmp);
260
261 QString actName=allActivitiesListWidget->currentItem()->text();
262 assert(actName!="");
263
264 //duplicate?
265 if(this->selectedActivitiesList.contains(_id))
266 return;
267
268 selectedActivitiesListWidget->addItem(actName);
269 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
270
271 this->selectedActivitiesList.append(_id);
272 }
273
addAllActivities()274 void AddConstraintMinDaysBetweenActivitiesForm::addAllActivities()
275 {
276 for(int tmp=0; tmp<allActivitiesListWidget->count(); tmp++){
277 int _id=this->activitiesList.at(tmp);
278
279 QString actName=allActivitiesListWidget->item(tmp)->text();
280 assert(actName!="");
281
282 if(this->selectedActivitiesList.contains(_id))
283 continue;
284
285 selectedActivitiesListWidget->addItem(actName);
286 this->selectedActivitiesList.append(_id);
287 }
288
289 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
290 }
291
removeActivity()292 void AddConstraintMinDaysBetweenActivitiesForm::removeActivity()
293 {
294 if(selectedActivitiesListWidget->currentRow()<0 || selectedActivitiesListWidget->count()<=0)
295 return;
296 int tmp=selectedActivitiesListWidget->currentRow();
297
298 selectedActivitiesList.removeAt(tmp);
299
300 selectedActivitiesListWidget->setCurrentRow(-1);
301 QListWidgetItem* item=selectedActivitiesListWidget->takeItem(tmp);
302 delete item;
303 if(tmp<selectedActivitiesListWidget->count())
304 selectedActivitiesListWidget->setCurrentRow(tmp);
305 else
306 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
307 }
308
clear()309 void AddConstraintMinDaysBetweenActivitiesForm::clear()
310 {
311 selectedActivitiesListWidget->clear();
312 selectedActivitiesList.clear();
313 }
314