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) 2005 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 "activitytagsform.h"
22 #include "studentsset.h"
23 #include "teacher.h"
24 #include "subject.h"
25 #include "activitytag.h"
26
27 #include <QInputDialog>
28
29 #include <QMessageBox>
30
31 #include <QListWidget>
32 #include <QAbstractItemView>
33
34 #include <QSplitter>
35 #include <QSettings>
36 #include <QObject>
37 #include <QMetaObject>
38
39 extern const QString COMPANY;
40 extern const QString PROGRAM;
41
42 extern bool students_schedule_ready;
43 extern bool rooms_schedule_ready;
44 extern bool teachers_schedule_ready;
45
ActivityTagsForm(QWidget * parent)46 ActivityTagsForm::ActivityTagsForm(QWidget* parent): QDialog(parent)
47 {
48 setupUi(this);
49
50 currentActivityTagTextEdit->setReadOnly(true);
51
52 renameActivityTagPushButton->setDefault(true);
53
54 activityTagsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
55
56 connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
57 connect(addActivityTagPushButton, SIGNAL(clicked()), this, SLOT(addActivityTag()));
58 connect(removeActivityTagPushButton, SIGNAL(clicked()), this, SLOT(removeActivityTag()));
59 connect(renameActivityTagPushButton, SIGNAL(clicked()), this, SLOT(renameActivityTag()));
60
61 connect(moveActivityTagUpPushButton, SIGNAL(clicked()), this, SLOT(moveActivityTagUp()));
62 connect(moveActivityTagDownPushButton, SIGNAL(clicked()), this, SLOT(moveActivityTagDown()));
63
64 connect(sortActivityTagsPushButton, SIGNAL(clicked()), this, SLOT(sortActivityTags()));
65 connect(activityTagsListWidget, SIGNAL(currentRowChanged(int)), this, SLOT(activityTagChanged(int)));
66 connect(activateActivityTagPushButton, SIGNAL(clicked()), this, SLOT(activateActivityTag()));
67 connect(deactivateActivityTagPushButton, SIGNAL(clicked()), this, SLOT(deactivateActivityTag()));
68 connect(activityTagsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(renameActivityTag()));
69 connect(helpPushButton, SIGNAL(clicked()), this, SLOT(help()));
70
71 connect(printablePushButton, SIGNAL(clicked()), this, SLOT(printableActivityTag()));
72 connect(notPrintablePushButton, SIGNAL(clicked()), this, SLOT(notPrintableActivityTag()));
73
74 connect(commentsPushButton, SIGNAL(clicked()), this, SLOT(comments()));
75
76 centerWidgetOnScreen(this);
77 restoreFETDialogGeometry(this);
78 //restore splitter state
79 QSettings settings(COMPANY, PROGRAM);
80 if(settings.contains(this->metaObject()->className()+QString("/splitter-state")))
81 splitter->restoreState(settings.value(this->metaObject()->className()+QString("/splitter-state")).toByteArray());
82
83 activityTagsListWidget->clear();
84 for(int i=0; i<gt.rules.activityTagsList.size(); i++){
85 ActivityTag* at=gt.rules.activityTagsList[i];
86 activityTagsListWidget->addItem(at->name);
87 }
88
89 if(activityTagsListWidget->count()>0)
90 activityTagsListWidget->setCurrentRow(0);
91 }
92
93
~ActivityTagsForm()94 ActivityTagsForm::~ActivityTagsForm()
95 {
96 saveFETDialogGeometry(this);
97 //save splitter state
98 QSettings settings(COMPANY, PROGRAM);
99 settings.setValue(this->metaObject()->className()+QString("/splitter-state"), splitter->saveState());
100 }
101
addActivityTag()102 void ActivityTagsForm::addActivityTag()
103 {
104 bool ok = false;
105 ActivityTag* at=new ActivityTag();
106 at->name = QInputDialog::getText( this, tr("Add activity tag"), tr("Please enter activity tag's name") ,
107 QLineEdit::Normal, QString(), &ok );
108
109 if ( ok && !((at->name).isEmpty()) ){
110 // user entered something and pressed OK
111 if(!gt.rules.addActivityTag(at)){
112 QMessageBox::information( this, tr("Activity tag insertion dialog"),
113 tr("Could not insert item. Must be a duplicate"));
114 delete at;
115 }
116 else{
117 activityTagsListWidget->addItem(at->name);
118 activityTagsListWidget->setCurrentRow(activityTagsListWidget->count()-1);
119 }
120 }
121 else{
122 if(ok){ //the user entered nothing
123 QMessageBox::information(this, tr("FET information"), tr("Incorrect name"));
124 }
125 delete at;// user entered nothing or pressed Cancel
126 }
127 }
128
removeActivityTag()129 void ActivityTagsForm::removeActivityTag()
130 {
131 int i=activityTagsListWidget->currentRow();
132 if(activityTagsListWidget->currentRow()<0){
133 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
134 return;
135 }
136
137 QString text=activityTagsListWidget->currentItem()->text();
138 int activity_tag_ID=gt.rules.searchActivityTag(text);
139 if(activity_tag_ID<0){
140 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
141 return;
142 }
143
144 /*if(QMessageBox::warning( this, tr("FET"),
145 tr("Are you sure you want to delete this activity tag?"),
146 tr("Yes"), tr("No"), 0, 0, 1 ) == 1)
147 return;*/
148 if(QMessageBox::warning( this, tr("FET"),
149 tr("Are you sure you want to delete this activity tag?"),
150 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
151 return;
152
153 int tmp=gt.rules.removeActivityTag(text);
154 if(tmp){
155 activityTagsListWidget->setCurrentRow(-1);
156 QListWidgetItem* item;
157 item=activityTagsListWidget->takeItem(i);
158 delete item;
159
160 if(i>=activityTagsListWidget->count())
161 i=activityTagsListWidget->count()-1;
162 if(i>=0)
163 activityTagsListWidget->setCurrentRow(i);
164 else
165 currentActivityTagTextEdit->setPlainText(QString(""));
166 }
167 }
168
renameActivityTag()169 void ActivityTagsForm::renameActivityTag()
170 {
171 int i=activityTagsListWidget->currentRow();
172 if(activityTagsListWidget->currentRow()<0){
173 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
174 return;
175 }
176
177 QString initialActivityTagName=activityTagsListWidget->currentItem()->text();
178
179 int activity_tag_ID=gt.rules.searchActivityTag(initialActivityTagName);
180 if(activity_tag_ID<0){
181 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
182 return;
183 }
184
185 bool ok = false;
186 QString finalActivityTagName;
187 finalActivityTagName = QInputDialog::getText( this, tr("Rename activity tag"), tr("Please enter new activity tag's name") ,
188 QLineEdit::Normal, initialActivityTagName, &ok );
189
190 if ( ok && !(finalActivityTagName.isEmpty()) ){
191 // user entered something and pressed OK
192 if(gt.rules.searchActivityTag(finalActivityTagName)>=0){
193 QMessageBox::information( this, tr("Activity tag insertion dialog"),
194 tr("Could not modify item. New name must be a duplicate"));
195 }
196 else{
197 gt.rules.modifyActivityTag(initialActivityTagName, finalActivityTagName);
198 activityTagsListWidget->item(i)->setText(finalActivityTagName);
199 activityTagChanged(activityTagsListWidget->currentRow());
200 }
201 }
202 }
203
moveActivityTagUp()204 void ActivityTagsForm::moveActivityTagUp()
205 {
206 if(activityTagsListWidget->count()<=1)
207 return;
208 int i=activityTagsListWidget->currentRow();
209 if(i<0 || i>=activityTagsListWidget->count())
210 return;
211 if(i==0)
212 return;
213
214 QString s1=activityTagsListWidget->item(i)->text();
215 QString s2=activityTagsListWidget->item(i-1)->text();
216
217 ActivityTag* at1=gt.rules.activityTagsList.at(i);
218 ActivityTag* at2=gt.rules.activityTagsList.at(i-1);
219
220 gt.rules.internalStructureComputed=false;
221 setRulesModifiedAndOtherThings(>.rules);
222
223 teachers_schedule_ready=false;
224 students_schedule_ready=false;
225 rooms_schedule_ready=false;
226
227 activityTagsListWidget->item(i)->setText(s2);
228 activityTagsListWidget->item(i-1)->setText(s1);
229
230 gt.rules.activityTagsList[i]=at2;
231 gt.rules.activityTagsList[i-1]=at1;
232
233 activityTagsListWidget->setCurrentRow(i-1);
234 activityTagChanged(i-1);
235 }
236
moveActivityTagDown()237 void ActivityTagsForm::moveActivityTagDown()
238 {
239 if(activityTagsListWidget->count()<=1)
240 return;
241 int i=activityTagsListWidget->currentRow();
242 if(i<0 || i>=activityTagsListWidget->count())
243 return;
244 if(i==activityTagsListWidget->count()-1)
245 return;
246
247 QString s1=activityTagsListWidget->item(i)->text();
248 QString s2=activityTagsListWidget->item(i+1)->text();
249
250 ActivityTag* at1=gt.rules.activityTagsList.at(i);
251 ActivityTag* at2=gt.rules.activityTagsList.at(i+1);
252
253 gt.rules.internalStructureComputed=false;
254 setRulesModifiedAndOtherThings(>.rules);
255
256 teachers_schedule_ready=false;
257 students_schedule_ready=false;
258 rooms_schedule_ready=false;
259
260 activityTagsListWidget->item(i)->setText(s2);
261 activityTagsListWidget->item(i+1)->setText(s1);
262
263 gt.rules.activityTagsList[i]=at2;
264 gt.rules.activityTagsList[i+1]=at1;
265
266 activityTagsListWidget->setCurrentRow(i+1);
267 activityTagChanged(i+1);
268 }
269
sortActivityTags()270 void ActivityTagsForm::sortActivityTags()
271 {
272 gt.rules.sortActivityTagsAlphabetically();
273
274 activityTagsListWidget->clear();
275 for(int i=0; i<gt.rules.activityTagsList.size(); i++){
276 ActivityTag* at=gt.rules.activityTagsList[i];
277 activityTagsListWidget->addItem(at->name);
278 }
279
280 if(activityTagsListWidget->count()>0)
281 activityTagsListWidget->setCurrentRow(0);
282 }
283
activityTagChanged(int index)284 void ActivityTagsForm::activityTagChanged(int index)
285 {
286 if(index<0){
287 currentActivityTagTextEdit->setPlainText(QString(""));
288 return;
289 }
290
291 ActivityTag* st=gt.rules.activityTagsList.at(index);
292 assert(st);
293 QString s=st->getDetailedDescriptionWithConstraints(gt.rules);
294 currentActivityTagTextEdit->setPlainText(s);
295 }
296
activateActivityTag()297 void ActivityTagsForm::activateActivityTag()
298 {
299 if(activityTagsListWidget->currentRow()<0){
300 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
301 return;
302 }
303
304 QString text=activityTagsListWidget->currentItem()->text();
305 int count=gt.rules.activateActivityTag(text);
306 QMessageBox::information(this, tr("FET information"), tr("Activated a number of %1 activities").arg(count));
307 }
308
deactivateActivityTag()309 void ActivityTagsForm::deactivateActivityTag()
310 {
311 if(activityTagsListWidget->currentRow()<0){
312 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
313 return;
314 }
315
316 QString text=activityTagsListWidget->currentItem()->text();
317 int count=gt.rules.deactivateActivityTag(text);
318 QMessageBox::information(this, tr("FET information"), tr("De-activated a number of %1 activities").arg(count));
319 }
320
printableActivityTag()321 void ActivityTagsForm::printableActivityTag()
322 {
323 if(activityTagsListWidget->currentRow()<0){
324 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
325 return;
326 }
327
328 QString text=activityTagsListWidget->currentItem()->text();
329
330 gt.rules.makeActivityTagPrintable(text);
331
332 activityTagChanged(activityTagsListWidget->currentRow());
333 }
334
notPrintableActivityTag()335 void ActivityTagsForm::notPrintableActivityTag()
336 {
337 if(activityTagsListWidget->currentRow()<0){
338 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
339 return;
340 }
341
342 QString text=activityTagsListWidget->currentItem()->text();
343
344 gt.rules.makeActivityTagNotPrintable(text);
345
346 activityTagChanged(activityTagsListWidget->currentRow());
347 }
348
help()349 void ActivityTagsForm::help()
350 {
351 QMessageBox::information(this, tr("FET help on activity tags"),
352 tr("Activity tag is a field which can be used or not, depending on your wish (optional field)."
353 " It is designed to help you with some constraints. Each activity has a list of activity tags"
354 " (which may be empty)."));
355 }
356
comments()357 void ActivityTagsForm::comments()
358 {
359 int ind=activityTagsListWidget->currentRow();
360 if(ind<0){
361 QMessageBox::information(this, tr("FET information"), tr("Invalid selected activity tag"));
362 return;
363 }
364
365 ActivityTag* at=gt.rules.activityTagsList[ind];
366 assert(at!=nullptr);
367
368 QDialog getCommentsDialog(this);
369
370 getCommentsDialog.setWindowTitle(tr("Activity tag comments"));
371
372 QPushButton* okPB=new QPushButton(tr("OK"));
373 okPB->setDefault(true);
374 QPushButton* cancelPB=new QPushButton(tr("Cancel"));
375
376 connect(okPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(accept()));
377 connect(cancelPB, SIGNAL(clicked()), &getCommentsDialog, SLOT(reject()));
378
379 QHBoxLayout* hl=new QHBoxLayout();
380 hl->addStretch();
381 hl->addWidget(okPB);
382 hl->addWidget(cancelPB);
383
384 QVBoxLayout* vl=new QVBoxLayout();
385
386 QPlainTextEdit* commentsPT=new QPlainTextEdit();
387 commentsPT->setPlainText(at->comments);
388 commentsPT->selectAll();
389 commentsPT->setFocus();
390
391 vl->addWidget(commentsPT);
392 vl->addLayout(hl);
393
394 getCommentsDialog.setLayout(vl);
395
396 const QString settingsName=QString("ActivityTagCommentsDialog");
397
398 getCommentsDialog.resize(500, 320);
399 centerWidgetOnScreen(&getCommentsDialog);
400 restoreFETDialogGeometry(&getCommentsDialog, settingsName);
401
402 int t=getCommentsDialog.exec();
403 saveFETDialogGeometry(&getCommentsDialog, settingsName);
404
405 if(t==QDialog::Accepted){
406 at->comments=commentsPT->toPlainText();
407
408 gt.rules.internalStructureComputed=false;
409 setRulesModifiedAndOtherThings(>.rules);
410
411 activityTagChanged(ind);
412 }
413 }
414