1 /***************************************************************************
2                           addconstraintactivitypreferredroomform.cpp  -  description
3                              -------------------
4     begin                : 7 Feb 2005
5     copyright            : (C) 2005 by Liviu Lalescu
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 "addconstraintactivitypreferredroomform.h"
23 #include "spaceconstraint.h"
24 
25 #include <QSet>
26 #include "lockunlock.h"
27 
AddConstraintActivityPreferredRoomForm(QWidget * parent)28 AddConstraintActivityPreferredRoomForm::AddConstraintActivityPreferredRoomForm(QWidget* parent): QDialog(parent)
29 {
30 	setupUi(this);
31 
32 	addConstraintPushButton->setDefault(true);
33 
34 	connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
35 	connect(helpPushButton, SIGNAL(clicked()), this, SLOT(help()));
36 	connect(addConstraintPushButton, SIGNAL(clicked()), this, SLOT(addConstraint()));
37 
38 	connect(selectedRealRoomsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeRealRoom()));
39 	connect(clearPushButton, SIGNAL(clicked()), this, SLOT(clearRealRooms()));
40 	connect(allRealRoomsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addRealRoom()));
41 
42 	centerWidgetOnScreen(this);
43 	restoreFETDialogGeometry(this);
44 
45 	QSize tmp1=teachersComboBox->minimumSizeHint();
46 	Q_UNUSED(tmp1);
47 	QSize tmp2=studentsComboBox->minimumSizeHint();
48 	Q_UNUSED(tmp2);
49 	QSize tmp3=subjectsComboBox->minimumSizeHint();
50 	Q_UNUSED(tmp3);
51 	QSize tmp4=activityTagsComboBox->minimumSizeHint();
52 	Q_UNUSED(tmp4);
53 
54 	QSize tmp5=roomsComboBox->minimumSizeHint();
55 	Q_UNUSED(tmp5);
56 	QSize tmp6=activitiesComboBox->minimumSizeHint();
57 	Q_UNUSED(tmp6);
58 
59 	activitiesComboBox->setMaximumWidth(maxRecommendedWidth(this));
60 
61 	teachersComboBox->addItem("");
62 	for(int i=0; i<gt.rules.teachersList.size(); i++){
63 		Teacher* tch=gt.rules.teachersList[i];
64 		teachersComboBox->addItem(tch->name);
65 	}
66 	teachersComboBox->setCurrentIndex(0);
67 
68 	subjectsComboBox->addItem("");
69 	for(int i=0; i<gt.rules.subjectsList.size(); i++){
70 		Subject* sb=gt.rules.subjectsList[i];
71 		subjectsComboBox->addItem(sb->name);
72 	}
73 	subjectsComboBox->setCurrentIndex(0);
74 
75 	activityTagsComboBox->addItem("");
76 	for(int i=0; i<gt.rules.activityTagsList.size(); i++){
77 		ActivityTag* st=gt.rules.activityTagsList[i];
78 		activityTagsComboBox->addItem(st->name);
79 	}
80 	activityTagsComboBox->setCurrentIndex(0);
81 
82 	populateStudentsComboBox(studentsComboBox, QString(""), true);
83 	studentsComboBox->setCurrentIndex(0);
84 
85 	filterChanged();
86 	updateRoomsComboBox();
87 
88 	allRealRoomsListWidget->clear();
89 	for(Room* rm : qAsConst(gt.rules.roomsList))
90 		if(rm->isVirtual==false)
91 			allRealRoomsListWidget->addItem(rm->name);
92 	allRealRoomsListWidget->setCurrentRow(0);
93 
94 	connect(teachersComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
95 	connect(studentsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
96 	connect(subjectsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
97 	connect(activityTagsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(filterChanged()));
98 }
99 
~AddConstraintActivityPreferredRoomForm()100 AddConstraintActivityPreferredRoomForm::~AddConstraintActivityPreferredRoomForm()
101 {
102 	saveFETDialogGeometry(this);
103 }
104 
filterOk(Activity * act)105 bool AddConstraintActivityPreferredRoomForm::filterOk(Activity* act)
106 {
107 	QString tn=teachersComboBox->currentText();
108 	QString stn=studentsComboBox->currentText();
109 	QString sbn=subjectsComboBox->currentText();
110 	QString atn=activityTagsComboBox->currentText();
111 	int ok=true;
112 
113 	//teacher
114 	if(tn!=""){
115 		bool ok2=false;
116 		for(QStringList::const_iterator it=act->teachersNames.constBegin(); it!=act->teachersNames.constEnd(); it++)
117 			if(*it == tn){
118 				ok2=true;
119 				break;
120 			}
121 		if(!ok2)
122 			ok=false;
123 	}
124 
125 	//subject
126 	if(sbn!="" && sbn!=act->subjectName)
127 		ok=false;
128 
129 	//activity tag
130 	if(atn!="" && !act->activityTagsNames.contains(atn))
131 		ok=false;
132 
133 	//students
134 	if(stn!=""){
135 		bool ok2=false;
136 		for(QStringList::const_iterator it=act->studentsNames.constBegin(); it!=act->studentsNames.constEnd(); it++)
137 			if(*it == stn){
138 				ok2=true;
139 				break;
140 			}
141 		if(!ok2)
142 			ok=false;
143 	}
144 
145 	return ok;
146 }
147 
filterChanged()148 void AddConstraintActivityPreferredRoomForm::filterChanged(){
149 	activitiesComboBox->clear();
150 	activitiesList.clear();
151 
152 	for(int i=0; i<gt.rules.activitiesList.size(); i++){
153 		Activity* act=gt.rules.activitiesList[i];
154 
155 		if(filterOk(act)){
156 			activitiesComboBox->addItem(act->getDescription(gt.rules));
157 			this->activitiesList.append(act->id);
158 		}
159 	}
160 }
161 
updateRoomsComboBox()162 void AddConstraintActivityPreferredRoomForm::updateRoomsComboBox()
163 {
164 	roomsComboBox->clear();
165 	for(int i=0; i<gt.rules.roomsList.size(); i++){
166 		Room* rm=gt.rules.roomsList[i];
167 		roomsComboBox->addItem(rm->name);
168 	}
169 }
170 
removeRealRoom()171 void AddConstraintActivityPreferredRoomForm::removeRealRoom()
172 {
173 	int ind=selectedRealRoomsListWidget->currentRow();
174 	if(ind<0 || ind>=selectedRealRoomsListWidget->count()){
175 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected real room."));
176 		return;
177 	}
178 
179 	QListWidgetItem* item=selectedRealRoomsListWidget->takeItem(ind);
180 	delete item;
181 
182 	if(ind>=selectedRealRoomsListWidget->count())
183 		ind=selectedRealRoomsListWidget->count()-1;
184 	selectedRealRoomsListWidget->setCurrentRow(ind);
185 }
186 
clearRealRooms()187 void AddConstraintActivityPreferredRoomForm::clearRealRooms()
188 {
189 	selectedRealRoomsListWidget->clear();
190 }
191 
addRealRoom()192 void AddConstraintActivityPreferredRoomForm::addRealRoom()
193 {
194 	int ind=allRealRoomsListWidget->currentRow();
195 	if(ind<0 || ind>=allRealRoomsListWidget->count()){
196 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected real room."));
197 		return;
198 	}
199 
200 	bool exists=false;
201 	for(int i=0; i<selectedRealRoomsListWidget->count(); i++)
202 		if(selectedRealRoomsListWidget->item(i)->text()==allRealRoomsListWidget->item(ind)->text()){
203 			exists=true;
204 			break;
205 		}
206 
207 	if(!exists){
208 		selectedRealRoomsListWidget->addItem(allRealRoomsListWidget->item(ind)->text());
209 		selectedRealRoomsListWidget->setCurrentRow(selectedRealRoomsListWidget->count()-1);
210 	}
211 }
212 
addConstraint()213 void AddConstraintActivityPreferredRoomForm::addConstraint()
214 {
215 	SpaceConstraint *ctr=nullptr;
216 
217 	double weight;
218 	QString tmp=weightLineEdit->text();
219 	weight_sscanf(tmp, "%lf", &weight);
220 	if(weight<0.0 || weight>100){
221 		QMessageBox::warning(this, tr("FET information"),
222 			tr("Invalid weight (percentage)"));
223 		return;
224 	}
225 
226 	int id;
227 	int tmp2=activitiesComboBox->currentIndex();
228 	//assert(tmp2<gt.rules.activitiesList.size());
229 	//assert(tmp2<activitiesList.size());
230 	if(tmp2<0 || tmp2>=gt.rules.activitiesList.size() || tmp2>=activitiesList.size()){
231 		QMessageBox::warning(this, tr("FET information"),
232 			tr("Invalid activity"));
233 		return;
234 	}
235 	else
236 		id=activitiesList.at(tmp2);
237 
238 	/*int i=activitiesComboBox->currentIndex();
239 	if(i<0 || activitiesComboBox->count()<=0){
240 		QMessageBox::warning(this, tr("FET information"),
241 			tr("Invalid activity"));
242 		return;
243 	}
244 	Activity* act=gt.rules.activitiesList.at(i);*/
245 
246 	int i=roomsComboBox->currentIndex();
247 	if(i<0 || roomsComboBox->count()<=0){
248 		QMessageBox::warning(this, tr("FET information"),
249 			tr("Invalid room"));
250 		return;
251 	}
252 	QString room=roomsComboBox->currentText();
253 
254 	int ri=gt.rules.searchRoom(room);
255 	assert(ri>=0);
256 	Room* rm=gt.rules.roomsList.at(ri);
257 
258 	if(rm->isVirtual==false){
259 		if(selectedRealRoomsListWidget->count()>0){
260 			QMessageBox::warning(this, tr("FET information"), tr("The preferred room of the activity is a real room, not a virtual one."
261 			 " This implies that the selected real rooms list should be empty."));
262 			return;
263 		}
264 	}
265 	else{
266 		if(selectedRealRoomsListWidget->count()>0 && weight<100.0){
267 			QMessageBox::warning(this, tr("FET information"), tr("If the preferred room is virtual and the list of real rooms is not empty,"
268 			 " the weight percentage must be exactly 100%."));
269 			return;
270 		}
271 
272 		if(selectedRealRoomsListWidget->count()>0 && rm->realRoomsSetsList.count()!=selectedRealRoomsListWidget->count()){
273 			QMessageBox::warning(this, tr("FET information"), tr("The preferred room of the activity is a virtual room."
274 			 " This implies that the number of selected real rooms in the list should either be zero or equal to the"
275 			 " number of sets of real rooms of the preferred virtual room, which is %1.").arg(rm->realRoomsSetsList.count()));
276 			return;
277 		}
278 
279 		QSet<QString> rrs;
280 		for(const QStringList& tl : qAsConst(rm->realRoomsSetsList))
281 			for(const QString& s : qAsConst(tl))
282 				if(!rrs.contains(s))
283 					rrs.insert(s);
284 
285 		QStringList incorrectList;
286 		for(int i=0; i<selectedRealRoomsListWidget->count(); i++){
287 			bool found=false;
288 			QString rrn=selectedRealRoomsListWidget->item(i)->text();
289 			if(rrs.contains(rrn))
290 				found=true;
291 
292 			if(!found)
293 				incorrectList.append(rrn);
294 		}
295 		if(!incorrectList.isEmpty()){
296 			switch(LongTextMessageBox::confirmation(this, tr("FET information"), tr("The selected real rooms: %1 are not found in the sets of sets of real rooms of the"
297 			 " selected preferred virtual room. This is probably wrong. Are you sure you want to add this constraint?").arg(incorrectList.join(", ")),
298 			 tr("Yes"), tr("No"), 0, 0, 1)){
299 			case 0:
300 				break;
301 			case 1:
302 				return;
303 			}
304 		}
305 	}
306 
307 	QStringList lst;
308 	for(int i=0; i<selectedRealRoomsListWidget->count(); i++)
309 		lst.append(selectedRealRoomsListWidget->item(i)->text());
310 
311 	ctr=new ConstraintActivityPreferredRoom(weight, id, room, lst, permLockedCheckBox->isChecked());
312 
313 	bool tmp3=gt.rules.addSpaceConstraint(ctr);
314 	if(tmp3){
315 		QString s=tr("Constraint added:");
316 		s+="\n\n";
317 		s+=ctr->getDetailedDescription(gt.rules);
318 		LongTextMessageBox::information(this, tr("FET information"), s);
319 
320 		/*if(permLockedCheckBox->isChecked()) wrong, must take care of weight==100.0
321 			idsOfPermanentlyLockedSpace.insert(id);
322 		else
323 			idsOfLockedSpace.insert(id);*/
324 		LockUnlock::computeLockedUnlockedActivitiesOnlySpace(); //safer
325 		LockUnlock::increaseCommunicationSpinBox();
326 	}
327 	else{
328 		QMessageBox::warning(this, tr("FET information"),
329 			tr("Constraint NOT added - must be a duplicate"));
330 		delete ctr;
331 	}
332 }
333 
help()334 void AddConstraintActivityPreferredRoomForm::help()
335 {
336 	QString s;
337 
338 	s+=tr("A room can be real (the simplest and the most used scenario) or virtual. You can read more about this in the rooms dialog, by clicking the Help button there.");
339 	s+="\n\n";
340 	s+=tr("If the preferred room selected in the combo box is real, the list of selected real rooms must remain empty.");
341 	s+="\n\n";
342 	s+=tr("If the preferred room selected in the combo box is virtual, you can select also the list of real rooms to be allocated to the "
343 	 "selected activity (if the preferred room selected in the combo box is virtual and the list of selected real rooms is not empty, the "
344 	 "weight of the constraint must be 100.0%).");
345 
346 	LongTextMessageBox::largeInformation(this, tr("FET help"), s);
347 }
348