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(>.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(>.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(>.rules);
371
372 subjectChanged(ind);
373 }
374 }
375