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