1 /***************************************************************************
2 modifyconstraintmindaysbetweenactivitiesform.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 "modifyconstraintmindaysbetweenactivitiesform.h"
21 #include "spaceconstraint.h"
22
23 #include <QList>
24
25 #include <QListWidget>
26 #include <QAbstractItemView>
27 #include <QScrollBar>
28
ModifyConstraintMinDaysBetweenActivitiesForm(QWidget * parent,ConstraintMinDaysBetweenActivities * ctr)29 ModifyConstraintMinDaysBetweenActivitiesForm::ModifyConstraintMinDaysBetweenActivitiesForm(QWidget* parent, ConstraintMinDaysBetweenActivities* ctr): QDialog(parent)
30 {
31 setupUi(this);
32
33 okPushButton->setDefault(true);
34
35 allActivitiesListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
36 selectedActivitiesListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
37
38 connect(cancelPushButton, SIGNAL(clicked()), this, SLOT(cancel()));
39 connect(okPushButton, SIGNAL(clicked()), this, SLOT(ok()));
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
44 connect(clearPushButton, SIGNAL(clicked()), this, SLOT(clear()));
45
46 centerWidgetOnScreen(this);
47 restoreFETDialogGeometry(this);
48
49 QSize tmp1=teachersComboBox->minimumSizeHint();
50 Q_UNUSED(tmp1);
51 QSize tmp2=studentsComboBox->minimumSizeHint();
52 Q_UNUSED(tmp2);
53 QSize tmp3=subjectsComboBox->minimumSizeHint();
54 Q_UNUSED(tmp3);
55 QSize tmp4=activityTagsComboBox->minimumSizeHint();
56 Q_UNUSED(tmp4);
57
58 this->_ctr=ctr;
59
60 selectedActivitiesList.clear();
61 selectedActivitiesListWidget->clear();
62 for(int i=0; i<ctr->n_activities; i++){
63 int actId=ctr->activitiesId[i];
64 this->selectedActivitiesList.append(actId);
65 Activity *act=gt.rules.activitiesPointerHash.value(actId, nullptr);
66 assert(act!=nullptr);
67 this->selectedActivitiesListWidget->addItem(act->getDescription(gt.rules));
68 }
69
70 if(gt.rules.mode!=MORNINGS_AFTERNOONS){
71 minDaysSpinBox->setMinimum(1);
72 minDaysSpinBox->setMaximum(gt.rules.nDaysPerWeek-1);
73 minDaysSpinBox->setValue(ctr->minDays);
74 }
75 else{
76 minDaysSpinBox->setMinimum(1);
77 minDaysSpinBox->setMaximum(gt.rules.nDaysPerWeek/2-1);
78 minDaysSpinBox->setValue(ctr->minDays);
79 }
80
81 consecutiveIfSameDayCheckBox->setChecked(ctr->consecutiveIfSameDay);
82 weightLineEdit->setText(CustomFETString::number(ctr->weightPercentage));
83
84 ////////////////
85 teachersComboBox->addItem("");
86 for(int i=0; i<gt.rules.teachersList.size(); i++){
87 Teacher* tch=gt.rules.teachersList[i];
88 teachersComboBox->addItem(tch->name);
89 }
90 teachersComboBox->setCurrentIndex(0);
91
92 subjectsComboBox->addItem("");
93 for(int i=0; i<gt.rules.subjectsList.size(); i++){
94 Subject* sb=gt.rules.subjectsList[i];
95 subjectsComboBox->addItem(sb->name);
96 }
97 subjectsComboBox->setCurrentIndex(0);
98
99 activityTagsComboBox->addItem("");
100 for(int i=0; i<gt.rules.activityTagsList.size(); i++){
101 ActivityTag* st=gt.rules.activityTagsList[i];
102 activityTagsComboBox->addItem(st->name);
103 }
104 activityTagsComboBox->setCurrentIndex(0);
105
106 populateStudentsComboBox(studentsComboBox, QString(""), true);
107 studentsComboBox->setCurrentIndex(0);
108
109 filterChanged();
110
111 connect(teachersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
112 connect(studentsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
113 connect(subjectsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
114 connect(activityTagsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
115 }
116
~ModifyConstraintMinDaysBetweenActivitiesForm()117 ModifyConstraintMinDaysBetweenActivitiesForm::~ModifyConstraintMinDaysBetweenActivitiesForm()
118 {
119 saveFETDialogGeometry(this);
120 }
121
filterChanged()122 void ModifyConstraintMinDaysBetweenActivitiesForm::filterChanged()
123 {
124 allActivitiesListWidget->clear();
125 this->activitiesList.clear();
126
127 for(int i=0; i<gt.rules.activitiesList.size(); i++){
128 Activity* ac=gt.rules.activitiesList[i];
129 if(filterOk(ac)){
130 allActivitiesListWidget->addItem(ac->getDescription(gt.rules));
131 this->activitiesList.append(ac->id);
132 }
133 }
134
135 int q=allActivitiesListWidget->verticalScrollBar()->minimum();
136 allActivitiesListWidget->verticalScrollBar()->setValue(q);
137 }
138
filterOk(Activity * act)139 bool ModifyConstraintMinDaysBetweenActivitiesForm::filterOk(Activity* act)
140 {
141 QString tn=teachersComboBox->currentText();
142 QString stn=studentsComboBox->currentText();
143 QString sbn=subjectsComboBox->currentText();
144 QString atn=activityTagsComboBox->currentText();
145 int ok=true;
146
147 //teacher
148 if(tn!=""){
149 bool ok2=false;
150 for(QStringList::const_iterator it=act->teachersNames.constBegin(); it!=act->teachersNames.constEnd(); it++)
151 if(*it == tn){
152 ok2=true;
153 break;
154 }
155 if(!ok2)
156 ok=false;
157 }
158
159 //subject
160 if(sbn!="" && sbn!=act->subjectName)
161 ok=false;
162
163 //activity tag
164 if(atn!="" && !act->activityTagsNames.contains(atn))
165 ok=false;
166
167 //students
168 if(stn!=""){
169 bool ok2=false;
170 for(QStringList::const_iterator it=act->studentsNames.constBegin(); it!=act->studentsNames.constEnd(); it++)
171 if(*it == stn){
172 ok2=true;
173 break;
174 }
175 if(!ok2)
176 ok=false;
177 }
178
179 return ok;
180 }
181
ok()182 void ModifyConstraintMinDaysBetweenActivitiesForm::ok()
183 {
184 double weight;
185 QString tmp=weightLineEdit->text();
186 weight_sscanf(tmp, "%lf", &weight);
187 if(weight<0.0 || weight>100.0){
188 QMessageBox::warning(this, tr("FET information"),
189 tr("Invalid weight (percentage)"));
190 return;
191 }
192
193 if(minDaysSpinBox->value()<=0){
194 QMessageBox::warning(this, tr("FET information"),
195 tr("Invalid number of min days between activities - it must be greater than 0."));
196 return;
197 }
198
199 if(this->selectedActivitiesList.size()==0){
200 QMessageBox::warning(this, tr("FET information"),
201 tr("Empty list of selected activities"));
202 return;
203 }
204 if(this->selectedActivitiesList.size()==1){
205 QMessageBox::warning(this, tr("FET information"),
206 tr("Only one selected activity"));
207 return;
208 }
209
210 #if 0
211 if(0 && this->selectedActivitiesList.size()>gt.rules.nDaysPerWeek){
212 QString s=tr("You want to add a constraint min days between activities for more activities than the number of days per week."
213 " 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).")+
214 "\n\n"+
215 tr("The best way to add the activities would be:")+
216 "\n\n"+
217
218 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"
219 ". 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"
220 " (possibly raising the weight of added constraint min days between activities up to 100%)")+
221
222 "\n\n"+
223
224 tr("2. If you don't add 'force consecutive if same day', then add a larger activity split into a number of"
225 " activities equal with the number of days per week and the remaining components into other larger split activity."
226 " For example, suppose you need to add 7 activities with duration 1 in a 5 days week. Add 2 larger container activities,"
227 " first one split into 5 activities with duration 1 and second one split into 2 activities with duration 1"
228 " (possibly raising the weight of added constraints min days between activities for each of the 2 containers up to 100%)")+
229
230 "\n\n"+
231 tr("Do you want to add current constraint as it is now (not recommended) or cancel and edit as instructed?");
232
233 int t=QMessageBox::warning(this, tr("FET warning"), s,
234 QMessageBox::Yes, QMessageBox::Cancel);
235 if(t==QMessageBox::Cancel)
236 return;
237 }
238 #endif
239
240 if(1){
241 ConstraintMinDaysBetweenActivities adc;
242
243 int i;
244 QList<int>::const_iterator it;
245 adc.activitiesId.clear();
246 for(i=0, it=this->selectedActivitiesList.constBegin(); it!=this->selectedActivitiesList.constEnd(); it++, i++){
247 adc.activitiesId.append(*it);
248 }
249 adc.n_activities=i;
250
251 adc.weightPercentage=weight;
252 adc.consecutiveIfSameDay=consecutiveIfSameDayCheckBox->isChecked();
253 adc.minDays=minDaysSpinBox->value();
254
255 bool duplicate=false;
256
257 for(TimeConstraint* tc : qAsConst(gt.rules.timeConstraintsList))
258 if(tc!=this->_ctr && tc->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES)
259 if( ( *((ConstraintMinDaysBetweenActivities*)tc) ) == adc){
260 duplicate=true;
261 break;
262 }
263
264 if(duplicate){
265 QMessageBox::warning(this, tr("FET information"), tr("Cannot proceed, current constraint is equal to another one (it is duplicated)"));
266 return;
267 }
268 }
269
270 if(_ctr->activitiesId!=selectedActivitiesList){
271 for(int oldId : qAsConst(_ctr->activitiesId)){
272 QSet<ConstraintMinDaysBetweenActivities*> cs=gt.rules.mdbaHash.value(oldId, QSet<ConstraintMinDaysBetweenActivities*>());
273 assert(cs.contains(_ctr));
274 cs.remove(_ctr);
275 gt.rules.mdbaHash.insert(oldId, cs);
276 }
277
278 for(int newId : qAsConst(selectedActivitiesList)){
279 QSet<ConstraintMinDaysBetweenActivities*> cs=gt.rules.mdbaHash.value(newId, QSet<ConstraintMinDaysBetweenActivities*>());
280 assert(!cs.contains(_ctr));
281 cs.insert(_ctr);
282 gt.rules.mdbaHash.insert(newId, cs);
283 }
284
285 _ctr->activitiesId=selectedActivitiesList;
286 _ctr->n_activities=_ctr->activitiesId.count();
287 }
288
289 /*int i;
290 QList<int>::iterator it;
291 this->_ctr->activitiesId.clear();
292 for(i=0, it=this->selectedActivitiesList.begin(); it!=this->selectedActivitiesList.end(); it++, i++){
293 this->_ctr->activitiesId.append(*it);
294 }
295 this->_ctr->n_activities=i;*/
296
297 this->_ctr->weightPercentage=weight;
298 this->_ctr->consecutiveIfSameDay=consecutiveIfSameDayCheckBox->isChecked();
299 this->_ctr->minDays=minDaysSpinBox->value();
300
301 gt.rules.internalStructureComputed=false;
302 setRulesModifiedAndOtherThings(>.rules);
303
304 this->close();
305 }
306
cancel()307 void ModifyConstraintMinDaysBetweenActivitiesForm::cancel()
308 {
309 this->close();
310 }
311
addActivity()312 void ModifyConstraintMinDaysBetweenActivitiesForm::addActivity()
313 {
314 if(allActivitiesListWidget->currentRow()<0)
315 return;
316 int tmp=allActivitiesListWidget->currentRow();
317 int _id=this->activitiesList.at(tmp);
318
319 QString actName=allActivitiesListWidget->currentItem()->text();
320 assert(actName!="");
321
322 //duplicate?
323 if(this->selectedActivitiesList.contains(_id))
324 return;
325
326 selectedActivitiesListWidget->addItem(actName);
327 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
328
329 this->selectedActivitiesList.append(_id);
330 }
331
addAllActivities()332 void ModifyConstraintMinDaysBetweenActivitiesForm::addAllActivities()
333 {
334 for(int tmp=0; tmp<allActivitiesListWidget->count(); tmp++){
335 int _id=this->activitiesList.at(tmp);
336
337 QString actName=allActivitiesListWidget->item(tmp)->text();
338 assert(actName!="");
339
340 if(this->selectedActivitiesList.contains(_id))
341 continue;
342
343 selectedActivitiesListWidget->addItem(actName);
344 this->selectedActivitiesList.append(_id);
345 }
346
347 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
348 }
349
removeActivity()350 void ModifyConstraintMinDaysBetweenActivitiesForm::removeActivity()
351 {
352 if(selectedActivitiesListWidget->currentRow()<0 || selectedActivitiesListWidget->count()<=0)
353 return;
354 int tmp=selectedActivitiesListWidget->currentRow();
355
356 this->selectedActivitiesList.removeAt(tmp);
357
358 selectedActivitiesListWidget->setCurrentRow(-1);
359 QListWidgetItem* item=selectedActivitiesListWidget->takeItem(tmp);
360 delete item;
361 if(tmp<selectedActivitiesListWidget->count())
362 selectedActivitiesListWidget->setCurrentRow(tmp);
363 else
364 selectedActivitiesListWidget->setCurrentRow(selectedActivitiesListWidget->count()-1);
365 }
366
clear()367 void ModifyConstraintMinDaysBetweenActivitiesForm::clear()
368 {
369 selectedActivitiesListWidget->clear();
370 selectedActivitiesList.clear();
371 }
372