1 //
2 //
3 // Description: This file is part of FET
4 //
5 //
6 // Author: Lalescu Liviu <Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)>
7 // Copyright (C) 2003 Liviu Lalescu <https://lalescu.ro/liviu/>
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 "timetable.h"
20 #include "fet.h"
21 #include "subjectsform.h"
22 #include "studentsset.h"
23 #include "teacher.h"
24 #include "subject.h"
25 
26 #include <QInputDialog>
27 
28 #include <QMessageBox>
29 
30 #include <QListWidget>
31 #include <QAbstractItemView>
32 
33 #include <QSplitter>
34 #include <QSettings>
35 #include <QObject>
36 #include <QMetaObject>
37 
38 extern const QString COMPANY;
39 extern const QString PROGRAM;
40 
41 extern bool students_schedule_ready;
42 extern bool rooms_schedule_ready;
43 extern bool teachers_schedule_ready;
44 
SubjectsForm(QWidget * parent)45 SubjectsForm::SubjectsForm(QWidget* parent): QDialog(parent)
46 {
47 	setupUi(this);
48 
49 	currentSubjectTextEdit->setReadOnly(true);
50 
51 	renameSubjectPushButton->setDefault(true);
52 
53 	subjectsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
54 
55 	connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
56 	connect(addSubjectPushButton, SIGNAL(clicked()), this, SLOT(addSubject()));
57 	connect(removeSubjectPushButton, SIGNAL(clicked()), this, SLOT(removeSubject()));
58 	connect(renameSubjectPushButton, SIGNAL(clicked()), this, SLOT(renameSubject()));
59 
60 	connect(moveSubjectUpPushButton, SIGNAL(clicked()), this, SLOT(moveSubjectUp()));
61 	connect(moveSubjectDownPushButton, SIGNAL(clicked()), this, SLOT(moveSubjectDown()));
62 
63 	connect(sortSubjectsPushButton, SIGNAL(clicked()), this, SLOT(sortSubjects()));
64 	connect(subjectsListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(subjectChanged(int)));
65 	connect(activateSubjectPushButton, SIGNAL(clicked()), this, SLOT(activateSubject()));
66 	connect(deactivateSubjectPushButton, SIGNAL(clicked()), this, SLOT(deactivateSubject()));
67 	connect(subjectsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(renameSubject()));
68 
69 	connect(commentsPushButton, SIGNAL(clicked()), this, SLOT(comments()));
70 
71 	centerWidgetOnScreen(this);
72 	restoreFETDialogGeometry(this);
73 	//restore splitter state
74 	QSettings settings(COMPANY, PROGRAM);
75 	if(settings.contains(this->metaObject()->className()+QString("/splitter-state")))
76 		splitter->restoreState(settings.value(this->metaObject()->className()+QString("/splitter-state")).toByteArray());
77 
78 	subjectsListWidget->clear();
79 	for(int i=0; i<gt.rules.subjectsList.size(); i++){
80 		Subject* sbj=gt.rules.subjectsList[i];
81 		subjectsListWidget->addItem(sbj->name);
82 	}
83 
84 	if(subjectsListWidget->count()>0)
85 		subjectsListWidget->setCurrentRow(0);
86 }
87 
88 
~SubjectsForm()89 SubjectsForm::~SubjectsForm()
90 {
91 	saveFETDialogGeometry(this);
92 	//save splitter state
93 	QSettings settings(COMPANY, PROGRAM);
94 	settings.setValue(this->metaObject()->className()+QString("/splitter-state"), splitter->saveState());
95 }
96 
addSubject()97 void SubjectsForm::addSubject()
98 {
99 	bool ok = false;
100 	Subject* sbj=new Subject();
101 	sbj->name = QInputDialog::getText( this, tr("Add subject"), tr("Please enter subject's name") ,
102 	 QLineEdit::Normal, QString(), &ok );
103 
104 	if ( ok && !((sbj->name).isEmpty()) ){
105 		// user entered something and pressed OK
106 		if(!gt.rules.addSubject(sbj)){
107 			QMessageBox::information( this, tr("Subject insertion dialog"),
108 				tr("Could not insert item. Must be a duplicate"));
109 			delete sbj;
110 		}
111 		else{
112 			subjectsListWidget->addItem(sbj->name);
113 			subjectsListWidget->setCurrentRow(subjectsListWidget->count()-1);
114 		}
115 	}
116 	else{
117 		if(ok){ //the user entered nothing
118 			QMessageBox::information(this, tr("FET information"), tr("Incorrect name"));
119 		}
120 		delete sbj;// user entered nothing or pressed Cancel
121 	}
122 }
123 
removeSubject()124 void SubjectsForm::removeSubject()
125 {
126 	int i=subjectsListWidget->currentRow();
127 	if(subjectsListWidget->currentRow()<0){
128 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
129 		return;
130 	}
131 
132 	QString text=subjectsListWidget->currentItem()->text();
133 	int subject_ID=gt.rules.searchSubject(text);
134 	if(subject_ID<0){
135 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
136 		return;
137 	}
138 
139 	/*if(QMessageBox::warning( this, tr("FET"),
140 		tr("Are you sure you want to delete this subject and all related activities and constraints?"),
141 		tr("Yes"), tr("No"), 0, 0, 1 ) == 1)
142 		return;*/
143 	if(QMessageBox::warning( this, tr("FET"),
144 		tr("Are you sure you want to delete this subject and all related activities and constraints?"),
145 		QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
146 		return;
147 
148 	int tmp=gt.rules.removeSubject(text);
149 	if(tmp){
150 		subjectsListWidget->setCurrentRow(-1);
151 		QListWidgetItem* item;
152 		item=subjectsListWidget->takeItem(i);
153 		delete item;
154 
155 		if(i>=subjectsListWidget->count())
156 			i=subjectsListWidget->count()-1;
157 		if(i>=0)
158 			subjectsListWidget->setCurrentRow(i);
159 		else
160 			currentSubjectTextEdit->setPlainText(QString(""));
161 	}
162 }
163 
renameSubject()164 void SubjectsForm::renameSubject()
165 {
166 	int i=subjectsListWidget->currentRow();
167 	if(subjectsListWidget->currentRow()<0){
168 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
169 		return;
170 	}
171 
172 	QString initialSubjectName=subjectsListWidget->currentItem()->text();
173 
174 	int subject_ID=gt.rules.searchSubject(initialSubjectName);
175 	if(subject_ID<0){
176 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
177 		return;
178 	}
179 
180 	bool ok = false;
181 	QString finalSubjectName;
182 	finalSubjectName = QInputDialog::getText( this, tr("Modify subject"), tr("Please enter new subject's name") ,
183 	 QLineEdit::Normal, initialSubjectName, &ok);
184 
185 	if ( ok && !(finalSubjectName.isEmpty()) ){
186 		// user entered something and pressed OK
187 		if(gt.rules.searchSubject(finalSubjectName)>=0){
188 			QMessageBox::information( this, tr("Subject insertion dialog"),
189 				tr("Could not modify item. New name must be a duplicate"));
190 		}
191 		else{
192 			gt.rules.modifySubject(initialSubjectName, finalSubjectName);
193 			subjectsListWidget->item(i)->setText(finalSubjectName);
194 			subjectChanged(subjectsListWidget->currentRow());
195 		}
196 	}
197 }
198 
moveSubjectUp()199 void SubjectsForm::moveSubjectUp()
200 {
201 	if(subjectsListWidget->count()<=1)
202 		return;
203 	int i=subjectsListWidget->currentRow();
204 	if(i<0 || i>=subjectsListWidget->count())
205 		return;
206 	if(i==0)
207 		return;
208 
209 	QString s1=subjectsListWidget->item(i)->text();
210 	QString s2=subjectsListWidget->item(i-1)->text();
211 
212 	Subject* sbj1=gt.rules.subjectsList.at(i);
213 	Subject* sbj2=gt.rules.subjectsList.at(i-1);
214 
215 	gt.rules.internalStructureComputed=false;
216 	setRulesModifiedAndOtherThings(&gt.rules);
217 
218 	teachers_schedule_ready=false;
219 	students_schedule_ready=false;
220 	rooms_schedule_ready=false;
221 
222 	subjectsListWidget->item(i)->setText(s2);
223 	subjectsListWidget->item(i-1)->setText(s1);
224 
225 	gt.rules.subjectsList[i]=sbj2;
226 	gt.rules.subjectsList[i-1]=sbj1;
227 
228 	subjectsListWidget->setCurrentRow(i-1);
229 	subjectChanged(i-1);
230 }
231 
moveSubjectDown()232 void SubjectsForm::moveSubjectDown()
233 {
234 	if(subjectsListWidget->count()<=1)
235 		return;
236 	int i=subjectsListWidget->currentRow();
237 	if(i<0 || i>=subjectsListWidget->count())
238 		return;
239 	if(i==subjectsListWidget->count()-1)
240 		return;
241 
242 	QString s1=subjectsListWidget->item(i)->text();
243 	QString s2=subjectsListWidget->item(i+1)->text();
244 
245 	Subject* sbj1=gt.rules.subjectsList.at(i);
246 	Subject* sbj2=gt.rules.subjectsList.at(i+1);
247 
248 	gt.rules.internalStructureComputed=false;
249 	setRulesModifiedAndOtherThings(&gt.rules);
250 
251 	teachers_schedule_ready=false;
252 	students_schedule_ready=false;
253 	rooms_schedule_ready=false;
254 
255 	subjectsListWidget->item(i)->setText(s2);
256 	subjectsListWidget->item(i+1)->setText(s1);
257 
258 	gt.rules.subjectsList[i]=sbj2;
259 	gt.rules.subjectsList[i+1]=sbj1;
260 
261 	subjectsListWidget->setCurrentRow(i+1);
262 	subjectChanged(i+1);
263 }
264 
sortSubjects()265 void SubjectsForm::sortSubjects()
266 {
267 	gt.rules.sortSubjectsAlphabetically();
268 
269 	subjectsListWidget->clear();
270 	for(int i=0; i<gt.rules.subjectsList.size(); i++){
271 		Subject* sbj=gt.rules.subjectsList[i];
272 		subjectsListWidget->addItem(sbj->name);
273 	}
274 
275 	if(subjectsListWidget->count()>0)
276 		subjectsListWidget->setCurrentRow(0);
277 }
278 
subjectChanged(int index)279 void SubjectsForm::subjectChanged(int index)
280 {
281 	if(index<0){
282 		currentSubjectTextEdit->setPlainText(QString(""));
283 		return;
284 	}
285 
286 	Subject* sb=gt.rules.subjectsList.at(index);
287 	assert(sb);
288 	QString s=sb->getDetailedDescriptionWithConstraints(gt.rules);
289 	currentSubjectTextEdit->setPlainText(s);
290 }
291 
activateSubject()292 void SubjectsForm::activateSubject()
293 {
294 	if(subjectsListWidget->currentRow()<0){
295 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
296 		return;
297 	}
298 
299 	QString subjectName=subjectsListWidget->currentItem()->text();
300 
301 	int count=gt.rules.activateSubject(subjectName);
302 	QMessageBox::information(this, tr("FET information"), tr("Activated a number of %1 activities").arg(count));
303 }
304 
deactivateSubject()305 void SubjectsForm::deactivateSubject()
306 {
307 	if(subjectsListWidget->currentRow()<0){
308 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
309 		return;
310 	}
311 
312 	QString subjectName=subjectsListWidget->currentItem()->text();
313 
314 	int count=gt.rules.deactivateSubject(subjectName);
315 	QMessageBox::information(this, tr("FET information"), tr("De-activated a number of %1 activities").arg(count));
316 }
317 
comments()318 void SubjectsForm::comments()
319 {
320 	int ind=subjectsListWidget->currentRow();
321 	if(ind<0){
322 		QMessageBox::information(this, tr("FET information"), tr("Invalid selected subject"));
323 		return;
324 	}
325 
326 	Subject* sbj=gt.rules.subjectsList[ind];
327 	assert(sbj!=nullptr);
328 
329 	QDialog getCommentsDialog(this);
330 
331 	getCommentsDialog.setWindowTitle(tr("Subject comments"));
332 
333 	QPushButton* okPB=new QPushButton(tr("OK"));
334 	okPB->setDefault(true);
335 	QPushButton* cancelPB=new QPushButton(tr("Cancel"));
336 
337 	connect(okPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(accept()));
338 	connect(cancelPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(reject()));
339 
340 	QHBoxLayout* hl=new QHBoxLayout();
341 	hl->addStretch();
342 	hl->addWidget(okPB);
343 	hl->addWidget(cancelPB);
344 
345 	QVBoxLayout* vl=new QVBoxLayout();
346 
347 	QPlainTextEdit* commentsPT=new QPlainTextEdit();
348 	commentsPT->setPlainText(sbj->comments);
349 	commentsPT->selectAll();
350 	commentsPT->setFocus();
351 
352 	vl->addWidget(commentsPT);
353 	vl->addLayout(hl);
354 
355 	getCommentsDialog.setLayout(vl);
356 
357 	const QString settingsName=QString("SubjectCommentsDialog");
358 
359 	getCommentsDialog.resize(500, 320);
360 	centerWidgetOnScreen(&getCommentsDialog);
361 	restoreFETDialogGeometry(&getCommentsDialog, settingsName);
362 
363 	int t=getCommentsDialog.exec();
364 	saveFETDialogGeometry(&getCommentsDialog, settingsName);
365 
366 	if(t==QDialog::Accepted){
367 		sbj->comments=commentsPT->toPlainText();
368 
369 		gt.rules.internalStructureComputed=false;
370 		setRulesModifiedAndOtherThings(&gt.rules);
371 
372 		subjectChanged(ind);
373 	}
374 }
375