1 /*
2 File import.cpp
3 */
4 
5 /***************************************************************************
6                                 FET
7                           -------------------
8    copyright            : (C) by Lalescu Liviu
9     email                : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
10  ***************************************************************************
11                           import.cpp  -  description
12                              -------------------
13     begin                : Mar 2008
14     copyright            : (C) by Volker Dirr
15                          : https://www.timetabling.de/
16  ***************************************************************************
17  *                                                                         *
18  *   This program is free software: you can redistribute it and/or modify  *
19  *   it under the terms of the GNU Affero General Public License as        *
20  *   published by the Free Software Foundation, either version 3 of the    *
21  *   License, or (at your option) any later version.                       *
22  *                                                                         *
23  ***************************************************************************/
24 
25 // Code contributed by Volker Dirr ( https://www.timetabling.de/ )
26 
27 //TODO: import days per week
28 //TODO: import hours per day
29 
30 #include "import.h"
31 
32 #include <Qt>
33 
34 #include <QtGlobal>
35 
36 #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
37 #include <QtWidgets>
38 #else
39 #include <QtGui>
40 #endif
41 
42 #include <QProgressDialog>
43 
44 #include <QSet>
45 #include <QHash>
46 #include <QList>
47 #include <QPair>
48 
49 extern Timetable gt;
50 
51 // maybe I can add some of them again as parameter into function name?
52 // it is not possible with fieldNumber and fieldName, because that conflicts with the using of command connect with chooseFieldsDialogUpdate (there are no parameters possible)
53 static QString fileName;				// file name of the csv file
54 
55 static QString fieldSeparator=",";
56 static QString textquote="\"";
57 static QString setSeparator="+";
58 
59 static QString importThing;
60 
61 static int numberOfFields;				// number of fields per line of the csv file
62 static QStringList fields;				// list of the fields of the first line of the csv file
63 static bool head;					// true = first line of csv file contain heading, so skip this line
64 static QString fieldName[NUMBER_OF_FIELDS];		// field name (normally similar to the head)
65 static int fieldNumber[NUMBER_OF_FIELDS];		// field number in the csv file
66 							// fieldNumber >= 0 is the number of the field
67 							// fieldNumber can also be IMPORT_DEFAULT_ITEM (==IMPORT_DEFAULT_ITEM). That mean that items of fieldList get the name of fieldDefaultItem (not of field[fieldNumber] from csv
68 							// fieldNumber can also be DO_NOT_IMPORT (==-2). That mean that items are not imported into fieldList.
69 static QStringList fieldList[NUMBER_OF_FIELDS];	// items of the fields (items from "field number")
70 static QString fieldDefaultItem[NUMBER_OF_FIELDS];	// used, if fieldNumber == IMPORT_DEFAULT_ITEM
71 static QString warnText;				// warnings about the csv file
72 static QStringList dataWarning;			// warnings about the current conflicts between the csv file and the data that is already in memory
73 static QString lastWarning;
74 
chooseWidth(int w)75 int Import::chooseWidth(int w)
76 {
77 	int ww=w;
78 	if(ww>1000)
79 		ww=1000;
80 
81 	return ww;
82 }
83 
chooseHeight(int h)84 int Import::chooseHeight(int h)
85 {
86 	int hh=h;
87 	if(hh>650)
88 		hh=650;
89 
90 	return hh;
91 }
92 
Import()93 Import::Import()
94 {
95 }
96 
~Import()97 Import::~Import()
98 {
99 }
100 
prearrangement()101 void Import::prearrangement(){
102 	assert(gt.rules.initialized);
103 
104 	fieldName[FIELD_LINE_NUMBER]=Import::tr("Line");
105 	fieldName[FIELD_YEAR_NAME]=Import::tr("Year");
106 	fieldName[FIELD_YEAR_NUMBER_OF_STUDENTS]=Import::tr("Number of Students per Year");
107 	fieldName[FIELD_GROUP_NAME]=Import::tr("Group");
108 	fieldName[FIELD_GROUP_NUMBER_OF_STUDENTS]=Import::tr("Number of Students per Group");
109 	fieldName[FIELD_SUBGROUP_NAME]=Import::tr("Subgroup");
110 	fieldName[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]=Import::tr("Number of Students per Subgroup");
111 	fieldName[FIELD_SUBJECT_NAME]=Import::tr("Subject");
112 	fieldName[FIELD_ACTIVITY_TAG_NAME]=Import::tr("Activity Tag");
113 	fieldName[FIELD_TEACHER_NAME]=Import::tr("Teacher");
114 	fieldName[FIELD_BUILDING_NAME]=Import::tr("Building");
115 	fieldName[FIELD_ROOM_NAME]=Import::tr("Room Name");
116 	fieldName[FIELD_ROOM_CAPACITY]=Import::tr("Room Capacity");
117 	fieldName[FIELD_STUDENTS_SET]=Import::tr("Students Sets");
118 	fieldName[FIELD_TEACHERS_SET]=Import::tr("Teachers");
119 	fieldName[FIELD_TOTAL_DURATION]=Import::tr("Total Duration");
120 	fieldName[FIELD_SPLIT_DURATION]=Import::tr("Split Duration");
121 	fieldName[FIELD_MIN_DAYS]=Import::tr("Min Days");
122 	fieldName[FIELD_MIN_DAYS_WEIGHT]=Import::tr("Min Days Weight");
123 	fieldName[FIELD_MIN_DAYS_CONSECUTIVE]=Import::tr("Min Days Consecutive");
124 	fieldName[FIELD_ACTIVITY_TAGS_SET]=Import::tr("Activity Tags");
125 	fieldName[FIELD_COMMENTS]=Import::tr("Comments");
126 	for(int i=0; i<NUMBER_OF_FIELDS; i++){
127 		fieldNumber[i]=DO_NOT_IMPORT;
128 		fieldDefaultItem[i]="";
129 		fieldList[i].clear();
130 	}
131 	fieldNumber[FIELD_LINE_NUMBER]=IMPORT_DEFAULT_ITEM;
132 	fieldDefaultItem[FIELD_LINE_NUMBER]=Import::tr("line");
133 	dataWarning.clear();
134 	warnText.clear();
135 	lastWarning.clear();
136 }
137 
138 //TODO: add this into the first function!? form too full?!
ChooseFieldsDialog(QWidget * parent)139 ChooseFieldsDialog::ChooseFieldsDialog(QWidget *parent): QDialog(parent)
140 {
141 	assert(fields.size()>0);
142 
143 	this->setWindowTitle(tr("FET - Import from CSV file"));
144 	QGridLayout* chooseFieldsMainLayout=new QGridLayout(this);
145 
146 	QVBoxLayout* fieldBox[NUMBER_OF_FIELDS];
147 	QHBoxLayout* fieldLine1[NUMBER_OF_FIELDS];
148 	QHBoxLayout* fieldLine2[NUMBER_OF_FIELDS];
149 	QHBoxLayout* fieldLine3[NUMBER_OF_FIELDS];
150 	QHBoxLayout* fieldLine3b[NUMBER_OF_FIELDS];
151 
152 	int gridRow=0;
153 	int gridColumn=0;
154 	for(int i=1; i<NUMBER_OF_FIELDS; i++){
155 		assert(fieldNumber[i]==DO_NOT_IMPORT || fieldNumber[i]==IMPORT_DEFAULT_ITEM);
156 		fieldGroupBox[i] = new QGroupBox(Import::tr("Please specify the %1 field:").arg(fieldName[i]));
157 		fieldBox[i] = new QVBoxLayout();
158 		fieldRadio1[i] = new QRadioButton(Import::tr("Don't import \"%1\".").arg(fieldName[i]));
159 		fieldRadio2[i] = new QRadioButton(Import::tr("Import this field from CSV:"));
160 
161 		//trick to keep the translation active, maybe we need it in the future
162 		QString s=Import::tr("Set always the same name:");
163 		Q_UNUSED(s);
164 
165 		//fieldRadio3[i] = new QRadioButton(Import::tr("Set always the same name:"));
166 		fieldRadio3[i] = new QRadioButton(Import::tr("Set always the same value:")); //modified by Liviu on 18 March 2009
167 		fieldRadio3b[i] = new QRadioButton(Import::tr("Set always the same value:"));
168 
169 		fieldLine1[i] = new QHBoxLayout();
170 		fieldLine1[i]->addWidget(fieldRadio1[i]);
171 		fieldBox[i]->addLayout(fieldLine1[i]);
172 
173 		fieldLine2CB[i] = new QComboBox();
174 		fieldLine2CB[i]->setMaximumWidth(220);			//max
175 		fieldLine2CB[i]->insertItems(0,fields);
176 		fieldLine2[i] = new QHBoxLayout();
177 		fieldLine2[i]->addWidget(fieldRadio2[i]);
178 		fieldLine2[i]->addWidget(fieldLine2CB[i]);
179 		fieldBox[i]->addLayout(fieldLine2[i]);
180 		fieldRadio2[i]->setChecked(true);
181 
182 		fieldLine3Text[i] = new QLineEdit(Import::tr("Please modify this text."));
183 //		fieldLine3Text[i]->setMaximumWidth(220);		//max
184 		fieldLine3[i] = new QHBoxLayout();
185 		fieldLine3[i]->addWidget(fieldRadio3[i]);
186 
187 		//Added by Liviu - 18 March 2009, so that the dialog looks nice when dialog is maximized
188 
189 		//TODO: add this line or not???
190 		fieldLine3[i]->addStretch();
191 		//If you uncomment the line below, please include the header <QSizePolicy> at the beginning of the file (though it is probably just a matter of aesthetics).
192 		//fieldLine3Text[i]->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
193 
194 		fieldLine3[i]->addWidget(fieldLine3Text[i]);
195 		fieldBox[i]->addLayout(fieldLine3[i]);
196 
197 		fieldLine3bSpinBox[i] = new QSpinBox();
198 		fieldLine3bSpinBox[i]->setMaximumWidth(220);		//max
199 		fieldLine3b[i] = new QHBoxLayout();
200 		fieldLine3b[i]->addWidget(fieldRadio3b[i]);
201 		fieldLine3b[i]->addWidget(fieldLine3bSpinBox[i]);
202 		fieldBox[i]->addLayout(fieldLine3b[i]);
203 
204 		fieldGroupBox[i]->setLayout(fieldBox[i]);
205 		chooseFieldsMainLayout->addWidget(fieldGroupBox[i], gridRow, gridColumn);
206 		if(fieldNumber[i]==DO_NOT_IMPORT)
207 			fieldGroupBox[i]->hide();
208 		else {
209 			if(gridColumn==1){
210 				gridColumn=0;
211 				gridRow++;
212 			} else
213 				gridColumn++;
214 		}
215 
216 		if(i==FIELD_YEAR_NAME || i==FIELD_TEACHER_NAME)
217 			fieldRadio1[i]->hide();
218 		if(i==FIELD_ROOM_CAPACITY){
219 			fieldRadio1[i]->hide();
220 			fieldLine3bSpinBox[i]->setMaximum(MAX_ROOM_CAPACITY);
221 			fieldLine3bSpinBox[i]->setMinimum(0);
222 			fieldLine3bSpinBox[i]->setValue(MAX_ROOM_CAPACITY);
223 			fieldRadio3b[i]->setChecked(true);
224 			fieldRadio3[i]->hide();
225 			fieldLine3Text[i]->hide();
226 		} else if(i==FIELD_YEAR_NUMBER_OF_STUDENTS || i==FIELD_GROUP_NUMBER_OF_STUDENTS || i==FIELD_SUBGROUP_NUMBER_OF_STUDENTS){
227 			fieldRadio1[i]->hide();
228 			fieldLine3bSpinBox[i]->setMaximum(MAX_TOTAL_SUBGROUPS);
229 			fieldLine3bSpinBox[i]->setMinimum(0);
230 			fieldLine3bSpinBox[i]->setValue(0);
231 			fieldRadio3b[i]->setChecked(true);
232 			fieldRadio3[i]->hide();
233 			fieldLine3Text[i]->hide();
234 		} else {
235 			fieldRadio3b[i]->hide();
236 			fieldLine3bSpinBox[i]->hide();
237 		}
238 		if(i==FIELD_SUBJECT_NAME){
239 			fieldRadio1[i]->hide();
240 			fieldRadio3[i]->hide();
241 			fieldLine3Text[i]->hide();
242 		}
243 		if(i==FIELD_ACTIVITY_TAG_NAME){
244 			fieldRadio1[i]->hide();
245 			fieldRadio3[i]->hide();
246 			fieldLine3Text[i]->hide();
247 		}
248 		if(i==FIELD_ROOM_NAME){
249 			fieldRadio3[i]->hide();
250 			fieldLine3Text[i]->hide();
251 		}
252 
253 		if(i==FIELD_TOTAL_DURATION){
254 			fieldRadio1[i]->hide();
255 			fieldLine3Text[i]->setText("1");
256 		}
257 		if(i==FIELD_SPLIT_DURATION){
258 			fieldRadio1[i]->hide();
259 			fieldLine3Text[i]->setText("1");
260 		}
261 		if(i==FIELD_MIN_DAYS){
262 			fieldRadio1[i]->hide();
263 			fieldLine3Text[i]->setText("1");
264 		}
265 		if(i==FIELD_MIN_DAYS_WEIGHT){
266 			fieldRadio1[i]->hide();
267 			fieldLine3Text[i]->setText("95");
268 		}
269 		if(i==FIELD_MIN_DAYS_CONSECUTIVE){
270 			fieldRadio1[i]->hide();
271 			fieldLine3Text[i]->setText("1");
272 		}
273 	}
274 
275 	gridRow++;
276 	/*
277 	pb=new QPushButton(tr("OK"));
278 	chooseFieldsMainLayout->addWidget(pb,gridRow,1);
279 	cancelpb=new QPushButton(tr("Cancel"));
280 	chooseFieldsMainLayout->addWidget(cancelpb,gridRow,2);*/
281 	pb=new QPushButton(tr("OK"));
282 	cancelpb=new QPushButton(tr("Cancel"));
283 	buttonsLayout=new QHBoxLayout();
284 	buttonsLayout->addStretch();
285 	buttonsLayout->addWidget(pb);
286 	buttonsLayout->addWidget(cancelpb);
287 	chooseFieldsMainLayout->addLayout(buttonsLayout,gridRow,1);
288 
289 	chooseFieldsDialogUpdateRadio1();
290 	chooseFieldsDialogUpdateRadio2();
291 	chooseFieldsDialogUpdateRadio3();
292 	chooseFieldsDialogUpdateRadio3b();
293 
294 	//connect(pb, SIGNAL(clicked()), this, SLOT(accept()));
295 	connect(pb, SIGNAL(clicked()), this, SLOT(chooseFieldsDialogClose()));
296 	connect(cancelpb, SIGNAL(clicked()), this, SLOT(reject()));
297 	for(int i=1; i<NUMBER_OF_FIELDS; i++){
298 		connect(fieldRadio1[i], SIGNAL(toggled(bool)), this, SLOT(chooseFieldsDialogUpdateRadio1()));
299 		connect(fieldRadio2[i], SIGNAL(toggled(bool)), this, SLOT(chooseFieldsDialogUpdateRadio2()));
300 		connect(fieldRadio3[i], SIGNAL(toggled(bool)), this, SLOT(chooseFieldsDialogUpdateRadio3()));
301 		connect(fieldRadio3b[i], SIGNAL(toggled(bool)), this, SLOT(chooseFieldsDialogUpdateRadio3b()));
302 		connect(fieldLine3Text[i], SIGNAL(textChanged(QString)), this, SLOT(chooseFieldsDialogUpdateLine3Text()));
303 	}
304 
305 	pb->setDefault(true);
306 	pb->setFocus();
307 
308 	//_settingsName=settingsName;
309 	//restoreFETDialogGeometry(this, _settingsName);
310 }
311 
~ChooseFieldsDialog()312 ChooseFieldsDialog::~ChooseFieldsDialog()
313 {
314 	//saveFETDialogGeometry(this, _settingsName);
315 }
316 
chooseFieldsDialogUpdateRadio1()317 void ChooseFieldsDialog::chooseFieldsDialogUpdateRadio1(){
318 	if(fieldRadio1[FIELD_GROUP_NAME]->isChecked()){
319 		fieldRadio1[FIELD_GROUP_NUMBER_OF_STUDENTS]->setChecked(true);
320 		fieldRadio1[FIELD_SUBGROUP_NAME]->setChecked(true);
321 		fieldRadio1[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setChecked(true);
322 		fieldGroupBox[FIELD_GROUP_NUMBER_OF_STUDENTS]->setDisabled(true);
323 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(true);
324 		fieldGroupBox[FIELD_SUBGROUP_NAME]->setDisabled(true);
325 	}
326 	if(fieldRadio1[FIELD_SUBGROUP_NAME]->isChecked()){
327 		fieldRadio1[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setChecked(true);
328 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(true);
329 	}
330 	if(fieldRadio1[FIELD_ROOM_NAME]->isChecked()){
331 		fieldRadio1[FIELD_ROOM_CAPACITY]->setChecked(true);
332 		fieldGroupBox[FIELD_ROOM_CAPACITY]->setDisabled(true);
333 	}
334 	if(fieldRadio1[FIELD_BUILDING_NAME]->isChecked()&&fieldRadio1[FIELD_ROOM_NAME]->isChecked()){
335 		pb->setDisabled(true);
336 	}
337 	if((fieldRadio1[FIELD_BUILDING_NAME]->isChecked()&&!fieldRadio1[FIELD_ROOM_NAME]->isChecked()&&fieldLine3Text[FIELD_BUILDING_NAME]->displayText()!="")
338 		||(!fieldRadio1[FIELD_BUILDING_NAME]->isChecked()&&fieldRadio1[FIELD_ROOM_NAME]->isChecked()&&fieldLine3Text[FIELD_BUILDING_NAME]->displayText()!="")){
339 		pb->setDisabled(false);
340 	}
341 }
342 
chooseFieldsDialogUpdateRadio2()343 void ChooseFieldsDialog::chooseFieldsDialogUpdateRadio2(){
344 	if(fieldRadio2[FIELD_GROUP_NAME]->isChecked()){
345 		fieldGroupBox[FIELD_SUBGROUP_NAME]->setDisabled(false);
346 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
347 		fieldGroupBox[FIELD_GROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
348 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
349 		if(fieldRadio1[FIELD_GROUP_NUMBER_OF_STUDENTS]->isChecked())
350 			fieldRadio3b[FIELD_GROUP_NUMBER_OF_STUDENTS]->setChecked(true);
351 		if(fieldRadio1[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->isChecked())
352 			fieldRadio3b[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setChecked(true);
353 	}
354 	if(fieldRadio2[FIELD_ROOM_NAME]->isChecked()){
355 		if(fieldRadio1[FIELD_ROOM_CAPACITY]->isChecked())
356 			fieldRadio3b[FIELD_ROOM_CAPACITY]->setChecked(true);
357 		fieldGroupBox[FIELD_ROOM_CAPACITY]->setDisabled(false);
358 	}
359 }
360 
chooseFieldsDialogUpdateRadio3()361 void ChooseFieldsDialog::chooseFieldsDialogUpdateRadio3(){
362 	if(fieldRadio3[FIELD_GROUP_NAME]->isChecked()){
363 		fieldGroupBox[FIELD_SUBGROUP_NAME]->setDisabled(false);
364 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
365 		fieldGroupBox[FIELD_GROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
366 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
367 		if(fieldRadio1[FIELD_GROUP_NUMBER_OF_STUDENTS]->isChecked())
368 			fieldRadio3b[FIELD_GROUP_NUMBER_OF_STUDENTS]->setChecked(true);
369 		if(fieldRadio1[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->isChecked())
370 			fieldRadio3b[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setChecked(true);
371 	}
372 	if(fieldRadio3[FIELD_ROOM_NAME]->isChecked()){
373 		if(fieldRadio1[FIELD_ROOM_CAPACITY]->isChecked())
374 			fieldRadio3b[FIELD_ROOM_CAPACITY]->setChecked(true);
375 		fieldGroupBox[FIELD_ROOM_CAPACITY]->setDisabled(false);
376 	}
377 }
378 
chooseFieldsDialogUpdateRadio3b()379 void ChooseFieldsDialog::chooseFieldsDialogUpdateRadio3b(){
380 	if(fieldRadio3b[FIELD_GROUP_NAME]->isChecked()){
381 		fieldGroupBox[FIELD_SUBGROUP_NAME]->setDisabled(false);
382 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
383 		fieldGroupBox[FIELD_GROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
384 		fieldGroupBox[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setDisabled(false);
385 		if(fieldRadio1[FIELD_GROUP_NUMBER_OF_STUDENTS]->isChecked())
386 			fieldRadio3b[FIELD_GROUP_NUMBER_OF_STUDENTS]->setChecked(true);
387 		if(fieldRadio1[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->isChecked())
388 			fieldRadio3b[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]->setChecked(true);
389 	}
390 	if(fieldRadio3b[FIELD_ROOM_NAME]->isChecked()){
391 		if(fieldRadio1[FIELD_ROOM_CAPACITY]->isChecked())
392 			fieldRadio3b[FIELD_ROOM_CAPACITY]->setChecked(true);
393 		fieldGroupBox[FIELD_ROOM_CAPACITY]->setDisabled(false);
394 	}
395 }
396 
chooseFieldsDialogUpdateLine3Text()397 void ChooseFieldsDialog::chooseFieldsDialogUpdateLine3Text(){
398 	bool textOK=true;
399 	for(int i=1; i<NUMBER_OF_FIELDS; i++){
400 		if(fieldLine3Text[i]->displayText()=="")
401 			textOK=false;
402 	}
403 	//by Liviu - always enabled
404 	if(1 || textOK)
405 		pb->setDisabled(false);
406 	else
407 		pb->setDisabled(true);
408 }
409 
chooseFieldsDialogClose()410 void ChooseFieldsDialog::chooseFieldsDialogClose(){
411 	for(int i=1; i<NUMBER_OF_FIELDS; i++){
412 		if(fieldNumber[i]!=DO_NOT_IMPORT){
413 			if(fieldRadio1[i]->isChecked()){
414 				fieldNumber[i]=DO_NOT_IMPORT;
415 			}
416 			if(fieldRadio2[i]->isChecked()){
417 				fieldNumber[i]=fieldLine2CB[i]->currentIndex();
418 				assert(fieldNumber[i]<fields.size());
419 				assert(fieldNumber[i]>=0);
420 			}
421 			if(fieldRadio3[i]->isChecked()){
422 				fieldNumber[i]=IMPORT_DEFAULT_ITEM;
423 				//fieldName[i]=fieldLine3CB[i]->currentText();
424 				fieldDefaultItem[i]=fieldLine3Text[i]->displayText();
425 			}
426 			if(fieldRadio3b[i]->isChecked()){
427 				fieldNumber[i]=IMPORT_DEFAULT_ITEM;
428 				fieldDefaultItem[i]=fieldLine3bSpinBox[i]->cleanText();
429 			}
430 		}
431 	}
432 
433 	this->accept();
434 }
435 
LastWarningsDialog(QWidget * parent)436 LastWarningsDialog::LastWarningsDialog(QWidget *parent): QDialog(parent)
437 {
438 	this->setWindowTitle(tr("FET - import %1 comment", "The comment of the importing of the category named %1").arg(importThing));
439 	QVBoxLayout* lastWarningsMainLayout=new QVBoxLayout(this);
440 
441 	QPlainTextEdit* lastWarningsText=new QPlainTextEdit();
442 	lastWarningsText->setMinimumWidth(500);				//width
443 	lastWarningsText->setMinimumHeight(250);
444 	lastWarningsText->setReadOnly(true);
445 	lastWarningsText->setWordWrapMode(QTextOption::NoWrap);
446 	lastWarningsText->setPlainText(lastWarning);
447 
448 	//Start Buttons
449 	QPushButton* pb1=new QPushButton(tr("&OK"));
450 	//pb1->setAutoDefault(true);
451 
452 	QHBoxLayout* hl=new QHBoxLayout();
453 	hl->addStretch();
454 	hl->addWidget(pb1);
455 
456 	//Start adding all into main layout
457 	lastWarningsMainLayout->addWidget(lastWarningsText);
458 	lastWarningsMainLayout->addLayout(hl);
459 
460 	QObject::connect(pb1, SIGNAL(clicked()), this, SLOT(accept()));
461 
462 	//pb1->setDefault(true);
463 
464 	pb1->setDefault(true);
465 	pb1->setFocus();
466 }
467 
~LastWarningsDialog()468 LastWarningsDialog::~LastWarningsDialog()
469 {
470 }
471 
472 // private funtions ---------------------------------------------------------------------------------------------------
getFileSeparatorFieldsAndHead(QWidget * parent,QDialog * & newParent)473 int Import::getFileSeparatorFieldsAndHead(QWidget* parent, QDialog* &newParent){
474 	assert(gt.rules.initialized);
475 
476 	newParent=((QDialog*)parent);
477 
478 	QString settingsName;
479 
480 	if(fieldNumber[FIELD_ACTIVITY_TAG_NAME]==IMPORT_DEFAULT_ITEM){
481 		importThing=Import::tr("activity tags");
482 		settingsName=QString("ImportActivityTagsSelectSeparatorsDialog");
483 	}
484 	if(fieldNumber[FIELD_ROOM_NAME]==IMPORT_DEFAULT_ITEM){
485 		importThing=Import::tr("buildings and rooms");
486 		settingsName=QString("ImportBuildingsRoomsSelectSeparatorsDialog");
487 	}
488 	if(fieldNumber[FIELD_TEACHER_NAME]==IMPORT_DEFAULT_ITEM){
489 		importThing=Import::tr("teachers");
490 		settingsName=QString("ImportTeachersSelectSeparatorsDialog");
491 	}
492 	if(fieldNumber[FIELD_SUBJECT_NAME]==IMPORT_DEFAULT_ITEM){
493 		importThing=Import::tr("subjects");
494 		settingsName=QString("ImportSubjectsSelectSeparatorsDialog");
495 	}
496 	if(fieldNumber[FIELD_YEAR_NAME]==IMPORT_DEFAULT_ITEM){
497 		importThing=Import::tr("years, groups and subgroups");
498 		settingsName=QString("ImportYearsGroupsSubgroupsSelectSeparatorsDialog");
499 	}
500 	if(fieldNumber[FIELD_STUDENTS_SET]==IMPORT_DEFAULT_ITEM){
501 		importThing=Import::tr("activities");
502 		settingsName=QString("ImportActivitiesSelectSeparatorsDialog");
503 	}
504 
505 	fileName=QFileDialog::getOpenFileName(parent, Import::tr("FET - Import %1 from CSV file").arg(importThing), IMPORT_DIRECTORY,
506 		Import::tr("Text Files")+" (*.csv *.dat *.txt)" + ";;" + Import::tr("All Files") + " (*)");
507 
508 	const QString NO_SEPARATOR_TRANSLATED=Import::tr("no separator");
509 	fieldSeparator=NO_SEPARATOR_TRANSLATED;	//needed, because a csv file contain maybe just one field!
510 	const QString NO_TEXTQUOTE_TRANSLATED=Import::tr("no textquote");
511 	textquote=NO_TEXTQUOTE_TRANSLATED;
512 	fields.clear();
513 	QFile file(fileName);
514 	if(fileName.isEmpty()){
515 		return false;
516 	}
517 	if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
518 		return false;
519 	}
520 	QTextStream in(&file);
521 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
522 	in.setEncoding(QStringConverter::Utf8);
523 #else
524 	in.setCodec("UTF-8");
525 #endif
526 	QString line = in.readLine();
527 	file.close();
528 
529 	if(line.size()<=0){
530 		QMessageBox::warning(parent, tr("FET warning"), tr("The first line of the file is empty. Please fix this."));
531 		return false;
532 	}
533 
534 	if(fieldNumber[FIELD_ACTIVITY_TAG_NAME]==IMPORT_DEFAULT_ITEM
535 		&& line.contains("\"Activity Tag\",\"Comments\"")
536 		&& line.size()<=QString("\"Activity Tag\",\"Comments\"").length()+1
537 		&& line.size()>=QString("\"Activity Tag\",\"Comments\"").length()){
538 		fieldNumber[FIELD_ACTIVITY_TAG_NAME]=0;
539 		fieldNumber[FIELD_COMMENTS]=1;
540 		head=true;
541 		fieldSeparator=",";
542 		textquote="\"";
543 		fields=line.split(fieldSeparator);
544 		return true;
545 	}
546 
547 	if(fieldNumber[FIELD_ACTIVITY_TAG_NAME]==IMPORT_DEFAULT_ITEM
548 		&& line.contains("Activity Tag,Comments")
549 		&& line.size()<=QString("Activity Tag,Comments").length()+1
550 		&& line.size()>=QString("Activity Tag,Comments").length()){
551 		fieldNumber[FIELD_ACTIVITY_TAG_NAME]=0;
552 		fieldNumber[FIELD_COMMENTS]=1;
553 		head=true;
554 		fieldSeparator=",";
555 		textquote="";
556 		fields=line.split(fieldSeparator);
557 		return true;
558 	}
559 
560 	if(fieldNumber[FIELD_ROOM_NAME]==IMPORT_DEFAULT_ITEM
561 		&& line.contains("\"Room\",\"Room Capacity\",\"Building\",\"Comments\"")
562 		&& line.size()<=QString("\"Room\",\"Room Capacity\",\"Building\",\"Comments\"").length()+1
563 		&& line.size()>=QString("\"Room\",\"Room Capacity\",\"Building\",\"Comments\"").length()){
564 		fieldNumber[FIELD_BUILDING_NAME]=2;
565 		fieldNumber[FIELD_ROOM_NAME]=0;
566 		fieldNumber[FIELD_ROOM_CAPACITY]=1;
567 		fieldNumber[FIELD_COMMENTS]=3;
568 		head=true;
569 		fieldSeparator=",";
570 		textquote="\"";
571 		fields=line.split(fieldSeparator);
572 		return true;
573 	}
574 
575 	if(fieldNumber[FIELD_ROOM_NAME]==IMPORT_DEFAULT_ITEM
576 		&& line.contains("Room,Room Capacity,Building,Comments")
577 		&& line.size()<=QString("Room,Room Capacity,Building,Comments").length()+1
578 		&& line.size()>=QString("Room,Room Capacity,Building,Comments").length()){
579 		fieldNumber[FIELD_BUILDING_NAME]=2;
580 		fieldNumber[FIELD_ROOM_NAME]=0;
581 		fieldNumber[FIELD_ROOM_CAPACITY]=1;
582 		fieldNumber[FIELD_COMMENTS]=3;
583 		head=true;
584 		fieldSeparator=",";
585 		textquote="";
586 		fields=line.split(fieldSeparator);
587 		return true;
588 	}
589 
590 	if(fieldNumber[FIELD_TEACHER_NAME]==IMPORT_DEFAULT_ITEM
591 		&& line.contains("\"Teacher\",\"Comments\"")
592 		&& line.size()<=QString("\"Teacher\",\"Comments\"").length()+1
593 		&& line.size()>=QString("\"Teacher\",\"Comments\"").length()){
594 		fieldNumber[FIELD_TEACHER_NAME]=0;
595 		fieldNumber[FIELD_COMMENTS]=1;
596 		head=true;
597 		fieldSeparator=",";
598 		textquote="\"";
599 		fields=line.split(fieldSeparator);
600 		return true;
601 	}
602 
603 	if(fieldNumber[FIELD_TEACHER_NAME]==IMPORT_DEFAULT_ITEM
604 		&& line.contains("Teacher,Comments")
605 		&& line.size()<=QString("Teacher,Comments").length()+1
606 		&& line.size()>=QString("Teacher,Comments").length()){
607 		fieldNumber[FIELD_TEACHER_NAME]=0;
608 		fieldNumber[FIELD_COMMENTS]=1;
609 		head=true;
610 		fieldSeparator=",";
611 		textquote="";
612 		fields=line.split(fieldSeparator);
613 		return true;
614 	}
615 
616 	if(fieldNumber[FIELD_SUBJECT_NAME]==IMPORT_DEFAULT_ITEM
617 		&& line.contains("\"Subject\",\"Comments\"")
618 		&& line.size()<=QString("\"Subject\",\"Comments\"").length()+1
619 		&& line.size()>=QString("\"Subject\",\"Comments\"").length()){
620 		fieldNumber[FIELD_SUBJECT_NAME]=0;
621 		fieldNumber[FIELD_COMMENTS]=1;
622 		head=true;
623 		fieldSeparator=",";
624 		textquote="\"";
625 		fields=line.split(fieldSeparator);
626 		return true;
627 	}
628 
629 	if(fieldNumber[FIELD_SUBJECT_NAME]==IMPORT_DEFAULT_ITEM
630 		&& line.contains("Subject,Comments")
631 		&& line.size()<=QString("Subject,Comments").length()+1
632 		&& line.size()>=QString("Subject,Comments").length()){
633 		fieldNumber[FIELD_SUBJECT_NAME]=0;
634 		fieldNumber[FIELD_COMMENTS]=1;
635 		head=true;
636 		fieldSeparator=",";
637 		textquote="";
638 		fields=line.split(fieldSeparator);
639 		return true;
640 	}
641 
642 	if(fieldNumber[FIELD_YEAR_NAME]==IMPORT_DEFAULT_ITEM
643 		&& line.contains("\"Year\",\"Number of Students per Year\",\"Group\",\"Number of Students per Group\",\"Subgroup\",\"Number of Students per Subgroup\",\"Comments\"")
644 		&& line.size()<=QString("\"Year\",\"Number of Students per Year\",\"Group\",\"Number of Students per Group\",\"Subgroup\",\"Number of Students per Subgroup\",\"Comments\"").length()+1
645 		&& line.size()>=QString("\"Year\",\"Number of Students per Year\",\"Group\",\"Number of Students per Group\",\"Subgroup\",\"Number of Students per Subgroup\",\"Comments\"").length()){
646 		fieldNumber[FIELD_YEAR_NAME]=0;
647 		fieldNumber[FIELD_YEAR_NUMBER_OF_STUDENTS]=1;
648 		fieldNumber[FIELD_GROUP_NAME]=2;
649 		fieldNumber[FIELD_GROUP_NUMBER_OF_STUDENTS]=3;
650 		fieldNumber[FIELD_SUBGROUP_NAME]=4;
651 		fieldNumber[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]=5;
652 		fieldNumber[FIELD_COMMENTS]=6;
653 		head=true;
654 		fieldSeparator=",";
655 		textquote="\"";
656 		fields=line.split(fieldSeparator);
657 		return true;
658 	}
659 
660 	if(fieldNumber[FIELD_YEAR_NAME]==IMPORT_DEFAULT_ITEM
661 		&& line.contains("Year,Number of Students per Year,Group,Number of Students per Group,Subgroup,Number of Students per Subgroup,Comments")
662 		&& line.size()<=QString("Year,Number of Students per Year,Group,Number of Students per Group,Subgroup,Number of Students per Subgroup,Comments").length()+1
663 		&& line.size()>=QString("Year,Number of Students per Year,Group,Number of Students per Group,Subgroup,Number of Students per Subgroup,Comments").length()){
664 		fieldNumber[FIELD_YEAR_NAME]=0;
665 		fieldNumber[FIELD_YEAR_NUMBER_OF_STUDENTS]=1;
666 		fieldNumber[FIELD_GROUP_NAME]=2;
667 		fieldNumber[FIELD_GROUP_NUMBER_OF_STUDENTS]=3;
668 		fieldNumber[FIELD_SUBGROUP_NAME]=4;
669 		fieldNumber[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]=5;
670 		fieldNumber[FIELD_COMMENTS]=6;
671 		head=true;
672 		fieldSeparator=",";
673 		textquote="";
674 		fields=line.split(fieldSeparator);
675 		return true;
676 	}
677 
678 	if(fieldNumber[FIELD_STUDENTS_SET]==IMPORT_DEFAULT_ITEM
679 		&& line.contains("\"Students Sets\",\"Subject\",\"Teachers\",\"Activity Tags\",\"Total Duration\",\"Split Duration\",\"Min Days\",\"Weight\",\"Consecutive\",\"Comments\"")
680 		&& line.size()<=QString("\"Students Sets\",\"Subject\",\"Teachers\",\"Activity Tags\",\"Total Duration\",\"Split Duration\",\"Min Days\",\"Weight\",\"Consecutive\",\"Comments\"").length()+1
681 		&& line.size()>=QString("\"Students Sets\",\"Subject\",\"Teachers\",\"Activity Tags\",\"Total Duration\",\"Split Duration\",\"Min Days\",\"Weight\",\"Consecutive\",\"Comments\"").length()){
682 		fieldNumber[FIELD_ACTIVITY_TAGS_SET]=3;
683 		fieldNumber[FIELD_SUBJECT_NAME]=1;
684 		fieldNumber[FIELD_STUDENTS_SET]=0;
685 		fieldNumber[FIELD_TEACHERS_SET]=2;
686 		fieldNumber[FIELD_TOTAL_DURATION]=4;
687 		fieldNumber[FIELD_SPLIT_DURATION]=5;
688 		fieldNumber[FIELD_MIN_DAYS]=6;
689 		fieldNumber[FIELD_MIN_DAYS_WEIGHT]=7;
690 		fieldNumber[FIELD_MIN_DAYS_CONSECUTIVE]=8;
691 		fieldNumber[FIELD_COMMENTS]=9;
692 		head=true;
693 		fieldSeparator=",";
694 		textquote="\"";
695 		fields=line.split(fieldSeparator);
696 		return true;
697 	}
698 
699 	if(fieldNumber[FIELD_STUDENTS_SET]==IMPORT_DEFAULT_ITEM
700 		&& line.contains("Students Sets,Subject,Teachers,Activity Tags,Total Duration,Split Duration,Min Days,Weight,Consecutive,Comments")
701 		&& line.size()<=QString("Students Sets,Subject,Teachers,Activity Tags,Total Duration,Split Duration,Min Days,Weight,Consecutive,Comments").length()+1
702 		&& line.size()>=QString("Students Sets,Subject,Teachers,Activity Tags,Total Duration,Split Duration,Min Days,Weight,Consecutive,Comments").length()){
703 		fieldNumber[FIELD_ACTIVITY_TAGS_SET]=3;
704 		fieldNumber[FIELD_SUBJECT_NAME]=1;
705 		fieldNumber[FIELD_STUDENTS_SET]=0;
706 		fieldNumber[FIELD_TEACHERS_SET]=2;
707 		fieldNumber[FIELD_TOTAL_DURATION]=4;
708 		fieldNumber[FIELD_SPLIT_DURATION]=5;
709 		fieldNumber[FIELD_MIN_DAYS]=6;
710 		fieldNumber[FIELD_MIN_DAYS_WEIGHT]=7;
711 		fieldNumber[FIELD_MIN_DAYS_CONSECUTIVE]=8;
712 		fieldNumber[FIELD_COMMENTS]=9;
713 		head=true;
714 		fieldSeparator=",";
715 		textquote="";
716 		fields=line.split(fieldSeparator);
717 		return true;
718 	}
719 
720 	QStringList separators;
721 	QStringList textquotes;
722 	separators<<fieldSeparator;
723 	const int NO_SEPARATOR_POS=0; //it is the first element. It may have length > 1 QChar
724 	textquotes<<textquote;
725 	const int NO_TEXTQUOTE_POS=0; //it is the first element. It may have length > 1 QChar
726 	for(int i=0; i<line.size();i++){
727 		//if(!(line.at(i)>='A'&&line.at(i)<='Z')&&!(line.at(i)>='a'&&line.at(i)<='z')&&!(line.at(i)>='0'&&line.at(i)<='9')&&!separators.contains(line.at(i))){
728 		if(!(line.at(i).isLetterOrNumber())&&!separators.contains(line.at(i))){
729 			separators<<line.at(i);
730 			//careful: if you intend to add strings longer than one QChar, take care of assert in line 647 (below in the same function) (fieldSeparator.size()==1)
731 		}
732 		if(!(line.at(i).isLetterOrNumber())&&!textquotes.contains(line.at(i))){
733 			textquotes<<line.at(i);
734 			//careful: if you intend to add strings longer than one QChar, take care of assert in line 659 (below in the same function) (textquote.size()==1)
735 		}
736 	}
737 
738 	newParent=new QDialog(parent);
739 	QDialog& separatorsDialog=(*newParent);
740 	separatorsDialog.setWindowTitle(Import::tr("FET - Import %1 from CSV file").arg(importThing));
741 	QVBoxLayout* separatorsMainLayout=new QVBoxLayout(&separatorsDialog);
742 
743 	QHBoxLayout* top=new QHBoxLayout();
744 	QLabel* topText=new QLabel();
745 
746 	int tmpi=fileName.lastIndexOf(FILE_SEP);
747 	tmpi=fileName.size()-tmpi-1;
748 	QString shortFileName=fileName.right(tmpi);
749 	topText->setText(Import::tr("The first line of file\n%1\nis:").arg(shortFileName));
750 	top->addWidget(topText);
751 	top->addStretch();
752 	QPlainTextEdit* textOfFirstLine=new QPlainTextEdit();
753 	textOfFirstLine->setReadOnly(true);
754 	textOfFirstLine->setPlainText(line);
755 
756 	QGroupBox* separatorsGroupBox = new QGroupBox(Import::tr("Please specify the used separator between fields:"));
757 	QComboBox* separatorsCB=nullptr;
758 	if(separators.size()>1){
759 		QHBoxLayout* separatorBoxChoose=new QHBoxLayout();
760 		separatorsCB=new QComboBox();
761 
762 		QLabel* separatorTextChoose=new QLabel();
763 		separatorTextChoose->setText(Import::tr("Used field separator:"));
764 		separatorsCB->insertItems(0,separators);
765 		separatorBoxChoose->addWidget(separatorTextChoose);
766 		separatorBoxChoose->addWidget(separatorsCB);
767 		separatorsGroupBox->setLayout(separatorBoxChoose);
768 	}
769 
770 	QGroupBox* textquoteGroupBox = new QGroupBox(Import::tr("Please specify the used text quote of text fields:"));
771 	QComboBox* textquoteCB=nullptr;
772 	if(textquotes.size()>1){
773 		QHBoxLayout* textquoteBoxChoose=new QHBoxLayout();
774 		textquoteCB=new QComboBox();
775 
776 		QLabel* textquoteTextChoose=new QLabel();
777 		textquoteTextChoose->setText(Import::tr("Used textquote:"));
778 		textquoteCB->insertItems(0,textquotes);
779 		textquoteBoxChoose->addWidget(textquoteTextChoose);
780 		textquoteBoxChoose->addWidget(textquoteCB);
781 		textquoteGroupBox->setLayout(textquoteBoxChoose);
782 	}
783 
784 	QGroupBox* firstLineGroupBox = new QGroupBox(Import::tr("Please specify the contents of the first line:"));
785 	QVBoxLayout* firstLineChooseBox=new QVBoxLayout();
786 	QRadioButton* firstLineRadio1 = new QRadioButton(Import::tr("The first line is the heading. Don't import that line."));
787 	QRadioButton* firstLineRadio2 = new QRadioButton(Import::tr("The first line contains data. Import that line."));
788 	firstLineRadio1->setChecked(true);
789 	firstLineChooseBox->addWidget(firstLineRadio1);
790 	firstLineChooseBox->addWidget(firstLineRadio2);
791 	firstLineGroupBox->setLayout(firstLineChooseBox);
792 
793 	QPushButton* pb=new QPushButton(tr("OK"));
794 	QPushButton* cancelpb=new QPushButton(tr("Cancel"));
795 	QHBoxLayout* hl=new QHBoxLayout();
796 	hl->addStretch();
797 	hl->addWidget(pb);
798 	hl->addWidget(cancelpb);
799 
800 	separatorsMainLayout->addLayout(top);
801 	separatorsMainLayout->addWidget(textOfFirstLine);
802 	if(separators.size()>1){
803 		separatorsMainLayout->addWidget(separatorsGroupBox);
804 		separatorsMainLayout->addWidget(textquoteGroupBox);
805 	}
806 	else{
807 		delete separatorsGroupBox;
808 		delete textquoteGroupBox;
809 	}
810 	separatorsMainLayout->addWidget(firstLineGroupBox);
811 	separatorsMainLayout->addLayout(hl);
812 	QObject::connect(pb, SIGNAL(clicked()), &separatorsDialog, SLOT(accept()));
813 	QObject::connect(cancelpb, SIGNAL(clicked()), &separatorsDialog, SLOT(reject()));
814 
815 	pb->setDefault(true);
816 	pb->setFocus();
817 
818 	int w=chooseWidth(separatorsDialog.sizeHint().width());
819 	int h=chooseHeight(separatorsDialog.sizeHint().height());
820 	separatorsDialog.resize(w,h);
821 	centerWidgetOnScreen(&separatorsDialog);
822 	restoreFETDialogGeometry(&separatorsDialog, settingsName);
823 
824 	int ok=separatorsDialog.exec();
825 	saveFETDialogGeometry(&separatorsDialog, settingsName);
826 	if(!ok) return false;
827 
828 	if(separators.size()>1){
829 		assert(separatorsCB!=nullptr);
830 		assert(textquoteCB!=nullptr);
831 		fieldSeparator=separatorsCB->currentText();
832 
833 		if(separatorsCB->currentIndex()==NO_SEPARATOR_POS){
834 			assert(fieldSeparator==NO_SEPARATOR_TRANSLATED);
835 			fieldSeparator=QString("no sep"); //must have length >= 2
836 		}
837 		else{
838 			assert(fieldSeparator.size()==1);
839 			//assert(!fieldSeparator.at(0).isLetterOrNumber());
840 		}
841 
842 		textquote=textquoteCB->currentText();
843 
844 		if(textquoteCB->currentIndex()==NO_TEXTQUOTE_POS){
845 			assert(textquote==NO_TEXTQUOTE_TRANSLATED);
846 			textquote=QString("no tquote"); //must have length >= 2
847 		}
848 		else{
849 			assert(textquote.size()==1);
850 			//assert(!textquote.at(0).isLetterOrNumber());
851 		}
852 	}
853 	else{
854 		assert(separatorsCB==nullptr);
855 		assert(textquoteCB==nullptr);
856 		fieldSeparator="";
857 		textquote="";
858 	}
859 //NEW start
860 	QString tmp;
861 	QString tmpLine=line;
862 	while(!tmpLine.isEmpty()){
863 		tmp.clear();
864 		bool foundField=false;
865 		if(tmpLine.left(1)==textquote){
866 			tmpLine.remove(0,1);
867 			while(!foundField && tmpLine.size()>1){
868 				if(tmpLine.left(1)!=textquote){
869 					tmp+=tmpLine.left(1);
870 				} else {
871 					if(tmpLine.mid(1,1)==fieldSeparator){
872 						foundField=true;
873 						tmpLine.remove(0,1);
874 					} else if(tmpLine.mid(1,1)==textquote){
875 						tmp+=textquote;
876 						tmpLine.remove(0,1);
877 					} else {
878 						QMessageBox::critical(newParent, tr("FET warning"), Import::tr("Missing field separator or text quote in first line. Import might be incorrect.")+"\n");
879 					}
880 				}
881 				tmpLine.remove(0,1);
882 			}
883 			if(!foundField && tmpLine.size()==1){
884 				if(tmpLine.left(1)==textquote){
885 					tmpLine.remove(0,1);
886 				} else {
887 					QMessageBox::critical(newParent, tr("FET warning"), Import::tr("Missing closing text quote in first line. Import might be incorrect.")+"\n");
888 					tmp+=tmpLine.left(1);
889 					tmpLine.remove(0,1);
890 				}
891 
892 			}
893 		} else {
894 			while(!foundField && !tmpLine.isEmpty()){
895 				if(tmpLine.left(1)!=fieldSeparator)
896 					tmp+=tmpLine.left(1);
897 				else
898 					foundField=true;
899 				tmpLine.remove(0,1);
900 			}
901 		}
902 		fields << tmp;
903 		if(foundField && tmpLine.isEmpty())
904 			fields << "";
905 	}
906 //NEW end
907 
908 /* OLD
909 	if(separators.size()>1){
910 		fieldSeparator=separatorsCB->currentText();
911 		fields=line.split(fieldSeparator);
912 	} else {
913 		fieldSeparator=separators.takeFirst();
914 		fields<<line;
915 	}
916 OLD */
917 
918 	if(firstLineRadio1->isChecked())
919 		head=true;
920 	else head=false;
921 	return true;
922 }
923 
readFields(QWidget * parent)924 int Import::readFields(QWidget* parent){
925 	QSet<QString> checkSet;
926 	QString check;
927 	numberOfFields=fields.size();
928 	assert(numberOfFields>0);
929 	for(int i=0; i<NUMBER_OF_FIELDS; i++){
930 		assert(fieldNumber[i]<=numberOfFields);
931 		assert(fieldNumber[i]>=DO_NOT_IMPORT);
932 	}
933 
934 	QFile file(fileName);
935 	if(fileName.isEmpty()){
936 		QMessageBox::warning(parent, tr("FET warning"), tr("Empty filename."));
937 		return false;
938 	}
939 	if(!file.open(QIODevice::ReadOnly)){
940 		QMessageBox::warning(parent, tr("Error! Can't open file."), fileName);
941 		return false;
942 	}
943 	QTextStream in(&file);
944 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
945 	in.setEncoding(QStringConverter::Utf8);
946 #else
947 	in.setCodec("UTF-8");
948 #endif
949 
950 	qint64 size=file.size();
951 	QProgressDialog* _progress=new QProgressDialog(parent);
952 	QProgressDialog& progress=(*_progress);
953 	progress.setWindowTitle(tr("Importing", "Title of a progress dialog"));
954 	progress.setLabelText(tr("Loading file"));
955 	progress.setModal(true);
956 	progress.setRange(0, qMax(size, qint64(1)));
957 	//cout<<"progress in readFields starts"<<endl;
958 	qint64 crt=0;
959 
960 	QStringList fields;
961 	QString itemOfField[NUMBER_OF_FIELDS];
962 	int lineNumber=0;
963 	while(!in.atEnd()){
964 		progress.setValue(crt);
965 		QString line = in.readLine();
966 		lineNumber++;
967 		crt+=line.length();
968 		if(progress.wasCanceled()){
969 			progress.setValue(size);
970 			QMessageBox::warning(parent, "FET", Import::tr("Loading canceled by user."));
971 			file.close();
972 			return false;
973 		}
974 		bool ok=true;
975 		if(!(lineNumber==1&&head)){
976 			fields.clear();
977 			QString tmp;
978 			QString tmpLine=line;
979 			while(!tmpLine.isEmpty()){
980 				tmp.clear();
981 				bool foundField=false;
982 				if(tmpLine.left(1)==textquote){
983 					tmpLine.remove(0,1);
984 					while(!foundField && tmpLine.size()>1){
985 						if(tmpLine.left(1)!=textquote){
986 							tmp+=tmpLine.left(1);
987 						} else {
988 							if(tmpLine.mid(1,1)==fieldSeparator){
989 								foundField=true;
990 								tmpLine.remove(0,1);
991 							} else if(tmpLine.mid(1,1)==textquote){
992 								tmp+=textquote;
993 								tmpLine.remove(0,1);
994 							} else
995 								warnText+=Import::tr("Warning: FET expected field separator or text separator in line %1. Import might be incorrect.").arg(lineNumber)+"\n";
996 						}
997 						tmpLine.remove(0,1);
998 					}
999 					if(!foundField && tmpLine.size()==1){
1000 						if(tmpLine.left(1)==textquote){
1001 							tmpLine.remove(0,1);
1002 						} else {
1003 							warnText+=Import::tr("Warning: FET expected closing text separator in line %1. Import might be incorrect.").arg(lineNumber)+"\n";
1004 							tmp+=tmpLine.left(1);
1005 							tmpLine.remove(0,1);
1006 						}
1007 
1008 					}
1009 				} else {
1010 					while(!foundField && !tmpLine.isEmpty()){
1011 						if(tmpLine.left(1)!=fieldSeparator)
1012 							tmp+=tmpLine.left(1);
1013 						else
1014 							foundField=true;
1015 						tmpLine.remove(0,1);
1016 					}
1017 				}
1018 				fields << tmp;
1019 				if(foundField && tmpLine.isEmpty())
1020 					fields << "";
1021 			}
1022 /*
1023 			if(separator.size()==1){
1024 				fields = line.split(separator);
1025 			} else
1026 				fields << line;
1027 */
1028 			if(numberOfFields!=fields.size()){
1029 				warnText+=Import::tr("Skipped line %1: FET expected %2 fields but found %3 fields.").arg(lineNumber).arg(numberOfFields).arg(fields.size())+"\n";
1030 				ok=false;
1031 			} else {
1032 				for(int i=0; i<NUMBER_OF_FIELDS; i++){
1033 					if(fieldNumber[i]>=0){
1034 						itemOfField[i].clear();
1035 						itemOfField[i] = fields[fieldNumber[i]];
1036 						if(itemOfField[i].isEmpty()){
1037 							if(i==FIELD_YEAR_NAME || i==FIELD_TEACHER_NAME || i==FIELD_SUBJECT_NAME){
1038 								warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(lineNumber).arg(fieldName[i])+"\n";
1039 								ok=false;
1040 							}
1041 							if(i==FIELD_YEAR_NUMBER_OF_STUDENTS || i==FIELD_GROUP_NUMBER_OF_STUDENTS || i==FIELD_SUBGROUP_NUMBER_OF_STUDENTS){
1042 								itemOfField[i]="0";
1043 							}
1044 							//if(i==FIELD_SUBGROUP_NAME) is OK
1045 							//if(i==FIELD_ACTIVITY_TAG_NAME) is OK
1046 							//if(i==FIELD_ROOM_NAME) is OK
1047 							if(i==FIELD_ROOM_CAPACITY){
1048 								itemOfField[i]=fieldDefaultItem[i];
1049 							}
1050 							if(i==FIELD_MIN_DAYS){
1051 								itemOfField[i]="0";
1052 							}
1053 							if(i==FIELD_MIN_DAYS_WEIGHT){
1054 								if(itemOfField[FIELD_MIN_DAYS].isEmpty()){
1055 									ok=false;
1056 									warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(lineNumber).arg(fieldName[FIELD_MIN_DAYS])+"\n";
1057 								} else
1058 									itemOfField[i]="95";
1059 							}
1060 							if(i==FIELD_MIN_DAYS_CONSECUTIVE){
1061 								if(itemOfField[FIELD_MIN_DAYS].isEmpty()){
1062 									ok=false;
1063 									warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(lineNumber).arg(fieldName[FIELD_MIN_DAYS])+"\n";
1064 								} else
1065 									itemOfField[i]="N";
1066 							}
1067 						}
1068 						if(ok && i==FIELD_SUBGROUP_NAME && !itemOfField[FIELD_SUBGROUP_NAME].isEmpty() && itemOfField[FIELD_GROUP_NAME].isEmpty()){
1069 							warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(lineNumber).arg(fieldName[FIELD_GROUP_NAME])+"\n";
1070 							ok=false;
1071 						}
1072 						if(ok && i==FIELD_SPLIT_DURATION){
1073 							if(itemOfField[FIELD_SPLIT_DURATION].isEmpty()){
1074 								if(!itemOfField[FIELD_TOTAL_DURATION].isEmpty()){
1075 									int totalInt=itemOfField[FIELD_TOTAL_DURATION].toInt(&ok, 10);
1076 									if(ok && totalInt>=1){
1077 										if(totalInt<=MAX_SPLIT_OF_AN_ACTIVITY){
1078 											QString tmpString;
1079 											for(int n=0; n<totalInt; n++){
1080 												if(n!=0)
1081 													tmpString+="+";
1082 												tmpString+="1";
1083 											}
1084 											itemOfField[FIELD_SPLIT_DURATION]=tmpString;
1085 										} else {
1086 											warnText+=Import::tr("Skipped line %1: Field '%2' produces too many subactivities.").arg(lineNumber).arg(fieldName[FIELD_TOTAL_DURATION])+"\n";
1087 											ok=false;
1088 										}
1089 									} else {
1090 										warnText+=Import::tr("Skipped line %1: Field '%2' contain incorrect data.").arg(lineNumber).arg(fieldName[FIELD_TOTAL_DURATION])+"\n";
1091 										ok=false;
1092 									}
1093 								} else {
1094 									warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(lineNumber).arg(fieldName[i])+"\n";
1095 									ok=false;
1096 								}
1097 							} else {
1098 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
1099 								QStringList splitList=itemOfField[FIELD_SPLIT_DURATION].split("+", Qt::SkipEmptyParts);
1100 #else
1101 								QStringList splitList=itemOfField[FIELD_SPLIT_DURATION].split("+", QString::SkipEmptyParts);
1102 #endif
1103 								if(splitList.size()<=MAX_SPLIT_OF_AN_ACTIVITY){
1104 									int tmpInt=0;
1105 									for(const QString& split : qAsConst(splitList)){
1106 										tmpInt+=split.toInt(&ok, 10);
1107 										if(!ok)
1108 											warnText+=Import::tr("Skipped line %1: Field '%2' doesn't contain an integer value.").arg(lineNumber).arg(fieldName[FIELD_SPLIT_DURATION])+"\n";
1109 									}
1110 									if(itemOfField[FIELD_TOTAL_DURATION].isEmpty()){
1111 										itemOfField[FIELD_TOTAL_DURATION]=CustomFETString::number(tmpInt);
1112 									} else {
1113 										int totalInt=itemOfField[FIELD_TOTAL_DURATION].toInt(&ok, 10);
1114 										if(totalInt!=tmpInt){
1115 											warnText+=Import::tr("Skipped line %1: Fields '%2' and '%3' do not have the same value.").arg(lineNumber).arg(fieldName[i]).arg(fieldName[FIELD_TOTAL_DURATION])+"\n";
1116 											ok=false;
1117 										}
1118 									}
1119 								} else {
1120 									warnText+=Import::tr("Skipped line %1: Field '%2' contains too many subactivities.").arg(lineNumber).arg(fieldName[i])+"\n";
1121 									ok=false;
1122 								}
1123 							}
1124 						}
1125 						if(ok && !itemOfField[FIELD_BUILDING_NAME].isEmpty() && itemOfField[FIELD_ROOM_NAME].isEmpty() && i==FIELD_ROOM_NAME){
1126 							warnText+=Import::tr("Warning in line %1: Field with building name doesn't relate to a room").arg(lineNumber)+"\n";
1127 						}
1128 						if(ok && (i==FIELD_YEAR_NUMBER_OF_STUDENTS || i==FIELD_GROUP_NUMBER_OF_STUDENTS || i==FIELD_SUBGROUP_NUMBER_OF_STUDENTS || i==FIELD_ROOM_CAPACITY || i==FIELD_TOTAL_DURATION || i==FIELD_MIN_DAYS)){
1129 							if(!itemOfField[i].isEmpty()){
1130 								int value=itemOfField[i].toInt(&ok, 10);
1131 								if(!ok)
1132 									warnText+=Import::tr("Skipped line %1: Field '%2' doesn't contain an integer value.").arg(lineNumber).arg(fieldName[i])+"\n";
1133 								else {
1134 									if(value<0){
1135 										warnText+=Import::tr("Skipped line %1: Field '%2' contains an invalid integer value.").arg(lineNumber).arg(fieldName[i])+"\n";
1136 										ok=false;
1137 									}
1138 								}
1139 							} else if(i==FIELD_TOTAL_DURATION){
1140 								 assert(true);
1141 							}else{
1142 								ok=false;
1143 								warnText+=Import::tr("Skipped line %1: Field '%2' doesn't contain an integer value.").arg(lineNumber).arg(fieldName[i])+"\n";
1144 								//because of bug reported by murad on 25 May 2010, crash when importing rooms, if capacity is empty
1145 								//assert(false);
1146 							}
1147 						}
1148 						if(ok && i==FIELD_MIN_DAYS_WEIGHT){
1149 //							double weight=itemOfField[i].toDouble(&ok);
1150 							double weight=customFETStrToDouble(itemOfField[i], &ok);
1151 							if(!ok)
1152 								warnText+=Import::tr("Skipped line %1: Field '%2' doesn't contain a number (double) value.").arg(lineNumber).arg(fieldName[i])+"\n";
1153 							else {
1154 								if(weight<0.0 || weight>100.0){
1155 									warnText+=Import::tr("Skipped line %1: Field '%2' contains an invalid number (double) value.").arg(lineNumber).arg(fieldName[i])+"\n";
1156 									ok=false;
1157 								}
1158 							}
1159 						}
1160 						if(ok && i==FIELD_MIN_DAYS_CONSECUTIVE){
1161 							QString tmpString;
1162 							tmpString=itemOfField[i];
1163 							tmpString=tmpString.toUpper();
1164 							if(tmpString=="Y" || tmpString=="YES" ||  tmpString=="T" || tmpString=="TRUE" || tmpString=="1")
1165 								itemOfField[i]="yes";
1166 							else if(tmpString=="N" || tmpString=="NO" || tmpString=="F" || tmpString=="FALSE" || tmpString=="0")
1167 								itemOfField[i]="no";
1168 							else
1169 								ok=false;
1170 							if(!ok)
1171 								warnText+=Import::tr("Skipped line %1: Field '%2' contains an unknown value.").arg(lineNumber).arg(fieldName[i])+"\n";
1172 						}
1173 					} else if(fieldNumber[i]==IMPORT_DEFAULT_ITEM){
1174 						itemOfField[i].clear();
1175 						itemOfField[i] = fieldDefaultItem[i];
1176 						//Removed by Liviu - we may have empty default fields
1177 						//assert(!fieldDefaultItem[i].isEmpty());
1178 					}
1179 				}
1180 			}
1181 			if(ok){
1182 				check.clear();
1183 				for(int i=0; i<NUMBER_OF_FIELDS; i++){
1184 					check+=itemOfField[i]+" ";
1185 				}
1186 				if(checkSet.contains(check)){
1187 					if(fieldNumber[FIELD_SPLIT_DURATION]!=DO_NOT_IMPORT||fieldNumber[FIELD_TOTAL_DURATION]!=DO_NOT_IMPORT){
1188 						warnText+=Import::tr("Note about line %1: Data was already in a previous line. So this data will be imported once again.").arg(lineNumber)+"\n";
1189 					} else {
1190 						warnText+=Import::tr("Skipped line %1: Data was already in a previous line.").arg(lineNumber)+"\n";
1191 						ok=false;
1192 					}
1193 				} else
1194 					checkSet<<check;
1195 			}
1196 			if(ok){
1197 				//QString tmp;
1198 				//tmp=tr("%1").arg(lineNumber);
1199 				//itemOfField[FIELD_LINE_NUMBER]=tmp;
1200 				itemOfField[FIELD_LINE_NUMBER]=CustomFETString::number(lineNumber);
1201 				for(int i=0; i<NUMBER_OF_FIELDS; i++){
1202 					if(fieldNumber[i]!=DO_NOT_IMPORT)
1203 						fieldList[i]<<itemOfField[i];
1204 				}
1205 			} else
1206 				warnText+="   "+Import::tr("Line %1 is: %2").arg(lineNumber).arg(line)+"\n";
1207 		}
1208 	}
1209 	progress.setValue(qMax(size, qint64(1)));
1210 	//cout<<"progress in readFields ends"<<endl;
1211 	int max=0;
1212 	for(int i=0; i<NUMBER_OF_FIELDS; i++){
1213 		if(max==0)
1214 			max=fieldList[i].size();
1215 		if(fieldNumber[i]>DO_NOT_IMPORT){
1216 			assert(fieldList[i].size()==max);
1217 		}
1218 		else
1219 			assert(fieldList[i].isEmpty());
1220 	}
1221 	file.close();
1222 	return true;
1223 }
1224 
showFieldsAndWarnings(QWidget * parent,QDialog * & newParent)1225 int Import::showFieldsAndWarnings(QWidget* parent, QDialog* &newParent){
1226 	newParent=((QDialog*)parent);
1227 
1228 	int ok=true;
1229 
1230 	int max=0;
1231 	for(int i=0; i<NUMBER_OF_FIELDS; i++){
1232 		if(fieldNumber[i]>DO_NOT_IMPORT){
1233 			if(max==0)
1234 				max=fieldList[i].size();
1235 			assert(fieldList[i].size()==max);
1236 		}
1237 		else{
1238 			if(i!=FIELD_TEACHER_NAME){		//needed for activities!
1239 				//assert(fieldList[i].isEmpty());
1240 				//because of bug reported 17.03.2008. Please add again?! compare add activities function
1241 			}
1242 		}
1243 	}
1244 	// Start Dialog
1245 	newParent=new QDialog(parent);
1246 	QDialog& addItemsDialog=(*newParent);
1247 	addItemsDialog.setWindowTitle(Import::tr("FET import %1 question").arg(importThing));
1248 	QVBoxLayout* addItemsMainLayout=new QVBoxLayout(&addItemsDialog);
1249 
1250 	//Start Warnings
1251 	QHBoxLayout* headWarnings=new QHBoxLayout();
1252 	QLabel* headWarningsText=new QLabel();
1253 
1254 	int tmp=fileName.lastIndexOf(FILE_SEP);
1255 	tmp=fileName.size()-tmp-1;
1256 	QString shortFileName=fileName.right(tmp);
1257 	if(!warnText.isEmpty())
1258 		headWarningsText->setText(Import::tr("There are several problems in file\n%1").arg(shortFileName));
1259 	else
1260 		headWarningsText->setText(Import::tr("There are no problems in file\n%1").arg(shortFileName));
1261 
1262 //TODO
1263 /*
1264 tr("There are no problems in file")
1265 +
1266 "\n"
1267 +
1268 FILE_STRIPPED_NAME
1269 */
1270 
1271 	headWarnings->addWidget(headWarningsText);
1272 	headWarnings->addStretch();
1273 
1274 	QPlainTextEdit* textOfWarnings=new QPlainTextEdit();
1275 	textOfWarnings->setMinimumWidth(500);			//width
1276 	textOfWarnings->setReadOnly(true);
1277 	textOfWarnings->setWordWrapMode(QTextOption::NoWrap);
1278 	textOfWarnings->setPlainText(warnText);
1279 
1280 	//Start data table
1281 	QLabel* headTableText=new QLabel();
1282 	if(max!=0)
1283 		headTableText->setText(Import::tr("Following data found in the file:"));
1284 	else
1285 		headTableText->setText(Import::tr("There is no usable data in the file."));
1286 
1287 	QTableWidget* fieldsTable= new QTableWidget;
1288 
1289 	//fieldsTable->setUpdatesEnabled(false);
1290 
1291 	fieldsTable->setRowCount(max);
1292 	QStringList fieldsTableLabel;
1293 
1294 	int columns=0;
1295 	for(int i=0; i<NUMBER_OF_FIELDS; i++){
1296 		if(fieldNumber[i]>DO_NOT_IMPORT){
1297 			fieldsTableLabel<<tr("%1").arg(fieldName[i]);
1298 			columns++;
1299 		}
1300 	}
1301 	fieldsTable->setColumnCount(columns);
1302 	fieldsTable->setHorizontalHeaderLabels(fieldsTableLabel);
1303 	for(int i=0; i<max; i++){
1304 		int column=0;
1305 		for(int f=0; f<NUMBER_OF_FIELDS; f++){
1306 			if(fieldNumber[f]>DO_NOT_IMPORT){
1307 				QTableWidgetItem* newItem=new QTableWidgetItem(fieldList[f][i]);
1308 				newItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
1309 				fieldsTable->setItem(i, column, newItem);
1310 				column++;
1311 			}
1312 		}
1313 	}
1314 	fieldsTable->resizeColumnsToContents();
1315 	//fieldsTable->resizeRowsToContents(); This takes too long for many rows, and it is also useless.
1316 
1317 	//fieldsTable->setUpdatesEnabled(true);
1318 
1319 	//Start current data warning
1320 	QVBoxLayout* dataWarningBox=new QVBoxLayout();
1321 	QLabel* dataWarningText=new QLabel();
1322 	/*if(dataWarning.size()==1)
1323 		dataWarningText->setText(Import::tr("FET noticed 1 warning with the current data."));
1324 	else*/
1325 	dataWarningText->setText(Import::tr("FET noticed %1 warnings with the current data.").arg(dataWarning.size()));
1326 	dataWarningBox->addWidget(dataWarningText);
1327 
1328 	QListWidget* dataWarningItems=new QListWidget();
1329 	dataWarningItems->addItems(dataWarning);
1330 	if(dataWarning.size()>0)
1331 		dataWarningBox->addWidget(dataWarningItems);
1332 	else
1333 		delete dataWarningItems;
1334 
1335 	//Start Buttons
1336 	QPushButton* pb1=new QPushButton(tr("&Import"));
1337 	QPushButton* pb2=new QPushButton(tr("&Cancel"));
1338 
1339 	//TODO: why doesn't work this?
1340 	//if((dataWarning.size()>0&&dataWarning.size()==max)||!warnText.isEmpty())
1341 	//	pb2->setDefault(true);
1342 	//else
1343 	//	 pb1->setDefault(true);
1344 	//	 pb1->setFocus();
1345 		// pb1->setAutoDefault(true);
1346 
1347 	QHBoxLayout* hl=new QHBoxLayout();
1348 	hl->addStretch();
1349 	hl->addWidget(pb1);
1350 	hl->addWidget(pb2);
1351 
1352 	//Start adding all into main layout
1353 	addItemsMainLayout->addLayout(headWarnings);
1354 	if(!warnText.isEmpty())
1355 		addItemsMainLayout->addWidget(textOfWarnings);
1356 	else
1357 		delete textOfWarnings;
1358 	addItemsMainLayout->addWidget(headTableText);
1359 	if(max!=0)
1360 		addItemsMainLayout->addWidget(fieldsTable);
1361 	else
1362 		delete fieldsTable;
1363 	addItemsMainLayout->addLayout(dataWarningBox);
1364 	addItemsMainLayout->addLayout(hl);
1365 
1366 	QObject::connect(pb1, SIGNAL(clicked()), &addItemsDialog, SLOT(accept()));
1367 	QObject::connect(pb2, SIGNAL(clicked()), &addItemsDialog, SLOT(reject()));
1368 
1369 	//pb1->setDefault(true);
1370 
1371 	int w=chooseWidth(addItemsDialog.sizeHint().width());
1372 	int h=chooseHeight(addItemsDialog.sizeHint().height());
1373 	addItemsDialog.resize(w,h);
1374 
1375 	QString settingsName;
1376 	if(importThing==Import::tr("activity tags"))
1377 		settingsName=QString("ImportActivityTagsShowFieldsAndWarningsDialog");
1378 	else if(importThing==Import::tr("buildings and rooms"))
1379 		settingsName=QString("ImportBuildingsRoomsShowFieldsAndWarningsDialog");
1380 	else if(importThing==Import::tr("teachers"))
1381 		settingsName=QString("ImportTeachersShowFieldsAndWarningsDialog");
1382 	else if(importThing==Import::tr("subjects"))
1383 		settingsName=QString("ImportSubjectsShowFieldsAndWarningsDialog");
1384 	else if(importThing==Import::tr("years, groups and subgroups"))
1385 		settingsName=QString("ImportYearsGroupsSubgroupsShowFieldsAndWarningsDialog");
1386 	else if(importThing==Import::tr("activities"))
1387 		settingsName=QString("ImportActivitiesShowFieldsAndWarningsDialog");
1388 
1389 	pb1->setDefault(true);
1390 	pb1->setFocus();
1391 
1392 	centerWidgetOnScreen(&addItemsDialog);
1393 	restoreFETDialogGeometry(&addItemsDialog, settingsName);
1394 
1395 	ok=addItemsDialog.exec();
1396 	saveFETDialogGeometry(&addItemsDialog, settingsName);
1397 
1398 	return ok;
1399 }
1400 
importCSVActivityTags(QWidget * parent)1401 void Import::importCSVActivityTags(QWidget* parent){
1402 	prearrangement();
1403 	fieldNumber[FIELD_ACTIVITY_TAG_NAME]=IMPORT_DEFAULT_ITEM;
1404 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
1405 	int ok;
1406 
1407 	QDialog* newParent;
1408 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
1409 	//DON'T ADD THIS! newParent->deleteLater();
1410 	if(!ok)	return;
1411 
1412 	if(fieldNumber[FIELD_ACTIVITY_TAG_NAME]==IMPORT_DEFAULT_ITEM){
1413 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
1414 		const QString settingsName=QString("ImportActivityTagsChooseFieldsDialog");
1415 		//DON'T ADD THIS! newParent2->deleteLater();
1416 		newParent=newParent2;
1417 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
1418 		int w= chooseWidth(cfd.sizeHint().width());
1419 		int h= chooseHeight(cfd.sizeHint().height());
1420 		cfd.resize(w,h);
1421 		centerWidgetOnScreen(&cfd);
1422 		restoreFETDialogGeometry(&cfd, settingsName);
1423 
1424 		ok=cfd.exec();
1425 		saveFETDialogGeometry(&cfd, settingsName);
1426 		if(!ok)	return;
1427 	}
1428 
1429 	ok = readFields(newParent);
1430 	if(!ok) return;
1431 
1432 	//check empty fields (start)
1433 	for(int i=0; i<fieldList[FIELD_ACTIVITY_TAG_NAME].size(); i++){
1434 		if(fieldList[FIELD_ACTIVITY_TAG_NAME][i].isEmpty())
1435 			warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_ACTIVITY_TAG_NAME])+"\n";
1436 	}
1437 	//check empty fields (end)
1438 
1439 	//check if already in memory (start)
1440 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1441 	QSet<QString> tmpSet=QSet<QString>(fieldList[FIELD_ACTIVITY_TAG_NAME].begin(), fieldList[FIELD_ACTIVITY_TAG_NAME].end());
1442 #else
1443 	QSet<QString> tmpSet=fieldList[FIELD_ACTIVITY_TAG_NAME].toSet();
1444 #endif
1445 	for(int i=0; i<gt.rules.activityTagsList.size(); i++){
1446 		ActivityTag* a=gt.rules.activityTagsList[i];
1447 		if(tmpSet.contains(a->name))
1448 			dataWarning<<Import::tr("%1 is already in FET data.").arg(a->name);
1449 	}
1450 	//check if already in memory (end)
1451 	QDialog* newParent2;
1452 	ok = showFieldsAndWarnings(newParent, newParent2);
1453 	//DON'T ADD THIS! newParent2->deleteLater();
1454 	newParent=newParent2;
1455 	if(!ok) return;
1456 
1457 	//add activity tags (start) - similar to teachersform.cpp by Liviu modified by Volker
1458 	tmpSet.clear();
1459 	for(ActivityTag* at : qAsConst(gt.rules.activityTagsList))
1460 		tmpSet.insert(at->name);
1461 	int count=0;
1462 	for(int i=0; i<fieldList[FIELD_ACTIVITY_TAG_NAME].size(); i++){
1463 		if(!fieldList[FIELD_ACTIVITY_TAG_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_ACTIVITY_TAG_NAME][i])){
1464 			tmpSet.insert(fieldList[FIELD_ACTIVITY_TAG_NAME][i]);
1465 			ActivityTag* a=new ActivityTag();
1466 			a->name=fieldList[FIELD_ACTIVITY_TAG_NAME][i];
1467 			if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
1468 				a->comments=fieldList[FIELD_COMMENTS][i];
1469 			if(!gt.rules.addActivityTagFast(a)){
1470 				delete a;
1471 				assert(0);
1472 			} else count++;
1473 		}
1474 	}
1475 	QMessageBox::information(newParent, tr("FET information"), Import::tr("%1 activity tags added. Please check activity tags form.").arg(count));
1476 	//add activity tags (end) - similar to teachersform.cpp by Liviu modified by Volker
1477 	int tmp=fileName.lastIndexOf(FILE_SEP);
1478 	IMPORT_DIRECTORY=fileName.left(tmp);
1479 	//gt.rules.internalStructureComputed=false;
1480 }
1481 
importCSVRoomsAndBuildings(QWidget * parent)1482 void Import::importCSVRoomsAndBuildings(QWidget* parent){
1483 	prearrangement();
1484 	fieldNumber[FIELD_ROOM_NAME]=IMPORT_DEFAULT_ITEM;
1485 	fieldNumber[FIELD_ROOM_CAPACITY]=IMPORT_DEFAULT_ITEM;
1486 	fieldNumber[FIELD_BUILDING_NAME]=IMPORT_DEFAULT_ITEM;
1487 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
1488 	int ok;
1489 
1490 	QDialog* newParent;
1491 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
1492 	//DON'T ADD THIS! newParent->deleteLater();
1493 	if(!ok)	return;
1494 
1495 	if(fieldNumber[FIELD_ROOM_NAME]==IMPORT_DEFAULT_ITEM){
1496 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
1497 		const QString settingsName=QString("ImportRoomsBuildingsChooseFieldsDialog");
1498 		//DON'T ADD THIS! newParent2->deleteLater();
1499 		newParent=newParent2;
1500 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
1501 		int w= chooseWidth(cfd.sizeHint().width());
1502 		int h= chooseHeight(cfd.sizeHint().height());
1503 		cfd.resize(w,h);
1504 		centerWidgetOnScreen(&cfd);
1505 		restoreFETDialogGeometry(&cfd, settingsName);
1506 
1507 		ok=cfd.exec();
1508 		saveFETDialogGeometry(&cfd, settingsName);
1509 	}
1510 
1511 	if(!ok)	return;
1512 
1513 	ok = readFields(newParent);
1514 	if(!ok) return;
1515 
1516 	QSet<QString> duplicatesCheck;
1517 	//check duplicates of rooms in csv
1518 	if(fieldNumber[FIELD_ROOM_NAME]!=DO_NOT_IMPORT)
1519 		for(int i=0; i<fieldList[FIELD_ROOM_NAME].size(); i++){
1520 			if(duplicatesCheck.contains(fieldList[FIELD_ROOM_NAME][i]))
1521 				warnText+=Import::tr("Skipped line %1: Field '%2' is already in a previous line.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_ROOM_NAME])+"\n";
1522 			else
1523 				duplicatesCheck<<fieldList[FIELD_ROOM_NAME][i];
1524 		}
1525 	duplicatesCheck.clear();
1526 	//check duplicates of buildings in csv. only if no room is imported.
1527 	if(fieldNumber[FIELD_ROOM_NAME]==DO_NOT_IMPORT&&fieldNumber[FIELD_BUILDING_NAME]!=DO_NOT_IMPORT)
1528 		for(int i=0; i<fieldList[FIELD_BUILDING_NAME].size(); i++){
1529 			if(duplicatesCheck.contains(fieldList[FIELD_BUILDING_NAME][i]))
1530 				warnText+=Import::tr("Skipped line %1: Field '%2' is already in a previous line.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_BUILDING_NAME])+"\n";
1531 			else
1532 				duplicatesCheck<<fieldList[FIELD_BUILDING_NAME][i];
1533 		}
1534 	duplicatesCheck.clear();
1535 	//check empty rooms (start)
1536 	if(fieldNumber[FIELD_ROOM_NAME]!=DO_NOT_IMPORT)
1537 		for(int i=0; i<fieldList[FIELD_ROOM_NAME].size(); i++)
1538 			if(fieldList[FIELD_ROOM_NAME][i].isEmpty())
1539 				warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_ROOM_NAME])+"\n";
1540 	//check empty rooms (end)
1541 	//check empty buildings (start)
1542 	if((fieldNumber[FIELD_ROOM_NAME]==DO_NOT_IMPORT||fieldNumber[FIELD_ROOM_NAME]==IMPORT_DEFAULT_ITEM)&&fieldNumber[FIELD_BUILDING_NAME]!=DO_NOT_IMPORT)
1543 		for(int i=0; i<fieldList[FIELD_BUILDING_NAME].size(); i++)
1544 			if(fieldList[FIELD_BUILDING_NAME][i].isEmpty())
1545 				warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_BUILDING_NAME])+"\n";
1546 	//check empty buildings (end)
1547 
1548 	//check if rooms are already in memory (start)
1549 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1550 	QSet<QString> tmpSet=QSet<QString>(fieldList[FIELD_ROOM_NAME].begin(), fieldList[FIELD_ROOM_NAME].end());
1551 #else
1552 	QSet<QString> tmpSet=fieldList[FIELD_ROOM_NAME].toSet();
1553 #endif
1554 	for(int i=0; i<gt.rules.roomsList.size(); i++){
1555 		Room* r=gt.rules.roomsList[i];
1556 		if(tmpSet.contains(r->name))
1557 			dataWarning<<Import::tr("%1 is already in FET data.").arg(r->name);
1558 	}
1559 	//check if rooms are already in memory (end)
1560 
1561 	//check if buildings are already in memory (start)
1562 	if(fieldNumber[FIELD_ROOM_NAME]<0){
1563 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1564 		tmpSet=QSet<QString>(fieldList[FIELD_BUILDING_NAME].begin(), fieldList[FIELD_BUILDING_NAME].end());
1565 #else
1566 		tmpSet=fieldList[FIELD_BUILDING_NAME].toSet();
1567 #endif
1568 		for(int i=0; i<gt.rules.buildingsList.size(); i++){
1569 			Building* b=gt.rules.buildingsList[i];
1570 			if(tmpSet.contains(b->name))
1571 				dataWarning<<Import::tr("%1 is already in FET data.").arg(b->name);
1572 		}
1573 	}
1574 	//check if buildings are already in memory (end)
1575 
1576 	QDialog* newParent2;
1577 	ok = showFieldsAndWarnings(newParent, newParent2);
1578 	//DON'T ADD THIS! newParent2->deleteLater();
1579 	newParent=newParent2;
1580 	if(!ok) return;
1581 
1582 	//add buildings (start) - similar to teachersform.cpp by Liviu modified by Volker
1583 	tmpSet.clear();
1584 	for(Building* bu : qAsConst(gt.rules.buildingsList))
1585 		tmpSet.insert(bu->name);
1586 	int count=0;
1587 	for(int i=0; i<fieldList[FIELD_BUILDING_NAME].size(); i++){
1588 		if(!fieldList[FIELD_BUILDING_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_BUILDING_NAME][i])){
1589 			tmpSet.insert(fieldList[FIELD_BUILDING_NAME][i]);
1590 			Building* b=new Building();
1591 			b->name=fieldList[FIELD_BUILDING_NAME][i];
1592 			if(!gt.rules.addBuildingFast(b)){
1593 				delete b;
1594 				assert(0);
1595 			} else count++;
1596 		}
1597 	}
1598 	//add buildings (end) - similar to teachersform.cpp by Liviu modified by Volker
1599 
1600 	//add rooms (start) - similar to teachersform.cpp by Liviu modified by Volker
1601 	tmpSet.clear();
1602 	for(Room* rm : qAsConst(gt.rules.roomsList))
1603 		tmpSet.insert(rm->name);
1604 	int countroom=0;
1605 	for(int i=0; i<fieldList[FIELD_ROOM_NAME].size(); i++){
1606 		if(!fieldList[FIELD_ROOM_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_ROOM_NAME][i])){
1607 			tmpSet.insert(fieldList[FIELD_ROOM_NAME][i]);
1608 			Room* r=new Room();
1609 			r->name=fieldList[FIELD_ROOM_NAME][i];
1610 			if(fieldNumber[FIELD_BUILDING_NAME]!=DO_NOT_IMPORT)
1611 				r->building=fieldList[FIELD_BUILDING_NAME][i];
1612 			else
1613 				r->building="";
1614 			if(fieldNumber[FIELD_ROOM_CAPACITY]!=DO_NOT_IMPORT){
1615 				QString tmpInt=fieldList[FIELD_ROOM_CAPACITY][i];
1616 				r->capacity=tmpInt.toInt();
1617 			}
1618 			else
1619 				assert(0==1);
1620 			if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
1621 				r->comments=fieldList[FIELD_COMMENTS][i];
1622 			if(!gt.rules.addRoomFast(r)){
1623 				delete r;
1624 				assert(0);
1625 			} else countroom++;
1626 		}
1627 	}
1628 	//add rooms (end) - similar to teachersform.cpp by Liviu modified by Volker
1629 	QMessageBox::information(newParent, tr("FET information"),
1630 	 Import::tr("%1 buildings added. Please check buildings form.").arg(count)+"\n"+tr("%1 rooms added. Please check rooms form.").arg(countroom));
1631 
1632 	int tmp=fileName.lastIndexOf(FILE_SEP);
1633 	IMPORT_DIRECTORY=fileName.left(tmp);
1634 	//gt.rules.internalStructureComputed=false;
1635 }
1636 
importCSVSubjects(QWidget * parent)1637 void Import::importCSVSubjects(QWidget* parent){
1638 	prearrangement();
1639 	fieldNumber[FIELD_SUBJECT_NAME]=IMPORT_DEFAULT_ITEM;
1640 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
1641 	int ok;
1642 
1643 	QDialog* newParent;
1644 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
1645 	//DON'T ADD THIS! newParent->deleteLater();
1646 	if(!ok)	return;
1647 
1648 	if(fieldNumber[FIELD_SUBJECT_NAME]==IMPORT_DEFAULT_ITEM){
1649 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
1650 		const QString settingsName=QString("ImportSubjectsChooseFieldsDialog");
1651 		//DON'T ADD THIS! newParent2->deleteLater();
1652 		newParent=newParent2;
1653 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
1654 		int w= chooseWidth(cfd.sizeHint().width());
1655 		int h= chooseHeight(cfd.sizeHint().height());
1656 		cfd.resize(w,h);
1657 		centerWidgetOnScreen(&cfd);
1658 		restoreFETDialogGeometry(&cfd, settingsName);
1659 
1660 		ok=cfd.exec();
1661 		saveFETDialogGeometry(&cfd, settingsName);
1662 	}
1663 
1664 	if(!ok)	return;
1665 
1666 	ok = readFields(newParent);
1667 	if(!ok) return;
1668 
1669 	//check empty fields (start)
1670 	for(int i=0; i<fieldList[FIELD_SUBJECT_NAME].size(); i++){
1671 		if(fieldList[FIELD_SUBJECT_NAME][i].isEmpty())
1672 			warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_SUBJECT_NAME])+"\n";
1673 	}
1674 	//check empty fields (end)
1675 
1676 	//check if already in memory (start)
1677 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1678 	QSet<QString> tmpSet(fieldList[FIELD_SUBJECT_NAME].begin(), fieldList[FIELD_SUBJECT_NAME].end());
1679 #else
1680 	QSet<QString> tmpSet=fieldList[FIELD_SUBJECT_NAME].toSet();
1681 #endif
1682 	for(int i=0; i<gt.rules.subjectsList.size(); i++){
1683 		Subject* s=gt.rules.subjectsList[i];
1684 		if(tmpSet.contains(s->name))
1685 			dataWarning<<Import::tr("%1 is already in FET data.").arg(s->name);
1686 	}
1687 	//check if already in memory (end)
1688 
1689 	QDialog* newParent2;
1690 	ok = showFieldsAndWarnings(newParent, newParent2);
1691 	//DON'T ADD THIS! newParent2->deleteLater();
1692 	newParent=newParent2;
1693 	if(!ok) return;
1694 
1695 	//add subjects (start) - similar to teachersform.cpp by Liviu modified by Volker
1696 	tmpSet.clear();
1697 	for(Subject* sbj : qAsConst(gt.rules.subjectsList))
1698 		tmpSet.insert(sbj->name);
1699 	int count=0;
1700 	for(int i=0; i<fieldList[FIELD_SUBJECT_NAME].size(); i++){
1701 		if(!fieldList[FIELD_SUBJECT_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_SUBJECT_NAME][i])){
1702 			tmpSet.insert(fieldList[FIELD_SUBJECT_NAME][i]);
1703 			Subject* s=new Subject();
1704 			s->name=fieldList[FIELD_SUBJECT_NAME][i];
1705 			if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
1706 				s->comments=fieldList[FIELD_COMMENTS][i];
1707 			if(!gt.rules.addSubjectFast(s)){
1708 				delete s;
1709 				assert(0);
1710 			} else count++;
1711 		}
1712 	}
1713 	//add subjects (end) - similar to teachersform.cpp by Liviu modified by Volker
1714 	QMessageBox::information(newParent, tr("FET information"), Import::tr("%1 subjects added. Please check subjects form.").arg(count));
1715 	int tmp=fileName.lastIndexOf(FILE_SEP);
1716 	IMPORT_DIRECTORY=fileName.left(tmp);
1717 	//gt.rules.internalStructureComputed=false;
1718 }
1719 
importCSVTeachers(QWidget * parent)1720 void Import::importCSVTeachers(QWidget* parent){
1721 	prearrangement();
1722 	fieldNumber[FIELD_TEACHER_NAME]=IMPORT_DEFAULT_ITEM;
1723 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
1724 	int ok;
1725 
1726 	QDialog* newParent;
1727 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
1728 	//DON'T ADD THIS! newParent->deleteLater();
1729 	if(!ok)	return;
1730 
1731 	if(fieldNumber[FIELD_TEACHER_NAME]==IMPORT_DEFAULT_ITEM){
1732 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
1733 		const QString settingsName=QString("ImportTeachersChooseFieldsDialog");
1734 		//DON'T ADD THIS! newParent2->deleteLater();
1735 		newParent=newParent2;
1736 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
1737 		int w= chooseWidth(cfd.sizeHint().width());
1738 		int h= chooseHeight(cfd.sizeHint().height());
1739 		cfd.resize(w,h);
1740 		centerWidgetOnScreen(&cfd);
1741 		restoreFETDialogGeometry(&cfd, settingsName);
1742 
1743 		ok=cfd.exec();
1744 		saveFETDialogGeometry(&cfd, settingsName);
1745 	}
1746 
1747 	if(!ok)	return;
1748 
1749 	ok = readFields(newParent);
1750 	if(!ok) return;
1751 
1752 	//check empty fields (start)
1753 	for(int i=0; i<fieldList[FIELD_TEACHER_NAME].size(); i++){
1754 		if(fieldList[FIELD_TEACHER_NAME][i].isEmpty())
1755 			warnText+=Import::tr("Skipped line %1: Field '%2' is empty.").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(fieldName[FIELD_TEACHER_NAME])+"\n";
1756 	}
1757 	//check empty fields (end)
1758 
1759 	//check if already in memory (start)
1760 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1761 	QSet<QString> tmpSet(fieldList[FIELD_TEACHER_NAME].begin(), fieldList[FIELD_TEACHER_NAME].end());
1762 #else
1763 	QSet<QString> tmpSet=fieldList[FIELD_TEACHER_NAME].toSet();
1764 #endif
1765 	for(int i=0; i<gt.rules.teachersList.size(); i++){
1766 		Teacher* t=gt.rules.teachersList[i];
1767 		if(tmpSet.contains(t->name))
1768 			dataWarning<<Import::tr("%1 is already in FET data.").arg(t->name);
1769 	}
1770 	//check if already in memory (end)
1771 
1772 	QDialog* newParent2;
1773 	ok = showFieldsAndWarnings(newParent, newParent2);
1774 	//DON'T ADD THIS! newParent2->deleteLater();
1775 	newParent=newParent2;
1776 	if(!ok) return;
1777 
1778 	//add teachers (start) - similar to teachersform.cpp by Liviu modified by Volker
1779 	tmpSet.clear();
1780 	for(Teacher* tch : qAsConst(gt.rules.teachersList))
1781 		tmpSet.insert(tch->name);
1782 	int count=0;
1783 	for(int i=0; i<fieldList[FIELD_TEACHER_NAME].size(); i++){
1784 		if(!fieldList[FIELD_TEACHER_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_TEACHER_NAME][i])){
1785 			tmpSet.insert(fieldList[FIELD_TEACHER_NAME][i]);
1786 			Teacher* tch=new Teacher();
1787 			if(gt.rules.mode==MORNINGS_AFTERNOONS)
1788 				tch->morningsAfternoonsBehavior=TEACHER_UNRESTRICTED_MORNINGS_AFTERNOONS;
1789 			tch->name=fieldList[FIELD_TEACHER_NAME][i];
1790 			if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
1791 				tch->comments=fieldList[FIELD_COMMENTS][i];
1792 			if(!gt.rules.addTeacherFast(tch)){
1793 				delete tch;
1794 				assert(0);
1795 			} else count++;
1796 		}
1797 	}
1798 	QMessageBox::information(newParent, tr("FET information"), Import::tr("%1 teachers added. Please check teachers form.").arg(count));
1799 	//add teachers (end) - similar to teachersform.cpp by Liviu modified by Volker
1800 	int tmp=fileName.lastIndexOf(FILE_SEP);
1801 	IMPORT_DIRECTORY=fileName.left(tmp);
1802 	//gt.rules.internalStructureComputed=false;
1803 }
1804 
importCSVStudents(QWidget * parent)1805 void Import::importCSVStudents(QWidget* parent){
1806 	prearrangement();
1807 	fieldNumber[FIELD_YEAR_NAME]=IMPORT_DEFAULT_ITEM;
1808 	fieldNumber[FIELD_YEAR_NUMBER_OF_STUDENTS]=IMPORT_DEFAULT_ITEM;
1809 	fieldNumber[FIELD_GROUP_NAME]=IMPORT_DEFAULT_ITEM;
1810 	fieldNumber[FIELD_GROUP_NUMBER_OF_STUDENTS]=IMPORT_DEFAULT_ITEM;
1811 	fieldNumber[FIELD_SUBGROUP_NAME]=IMPORT_DEFAULT_ITEM;
1812 	fieldNumber[FIELD_SUBGROUP_NUMBER_OF_STUDENTS]=IMPORT_DEFAULT_ITEM;
1813 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
1814 	int ok;
1815 
1816 	QDialog* newParent;
1817 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
1818 	//DON'T ADD THIS! newParent->deleteLater();
1819 	if(!ok)	return;
1820 
1821 	if(fieldNumber[FIELD_YEAR_NAME]==IMPORT_DEFAULT_ITEM){
1822 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
1823 		const QString settingsName=QString("ImportYearsGroupsSubgroupsChooseFieldsDialog");
1824 		//DON'T ADD THIS! newParent2->deleteLater();
1825 		newParent=newParent2;
1826 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
1827 		int w=chooseWidth(cfd.sizeHint().width());
1828 		int h=chooseHeight(cfd.sizeHint().height());
1829 		cfd.resize(w,h);
1830 
1831 		centerWidgetOnScreen(&cfd);
1832 		restoreFETDialogGeometry(&cfd, settingsName);
1833 
1834 		ok=cfd.exec();
1835 		saveFETDialogGeometry(&cfd, settingsName);
1836 		if(!ok)	return;
1837 	}
1838 
1839 	ok = readFields(newParent);
1840 	if(!ok) return;
1841 
1842 	//check if already in memory (start) - similar to adding items by Liviu modified by Volker
1843 	QString yearName;
1844 	QString groupName;
1845 	QString subgroupName;
1846 	QSet<QString> usedCSVYearNames;			// this is much faster than QStringList
1847 	QSet<QString> usedCSVGroupNames;
1848 	QSet<QString> usedCSVSubgroupNames;
1849 
1850 	//check csv
1851 	QProgressDialog* _progress=new QProgressDialog(newParent);
1852 	QProgressDialog& progress=(*_progress);
1853 	progress.setWindowTitle(tr("Importing", "Title of a progress dialog"));
1854 	//cout<<"progress in importCSVStudents starts, range="<<fieldList[FIELD_YEAR_NAME].size()<<endl;
1855 	progress.setLabelText(tr("Checking CSV"));
1856 	progress.setModal(true);
1857 	progress.setRange(0, qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
1858 	for(int i=0; i<fieldList[FIELD_YEAR_NAME].size(); i++){
1859 		progress.setValue(i);
1860 		if(progress.wasCanceled()){
1861 			progress.setValue(fieldList[FIELD_YEAR_NAME].size());
1862 			QMessageBox::warning(newParent, "FET", Import::tr("Checking CSV canceled by user."));
1863 			return;
1864 		}
1865 		if(fieldNumber[FIELD_YEAR_NAME]>=0)
1866 			yearName=fieldList[FIELD_YEAR_NAME][i];
1867 		else
1868 			yearName=fieldDefaultItem[FIELD_YEAR_NAME];
1869 		if((fieldNumber[FIELD_GROUP_NAME])>=0)
1870 			groupName=fieldList[FIELD_GROUP_NAME][i];
1871 		else
1872 			groupName=fieldDefaultItem[FIELD_GROUP_NAME];
1873 		if((fieldNumber[FIELD_SUBGROUP_NAME])>=0)
1874 			subgroupName=fieldList[FIELD_SUBGROUP_NAME][i];
1875 		else
1876 			subgroupName=fieldDefaultItem[FIELD_SUBGROUP_NAME];
1877 		if((fieldNumber[FIELD_YEAR_NAME])>=IMPORT_DEFAULT_ITEM){
1878 			if(!yearName.isEmpty())
1879 				if(!usedCSVYearNames.contains(yearName))
1880 					usedCSVYearNames<<yearName;
1881 		}
1882 		if((fieldNumber[FIELD_GROUP_NAME])>=IMPORT_DEFAULT_ITEM){
1883 			if(!groupName.isEmpty())
1884 				if(!usedCSVGroupNames.contains(groupName))
1885 					usedCSVGroupNames<<groupName;
1886 			if(usedCSVYearNames.contains(groupName))
1887 				warnText+=Import::tr("Problem in line %1: Group name %2 is taken for a year - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(groupName)+"\n";
1888 			if(usedCSVGroupNames.contains(yearName))
1889 				warnText+=Import::tr("Problem in line %1: Year name %2 is taken for a group - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(yearName)+"\n";
1890 
1891 		}
1892 		if((fieldNumber[FIELD_SUBGROUP_NAME])>=IMPORT_DEFAULT_ITEM){
1893 			if(!subgroupName.isEmpty())
1894 				if(!usedCSVSubgroupNames.contains(subgroupName))
1895 					usedCSVSubgroupNames<<subgroupName;
1896 			if(usedCSVYearNames.contains(subgroupName))
1897 				warnText+=Import::tr("Problem in line %1: Subgroup name %2 is taken for a year - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(subgroupName)+"\n";
1898 			if(usedCSVGroupNames.contains(subgroupName))
1899 				warnText+=Import::tr("Problem in line %1: Subgroup name %2 is taken for a group - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(subgroupName)+"\n";
1900 			if(usedCSVSubgroupNames.contains(groupName))
1901 				warnText+=Import::tr("Problem in line %1: Group name %2 is taken for a subgroup - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(groupName)+"\n";
1902 			if(usedCSVSubgroupNames.contains(yearName))
1903 				warnText+=Import::tr("Problem in line %1: Year name %2 is taken for a subgroup - please consider another name").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(yearName)+"\n";
1904 		}
1905 	}
1906 	progress.setValue(qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
1907 	//cout<<"progress in importCSVStudents ends"<<endl;
1908 
1909 	//check current data
1910 	QProgressDialog* _progress2=new QProgressDialog(newParent);
1911 	QProgressDialog& progress2=(*_progress2);
1912 	progress2.setWindowTitle(tr("Importing", "Title of a progress dialog"));
1913 	progress2.setLabelText(tr("Checking data"));
1914 	progress2.setModal(true);
1915 	progress2.setRange(0, qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
1916 	//cout<<"progress2 in importCSVStudents starts, range="<<fieldList[FIELD_YEAR_NAME].size()<<endl;
1917 	int kk=0;
1918 	for(int i=0; i<gt.rules.yearsList.size(); i++){
1919 		progress2.setValue(kk);
1920 		kk++;
1921 		if(progress2.wasCanceled()){
1922 			progress2.setValue(fieldList[FIELD_YEAR_NAME].size());
1923 			QMessageBox::warning(newParent, "FET", Import::tr("Checking data canceled by user."));
1924 			return;
1925 		}
1926 		StudentsYear* sty=gt.rules.yearsList[i];
1927 		if(usedCSVYearNames.contains(sty->name))
1928 			dataWarning<<Import::tr("Year %1 is already in FET data.").arg(sty->name);
1929 		if(usedCSVGroupNames.contains(sty->name))
1930 			dataWarning<<Import::tr("Can't import group %1. Name is already taken for a year.").arg(sty->name);
1931 		if(usedCSVSubgroupNames.contains(sty->name))
1932 			dataWarning<<Import::tr("Can't import subgroup %1. Name is already taken for a year.").arg(sty->name);
1933 		for(int j=0; j<sty->groupsList.size(); j++){
1934 			progress2.setValue(kk);
1935 			kk++;
1936 			if(progress2.wasCanceled()){
1937 				progress2.setValue(fieldList[FIELD_YEAR_NAME].size());
1938 				QMessageBox::warning(newParent, "FET", Import::tr("Checking data canceled by user."));
1939 				return;
1940 			}
1941 
1942 			StudentsGroup* stg=sty->groupsList[j];
1943 			if(usedCSVYearNames.contains(stg->name))
1944 				dataWarning<<Import::tr("Can't import year %1. Name is already taken for a group.").arg(stg->name);
1945 			if(usedCSVGroupNames.contains(stg->name))
1946 				dataWarning<<Import::tr("Group name %1 is already in FET data (in the same or in another year).").arg(stg->name);
1947 			if(usedCSVSubgroupNames.contains(stg->name))
1948 				dataWarning<<Import::tr("Can't import subgroup %1. Name is already taken for a group.").arg(stg->name);
1949 			for(int k=0; k<stg->subgroupsList.size(); k++){
1950 				progress2.setValue(kk);
1951 				kk++;
1952 
1953 				if(progress2.wasCanceled()){
1954 					progress2.setValue(fieldList[FIELD_YEAR_NAME].size());
1955 					QMessageBox::warning(newParent, "FET", Import::tr("Checking data canceled by user."));
1956 					return;
1957 				}
1958 
1959 				StudentsSubgroup* sts=stg->subgroupsList[k];
1960 				if(usedCSVYearNames.contains(sts->name))
1961 					dataWarning<<Import::tr("Can't import year %1. Name is already taken for a subgroup.").arg(sts->name);
1962 				if(usedCSVGroupNames.contains(sts->name))
1963 					dataWarning<<Import::tr("Can't import group %1. Name is taken for a subgroup.").arg(sts->name);
1964 				if(usedCSVSubgroupNames.contains(sts->name))
1965 					dataWarning<<Import::tr("Subgroup name %1 is already in FET data (in the same or in another group).").arg(sts->name);
1966 			}
1967 		}
1968 	}
1969 	progress2.setValue(qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
1970 	//cout<<"progress2 in importCSVStudents ends"<<endl;
1971 
1972 	QDialog* newParent2;
1973 	ok = showFieldsAndWarnings(newParent, newParent2);
1974 	//DON'T ADD THIS! newParent2->deleteLater();
1975 	newParent=newParent2;
1976 	if(!ok) return;
1977 
1978 	//add students (start) - similar to adding items by Liviu modified by Volker
1979 	lastWarning.clear();
1980 	int addedYears=0;
1981 	int addedGroups=0;
1982 	int addedSubgroups=0;
1983 	QProgressDialog* _progress3=new QProgressDialog(newParent);
1984 	QProgressDialog& progress3=(*_progress3);
1985 	progress3.setWindowTitle(tr("Importing", "Title of a progress dialog"));
1986 	progress3.setLabelText(tr("Importing data"));
1987 	progress3.setModal(true);
1988 	progress3.setRange(0, qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
1989 	//cout<<"progress3 in importCSVStudents starts, range="<<fieldList[FIELD_YEAR_NAME].size()<<endl;
1990 
1991 	QHash<QString, StudentsSet*> studentsHash;
1992 	QSet<QPair<QString, QString>> groupsInYearSet; //first year, then group
1993 	QSet<QPair<QString, QString>> subgroupsInGroupSet; //first group, then subgroup
1994 	for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
1995 		studentsHash.insert(year->name, year);
1996 		for(StudentsGroup* group : qAsConst(year->groupsList)){
1997 			studentsHash.insert(group->name, group);
1998 			groupsInYearSet.insert(QPair<QString, QString> (year->name, group->name));
1999 			for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
2000 				studentsHash.insert(subgroup->name, subgroup);
2001 				subgroupsInGroupSet.insert(QPair<QString, QString> (group->name, subgroup->name));
2002 			}
2003 		}
2004 	}
2005 
2006 	for(int i=0; i<fieldList[FIELD_YEAR_NAME].size(); i++){
2007 		progress3.setValue(i);
2008 		if(progress3.wasCanceled()){
2009 			progress3.setValue(fieldList[FIELD_YEAR_NAME].size());
2010 			QMessageBox::warning(newParent, "FET", Import::tr("Importing data canceled by user."));
2011 			//return false;
2012 			ok=false;
2013 			goto ifUserCanceledProgress3;
2014 		}
2015 		ok=true;
2016 		bool tryNext=false;
2017 		if(fieldNumber[FIELD_YEAR_NAME]!=IMPORT_DEFAULT_ITEM)
2018 			yearName=fieldList[FIELD_YEAR_NAME][i];
2019 		else
2020 			yearName=fieldDefaultItem[FIELD_YEAR_NAME];
2021 		assert(!yearName.isEmpty());
2022 		//StudentsSet* ss=gt.rules.searchStudentsSet(yearName);
2023 		StudentsSet* ss=studentsHash.value(yearName, nullptr);
2024 		if(ss!=nullptr){
2025 			if(ss->type==STUDENTS_SUBGROUP)
2026 				ok=false;
2027 			else if(ss->type==STUDENTS_GROUP)
2028 				ok=false;
2029 			else if(ss->type==STUDENTS_YEAR){
2030 				ok=false;
2031 				tryNext=true;
2032 			}
2033 			else
2034 				assert(0);
2035 		}
2036 		if(ok){
2037 			StudentsYear* sy=new StudentsYear();
2038 			sy->name=yearName;
2039 			QString tmpString=fieldList[FIELD_YEAR_NUMBER_OF_STUDENTS][i];
2040 			sy->numberOfStudents=tmpString.toInt();
2041 			assert(!fieldList[FIELD_YEAR_NUMBER_OF_STUDENTS].isEmpty());
2042 			if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
2043 				sy->comments=fieldList[FIELD_COMMENTS][i];
2044 			/*if(gt.rules.searchYear(yearName) >=0 )
2045 				delete sy;
2046 			else {
2047 				bool tmp=gt.rules.addYear(sy);
2048 				assert(tmp);
2049 				addedYears++;
2050 			}*/
2051 			StudentsSet* studentsSet=ss; //studentsHash.value(yearName, nullptr);
2052 			bool yearExists=false;
2053 			if(studentsSet!=nullptr){
2054 				assert(0);
2055 				if(studentsSet->type==STUDENTS_YEAR)
2056 					yearExists=true;
2057 			}
2058 			if(yearExists){
2059 				delete sy;
2060 				assert(0);
2061 			}
2062 			else{
2063 				bool tmp=gt.rules.addYearFast(sy);
2064 				assert(tmp);
2065 				addedYears++;
2066 				studentsHash.insert(sy->name, sy);
2067 			}
2068 		}
2069 		if((tryNext || ok) && fieldNumber[FIELD_GROUP_NAME]!=DO_NOT_IMPORT){
2070 			ok=true;
2071 			tryNext=false;
2072 			StudentsGroup* sg;
2073 			sg=nullptr;
2074 			if(fieldNumber[FIELD_GROUP_NAME]!=IMPORT_DEFAULT_ITEM)
2075 				groupName=fieldList[FIELD_GROUP_NAME][i];
2076 			else
2077 				groupName=fieldDefaultItem[FIELD_GROUP_NAME];
2078 			if(groupName.isEmpty())
2079 				ok=false;
2080 			else {
2081 				//if(ok && gt.rules.searchGroup(yearName, groupName)>=0){
2082 				if(ok && groupsInYearSet.contains(QPair<QString, QString> (yearName, groupName))){
2083 					ok=false;
2084 					tryNext=true;
2085 				}
2086 				//StudentsSet* ss=gt.rules.searchStudentsSet(groupName);
2087 				StudentsSet* ss=studentsHash.value(groupName, nullptr);
2088 				if(ss!=nullptr && ss->type==STUDENTS_YEAR)
2089 					ok=false;
2090 				else if(ss!=nullptr && ss->type==STUDENTS_SUBGROUP)
2091 					ok=false;
2092 				else if(ss!=nullptr && ss->type==STUDENTS_GROUP){
2093 					if(fieldNumber[FIELD_SUBGROUP_NAME]==DO_NOT_IMPORT)
2094 						lastWarning+=Import::tr("Group name %1 exists in another year. It means that some years share the same group.").arg(groupName)+"\n";
2095 					if(fieldNumber[FIELD_SUBGROUP_NAME]!=DO_NOT_IMPORT)
2096 						if(fieldList[FIELD_SUBGROUP_NAME].isEmpty())
2097 							lastWarning+=Import::tr("Group name %1 exists in another year. It means that some years share the same group.").arg(groupName)+"\n";
2098 				}
2099 				if(ss!=nullptr&&ok){
2100 					sg=(StudentsGroup*)ss;
2101 				}
2102 				else if(ss==nullptr&&ok){
2103 					sg=new StudentsGroup();
2104 					sg->name=groupName;
2105 					QString tmpString=fieldList[FIELD_GROUP_NUMBER_OF_STUDENTS][i];
2106 					sg->numberOfStudents=tmpString.toInt();
2107 					if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
2108 						sg->comments=fieldList[FIELD_COMMENTS][i];
2109 					assert(ok);
2110 					assert(!fieldList[FIELD_GROUP_NUMBER_OF_STUDENTS].isEmpty());
2111 
2112 					studentsHash.insert(sg->name, sg);
2113 				}
2114 				if(ok){
2115 					StudentsSet* tmpStudentsSet=studentsHash.value(yearName, nullptr);
2116 					assert(tmpStudentsSet->type==STUDENTS_YEAR);
2117 
2118 					StudentsYear* year=(StudentsYear*)tmpStudentsSet;
2119 					assert(year!=nullptr);
2120 					gt.rules.addGroupFast(year, sg);
2121 
2122 					groupsInYearSet.insert(QPair<QString, QString> (yearName, sg->name));
2123 
2124 					addedGroups++;
2125 				}
2126 			}
2127 		}
2128 		if((tryNext || ok) && fieldNumber[FIELD_SUBGROUP_NAME]!=DO_NOT_IMPORT){
2129 			ok=true;
2130 			if(fieldNumber[FIELD_SUBGROUP_NAME]!=IMPORT_DEFAULT_ITEM)
2131 				subgroupName=fieldList[FIELD_SUBGROUP_NAME][i];
2132 			else
2133 				subgroupName=fieldDefaultItem[FIELD_SUBGROUP_NAME];
2134 			if(subgroupName.isEmpty())
2135 				ok=false;
2136 			else {
2137 				//if(ok && gt.rules.searchSubgroup(yearName, groupName, subgroupName)>=0){
2138 				if(ok && subgroupsInGroupSet.contains(QPair<QString, QString> (groupName, subgroupName))){
2139 					ok=false;
2140 				}
2141 				//StudentsSet* ss=gt.rules.searchStudentsSet(subgroupName);
2142 				StudentsSet* ss=studentsHash.value(subgroupName, nullptr);
2143 				StudentsSubgroup* sts;
2144 				sts=nullptr;
2145 				if(ss!=nullptr && ss->type==STUDENTS_YEAR){
2146 					ok=false;
2147 				}
2148 				else if(ss!=nullptr && ss->type==STUDENTS_GROUP){
2149 					ok=false;
2150 				}
2151 				else if(ss!=nullptr && ss->type==STUDENTS_SUBGROUP){
2152 					lastWarning+=Import::tr("Subgroup name %1 exists in another group. It means that some groups share the same subgroup.").arg(subgroupName)+"\n";
2153 				}
2154 				if(ss!=nullptr&&ok){
2155 					sts=(StudentsSubgroup*)ss;
2156 				}
2157 				else if(ss==nullptr&&ok) {
2158 					sts=new StudentsSubgroup();
2159 					sts->name=subgroupName;
2160 					QString tmpString=fieldList[FIELD_SUBGROUP_NUMBER_OF_STUDENTS][i];
2161 					sts->numberOfStudents=tmpString.toInt();
2162 					if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT)
2163 						sts->comments=fieldList[FIELD_COMMENTS][i];
2164 					assert(ok);
2165 					assert(!fieldList[FIELD_SUBGROUP_NUMBER_OF_STUDENTS].isEmpty());
2166 
2167 					studentsHash.insert(sts->name, sts);
2168 				}
2169 				if(ok){
2170 					StudentsSet* tmpStudentsSet=studentsHash.value(yearName, nullptr);
2171 					assert(tmpStudentsSet->type==STUDENTS_YEAR);
2172 
2173 					StudentsYear* year=(StudentsYear*)tmpStudentsSet;
2174 					assert(year!=nullptr);
2175 
2176 					tmpStudentsSet=studentsHash.value(groupName, nullptr);
2177 					assert(tmpStudentsSet->type==STUDENTS_GROUP);
2178 
2179 					StudentsGroup* group=(StudentsGroup*)tmpStudentsSet;
2180 					assert(group!=nullptr);
2181 
2182 					gt.rules.addSubgroupFast(year, group, sts);
2183 
2184 					subgroupsInGroupSet.insert(QPair<QString, QString> (groupName, sts->name));
2185 
2186 					addedSubgroups++;
2187 				}
2188 			}
2189 		}
2190 	}
2191 
2192 	progress3.setValue(qMax(fieldList[FIELD_YEAR_NAME].size(), 1));
2193 	//cout<<"progress3 in importCSVStudents ends"<<endl;
2194 	//add students (end) - similar to adding items by Liviu modified by Volker
2195 
2196 ifUserCanceledProgress3:
2197 
2198 	if(!lastWarning.isEmpty())
2199 		lastWarning.insert(0,"\n"+Import::tr("Notes:")+"\n");
2200 	lastWarning.insert(0,Import::tr("%1 subgroups added. Please check subgroups form.").arg(addedSubgroups)+"\n");
2201 	lastWarning.insert(0,Import::tr("%1 groups added. Please check groups form.").arg(addedGroups)+"\n");
2202 	lastWarning.insert(0,Import::tr("%1 years added. Please check years form.").arg(addedYears)+"\n");
2203 
2204 	gt.rules.computePermanentStudentsHash();
2205 
2206 	LastWarningsDialog lwd(newParent);
2207 	int w=chooseWidth(lwd.sizeHint().width());
2208 	int h=chooseHeight(lwd.sizeHint().height());
2209 	lwd.resize(w,h);
2210 	centerWidgetOnScreen(&lwd);
2211 
2212 	ok=lwd.exec();
2213 
2214 	int tmp=fileName.lastIndexOf(FILE_SEP);
2215 	IMPORT_DIRECTORY=fileName.left(tmp);
2216 	//gt.rules.internalStructureComputed=false;
2217 }
2218 
importCSVActivities(QWidget * parent)2219 void Import::importCSVActivities(QWidget* parent){
2220 	prearrangement();
2221 	fieldNumber[FIELD_STUDENTS_SET]=IMPORT_DEFAULT_ITEM;
2222 	fieldNumber[FIELD_SUBJECT_NAME]=IMPORT_DEFAULT_ITEM;
2223 	fieldNumber[FIELD_TEACHERS_SET]=IMPORT_DEFAULT_ITEM;
2224 	fieldNumber[FIELD_ACTIVITY_TAGS_SET]=IMPORT_DEFAULT_ITEM;
2225 	fieldNumber[FIELD_TOTAL_DURATION]=IMPORT_DEFAULT_ITEM;
2226 	fieldNumber[FIELD_SPLIT_DURATION]=IMPORT_DEFAULT_ITEM;
2227 	fieldNumber[FIELD_MIN_DAYS]=IMPORT_DEFAULT_ITEM;
2228 	fieldNumber[FIELD_MIN_DAYS_WEIGHT]=IMPORT_DEFAULT_ITEM;
2229 	fieldNumber[FIELD_MIN_DAYS_CONSECUTIVE]=IMPORT_DEFAULT_ITEM;
2230 	fieldNumber[FIELD_COMMENTS]=IMPORT_DEFAULT_ITEM;
2231 
2232 	int ok;
2233 
2234 	QDialog* newParent;
2235 	ok = getFileSeparatorFieldsAndHead(parent, newParent);
2236 	//DON'T ADD THIS! newParent->deleteLater();
2237 	if(!ok)	return;
2238 
2239 	if(fieldNumber[FIELD_SUBJECT_NAME]==IMPORT_DEFAULT_ITEM){
2240 		QDialog* newParent2=new ChooseFieldsDialog(newParent);
2241 		const QString settingsName=QString("ImportActivitiesChooseFieldsDialog");
2242 		//DON'T ADD THIS! newParent2->deleteLater();
2243 		newParent=newParent2;
2244 		ChooseFieldsDialog& cfd=(*((ChooseFieldsDialog*)newParent));
2245 		int w=chooseWidth(cfd.sizeHint().width());
2246 		int h=chooseHeight(cfd.sizeHint().height());
2247 		cfd.resize(w,h);
2248 		centerWidgetOnScreen(&cfd);
2249 		restoreFETDialogGeometry(&cfd, settingsName);
2250 
2251 		ok=cfd.exec();
2252 		saveFETDialogGeometry(&cfd, settingsName);
2253 	}
2254 	if(!ok)	return;
2255 
2256 	if(fieldNumber[FIELD_SPLIT_DURATION]==DO_NOT_IMPORT&&fieldNumber[FIELD_TOTAL_DURATION]==DO_NOT_IMPORT){
2257 		QMessageBox::warning(newParent, tr("FET warning"), Import::tr("FET needs to know %1 or %2 if you import %3.").arg(fieldName[FIELD_SPLIT_DURATION]).arg(fieldName[FIELD_TOTAL_DURATION]).arg(importThing));
2258 		return;
2259 	}
2260 
2261 	ok = readFields(newParent);
2262 	if(!ok) return;
2263 
2264 	//check number of fields (start) //because of bug reported 17.03.2008
2265 	int checkNumber=0;
2266 	if(fieldList[FIELD_STUDENTS_SET].size()>0){
2267 		checkNumber=fieldList[FIELD_STUDENTS_SET].size();
2268 	}
2269 	if(fieldList[FIELD_SUBJECT_NAME].size()>0){
2270 		if(checkNumber>0){
2271 			assert(checkNumber==fieldList[FIELD_SUBJECT_NAME].size());
2272 		}
2273 		checkNumber=fieldList[FIELD_SUBJECT_NAME].size();
2274 	}
2275 	if(fieldList[FIELD_TEACHERS_SET].size()>0){
2276 		if(checkNumber>0){
2277 			assert(checkNumber==fieldList[FIELD_TEACHERS_SET].size());
2278 		}
2279 		checkNumber=fieldList[FIELD_TEACHERS_SET].size();
2280 	}
2281 	if(fieldList[FIELD_ACTIVITY_TAGS_SET].size()>0){
2282 		if(checkNumber>0){
2283 			assert(checkNumber==fieldList[FIELD_ACTIVITY_TAGS_SET].size());
2284 		}
2285 		checkNumber=fieldList[FIELD_ACTIVITY_TAGS_SET].size();
2286 	}
2287 	if(fieldList[FIELD_TOTAL_DURATION].size()>0){
2288 		if(checkNumber>0){
2289 			assert(checkNumber==fieldList[FIELD_TOTAL_DURATION].size());
2290 		}
2291 		checkNumber=fieldList[FIELD_TOTAL_DURATION].size();
2292 	}
2293 	if(fieldList[FIELD_SPLIT_DURATION].size()>0){
2294 		if(checkNumber>0){
2295 			assert(checkNumber==fieldList[FIELD_SPLIT_DURATION].size());
2296 		}
2297 		checkNumber=fieldList[FIELD_SPLIT_DURATION].size();
2298 	}
2299 	if(fieldList[FIELD_MIN_DAYS].size()>0){
2300 		if(checkNumber>0){
2301 			assert(checkNumber==fieldList[FIELD_MIN_DAYS].size());
2302 		}
2303 		checkNumber=fieldList[FIELD_MIN_DAYS].size();
2304 	}
2305 	if(fieldList[FIELD_MIN_DAYS_WEIGHT].size()>0){
2306 		if(checkNumber>0){
2307 			assert(checkNumber==fieldList[FIELD_MIN_DAYS_WEIGHT].size());
2308 		}
2309 		checkNumber=fieldList[FIELD_MIN_DAYS_WEIGHT].size();
2310 	}
2311 	if(fieldList[FIELD_MIN_DAYS_CONSECUTIVE].size()>0){
2312 		if(checkNumber>0){
2313 			assert(checkNumber==fieldList[FIELD_MIN_DAYS_CONSECUTIVE].size());
2314 		}
2315 		checkNumber=fieldList[FIELD_MIN_DAYS_CONSECUTIVE].size();
2316 	}
2317 
2318 	if(fieldList[FIELD_STUDENTS_SET].size()==0){
2319 		for(int i=0; i<checkNumber; i++)
2320 			fieldList[FIELD_STUDENTS_SET]<<"";
2321 	}
2322 	if(fieldList[FIELD_SUBJECT_NAME].size()==0){
2323 		for(int i=0; i<checkNumber; i++)
2324 			fieldList[FIELD_SUBJECT_NAME]<<"";
2325 	}
2326 	if(fieldList[FIELD_TEACHERS_SET].size()==0){
2327 		for(int i=0; i<checkNumber; i++)
2328 			fieldList[FIELD_TEACHERS_SET]<<"";
2329 	}
2330 	if(fieldList[FIELD_ACTIVITY_TAGS_SET].size()==0){
2331 		for(int i=0; i<checkNumber; i++)
2332 			fieldList[FIELD_ACTIVITY_TAGS_SET]<<"";
2333 	}
2334 	if(fieldList[FIELD_TOTAL_DURATION].size()==0){
2335 		for(int i=0; i<checkNumber; i++)
2336 			fieldList[FIELD_TOTAL_DURATION]<<"1";
2337 	}
2338 	if(fieldList[FIELD_SPLIT_DURATION].size()==0){
2339 		for(int i=0; i<checkNumber; i++)
2340 			fieldList[FIELD_SPLIT_DURATION]<<"1";
2341 	}
2342 	if(fieldList[FIELD_MIN_DAYS].size()==0){
2343 		for(int i=0; i<checkNumber; i++)
2344 			fieldList[FIELD_MIN_DAYS]<<"1";
2345 	}
2346 	if(fieldList[FIELD_MIN_DAYS_WEIGHT].size()==0){
2347 		for(int i=0; i<checkNumber; i++)
2348 			fieldList[FIELD_MIN_DAYS_WEIGHT]<<"95";
2349 	}
2350 	if(fieldList[FIELD_MIN_DAYS_CONSECUTIVE].size()==0){
2351 		for(int i=0; i<checkNumber; i++)
2352 			fieldList[FIELD_MIN_DAYS_CONSECUTIVE]<<"no";
2353 	}
2354 
2355 	//check number of fields (end) //because of bug reported 17.03.2008
2356 
2357 	//check if already in memory (start)
2358 	//check if students set is in memory
2359 	/*QHash<QString, StudentsSet*> studentsHash;
2360 	for(StudentsYear* year : qAsConst(gt.rules.yearsList)){
2361 		studentsHash.insert(year->name, year);
2362 		for(StudentsGroup* group : qAsConst(year->groupsList)){
2363 			studentsHash.insert(group->name, group);
2364 			for(StudentsSubgroup* subgroup : qAsConst(group->subgroupsList)){
2365 				studentsHash.insert(subgroup->name, subgroup);
2366 			}
2367 		}
2368 	}*/
2369 	const QHash<QString, StudentsSet*>& studentsHash=gt.rules.permanentStudentsHash;
2370 
2371 	lastWarning.clear();
2372 	QString line;
2373 	QStringList students;
2374 	bool firstWarning=true;
2375 	for(int i=0; i<fieldList[FIELD_STUDENTS_SET].size(); i++){
2376 		line.clear();
2377 		line=fieldList[FIELD_STUDENTS_SET][i];
2378 		students.clear();
2379 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2380 		students=line.split("+", Qt::SkipEmptyParts);
2381 #else
2382 		students=line.split("+", QString::SkipEmptyParts);
2383 #endif
2384 		if(!fieldList[FIELD_STUDENTS_SET][i].isEmpty()){
2385 			for(int s=0; s<students.size(); s++){
2386 				//StudentsSet* ss=gt.rules.searchStudentsSet(students[s]);
2387 				StudentsSet* ss=studentsHash.value(students[s], nullptr);
2388 				if(ss==nullptr){
2389 					if(firstWarning){
2390 						lastWarning+=Import::tr("FET can't import activities, because FET needs to know the structure of the "
2391 						"students sets. You must add (or import) years, groups and subgroups first.")+"\n"+
2392 						tr("It is recommended to import also teachers, rooms, buildings, subjects and activity tags before "
2393 						"importing activities. It is not needed, because FET will automatically do it, but you can "
2394 						"check the activity csv file by that.")+"\n";
2395 						firstWarning=false;
2396 					}
2397 					lastWarning+=Import::tr("Students set %1 doesn't exist. You must add (or import) years, groups and subgroups first.").arg(students[s])+"\n";
2398 				}
2399 			}
2400 		}
2401 	}
2402 	if(lastWarning.size()>0){
2403 		QDialog* newParent2=new LastWarningsDialog(newParent);
2404 		//DON'T ADD THIS! newParent2->deleteLater();
2405 		newParent=newParent2;
2406 		LastWarningsDialog& lwd=(*((LastWarningsDialog*)newParent));
2407 		int w=chooseWidth(lwd.sizeHint().width());
2408 		int h=chooseHeight(lwd.sizeHint().height());
2409 		lwd.resize(w,h);
2410 		centerWidgetOnScreen(&lwd);
2411 
2412 		ok=lwd.exec();
2413 		return;
2414 	}
2415 	//check if teacher is in memory
2416 	assert(fieldList[FIELD_TEACHER_NAME].isEmpty());
2417 	QStringList teachers;
2418 	QSet<QString> tmpSet;
2419 	tmpSet.clear();
2420 	for(int i=0; i<gt.rules.teachersList.size(); i++){
2421 		Teacher* t=gt.rules.teachersList[i];
2422 		tmpSet.insert(t->name);
2423 	}
2424 	for(int i=0; i<fieldList[FIELD_TEACHERS_SET].size(); i++){
2425 		line.clear();
2426 		line=fieldList[FIELD_TEACHERS_SET][i];
2427 		teachers.clear();
2428 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2429 		teachers=line.split("+", Qt::SkipEmptyParts);
2430 #else
2431 		teachers=line.split("+", QString::SkipEmptyParts);
2432 #endif
2433 		for(int t=0; t<teachers.size(); t++){
2434 			bool add=true;
2435 			if(tmpSet.contains(teachers[t]) || teachers[t]=="")
2436 				add=false;
2437 			if(add){
2438 				dataWarning<<Import::tr("%1 %2 will be added.", "For instance 'Subject Math will be added', so use singular").arg(fieldName[FIELD_TEACHER_NAME]).arg(teachers[t]);
2439 				tmpSet.insert(teachers[t]);
2440 				fieldList[FIELD_TEACHER_NAME]<<teachers[t];
2441 			}
2442 		}
2443 	}
2444 	//check if subject is in memory
2445 	tmpSet.clear();
2446 	for(int i=0; i<gt.rules.subjectsList.size(); i++){
2447 		Subject* s=gt.rules.subjectsList[i];
2448 		tmpSet.insert(s->name);
2449 	}
2450 	for(int sn=0; sn<fieldList[FIELD_SUBJECT_NAME].size(); sn++){
2451 		bool add=true;
2452 		if(tmpSet.contains(fieldList[FIELD_SUBJECT_NAME][sn]) || fieldList[FIELD_SUBJECT_NAME][sn]=="")
2453 			add=false;
2454 		if(add){
2455 			dataWarning<<Import::tr("%1 %2 will be added.", "For instance 'Subject Math will be added', so use singular").arg(fieldName[FIELD_SUBJECT_NAME]).arg(fieldList[FIELD_SUBJECT_NAME][sn]);
2456 			tmpSet.insert(fieldList[FIELD_SUBJECT_NAME][sn]);
2457 		}
2458 	}
2459 	//check if activity tag is in memory
2460 	assert(fieldList[FIELD_ACTIVITY_TAG_NAME].isEmpty());
2461 	QStringList activityTags;
2462 	tmpSet.clear();
2463 	for(int i=0; i<gt.rules.activityTagsList.size(); i++){
2464 		ActivityTag* at=gt.rules.activityTagsList[i];
2465 		tmpSet.insert(at->name);
2466 	}
2467 	for(int i=0; i<fieldList[FIELD_ACTIVITY_TAGS_SET].size(); i++){
2468 		line.clear();
2469 		line=fieldList[FIELD_ACTIVITY_TAGS_SET][i];
2470 		activityTags.clear();
2471 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2472 		activityTags=line.split("+", Qt::SkipEmptyParts);
2473 #else
2474 		activityTags=line.split("+", QString::SkipEmptyParts);
2475 #endif
2476 		for(int at=0; at<activityTags.size(); at++){
2477 			bool add=true;
2478 			if(tmpSet.contains(activityTags[at]) || activityTags[at]=="")
2479 				add=false;
2480 			if(add){
2481 				dataWarning<<Import::tr("%1 %2 will be added.", "For instance 'Subject Math will be added', so use singular").arg(fieldName[FIELD_ACTIVITY_TAG_NAME]).arg(activityTags[at]);
2482 				tmpSet.insert(activityTags[at]);
2483 				fieldList[FIELD_ACTIVITY_TAG_NAME]<<activityTags[at];
2484 			}
2485 		}
2486 	}
2487 	tmpSet.clear();
2488 	//check if already in memory (end)
2489 
2490 	QDialog* newParent2;
2491 	ok = showFieldsAndWarnings(newParent, newParent2);
2492 	//DON'T ADD THIS! newParent2->deleteLater();
2493 	newParent=newParent2;
2494 	if(!ok) return;
2495 
2496 	//add teachers
2497 	//maybe TODO write a function, so also import teacher csv can share this code
2498 	tmpSet.clear();
2499 	for(Teacher* tch : qAsConst(gt.rules.teachersList))
2500 		tmpSet.insert(tch->name);
2501 	int count=0;
2502 	for(int i=0; i<fieldList[FIELD_TEACHER_NAME].size(); i++){
2503 		if(!fieldList[FIELD_TEACHER_NAME][i].isEmpty()){
2504 			Teacher* tch=new Teacher();
2505 			if(gt.rules.mode==MORNINGS_AFTERNOONS)
2506 				tch->morningsAfternoonsBehavior=TEACHER_UNRESTRICTED_MORNINGS_AFTERNOONS;
2507 			tch->name=fieldList[FIELD_TEACHER_NAME][i];
2508 			assert(!tmpSet.contains(tch->name));
2509 			if(!gt.rules.addTeacherFast(tch)){
2510 				delete tch;
2511 				assert(0);
2512 			} else
2513 				count++;
2514 			tmpSet.insert(tch->name);
2515 		}
2516 	}
2517 	fieldList[FIELD_TEACHER_NAME].clear();
2518 	if(count>0)
2519 		lastWarning+=Import::tr("%1 teachers added. Please check teachers form.").arg(count)+"\n";
2520 	//add subjects
2521 	//maybe TODO write a function, so also import subjects csv can share this code
2522 	tmpSet.clear();
2523 	for(Subject* sbj : qAsConst(gt.rules.subjectsList))
2524 		tmpSet.insert(sbj->name);
2525 	count=0;
2526 	for(int i=0; i<fieldList[FIELD_SUBJECT_NAME].size(); i++){
2527 		if(!fieldList[FIELD_SUBJECT_NAME][i].isEmpty() && !tmpSet.contains(fieldList[FIELD_SUBJECT_NAME][i])){
2528 			Subject* s=new Subject();
2529 			s->name=fieldList[FIELD_SUBJECT_NAME][i];
2530 			assert(!tmpSet.contains(s->name));
2531 			if(!gt.rules.addSubjectFast(s)){
2532 				delete s;
2533 				assert(0);
2534 			} else
2535 				count++;
2536 			tmpSet.insert(s->name);
2537 		}
2538 	}
2539 	if(count>0)
2540 		lastWarning+=Import::tr("%1 subjects added. Please check subjects form.").arg(count)+"\n";
2541 	//add activity tags
2542 	//maybe TODO write a function, so also import activity tags csv can share this code
2543 	tmpSet.clear();
2544 	for(ActivityTag* at : qAsConst(gt.rules.activityTagsList))
2545 		tmpSet.insert(at->name);
2546 	count=0;
2547 	for(int i=0; i<fieldList[FIELD_ACTIVITY_TAG_NAME].size(); i++){
2548 		if(!fieldList[FIELD_ACTIVITY_TAG_NAME][i].isEmpty()){
2549 			ActivityTag* a=new ActivityTag();
2550 			a->name=fieldList[FIELD_ACTIVITY_TAG_NAME][i];
2551 			assert(!tmpSet.contains(a->name));
2552 			if(!gt.rules.addActivityTag(a)){
2553 				delete a;
2554 				assert(0);
2555 			} else
2556 				count++;
2557 			tmpSet.insert(a->name);
2558 		}
2559 	}
2560 	if(count>0)
2561 		lastWarning+=Import::tr("%1 activity tags added. Please check activity tags form.").arg(count)+"\n";
2562 
2563 	//add activities (start) - similar to Liviu's code modified by Volker
2564 	count=0;
2565 	int count2=0;
2566 	int activityid=0; //We set the id of this newly added activity = (the largest existing id + 1)
2567 	for(int i=0; i<gt.rules.activitiesList.size(); i++){	//TODO: do it the same in addactivityform.cpp (calculate activity id just one time)
2568 		Activity* act=gt.rules.activitiesList[i];
2569 		if(act->id > activityid)
2570 			activityid = act->id;
2571 	}
2572 	activityid++;
2573 	QProgressDialog* _progress4=new QProgressDialog(newParent);
2574 	QProgressDialog& progress4=(*_progress4);
2575 	progress4.setWindowTitle(tr("Importing", "Title of a progress dialog"));
2576 	progress4.setLabelText(tr("Importing activities"));
2577 	progress4.setModal(true);
2578 	progress4.setRange(0, qMax(fieldList[FIELD_SUBJECT_NAME].size(), 1));
2579 
2580 	bool incorrect_bool_consecutive=false;
2581 
2582 	for(int i=0; i<fieldList[FIELD_SUBJECT_NAME].size(); i++){
2583 		progress4.setValue(i);
2584 		if(progress4.wasCanceled()){
2585 			progress4.setValue(fieldList[FIELD_SUBJECT_NAME].size());
2586 			QMessageBox::warning(newParent, "FET", Import::tr("Importing data canceled by user."));
2587 			//return false;
2588 			ok=false;
2589 			goto ifUserCanceledProgress4;
2590 		}
2591 
2592 		bool ok2;
2593 		QString tmpStr=fieldList[FIELD_MIN_DAYS_WEIGHT][i];
2594 //		double weight=tmpStr.toDouble(&ok2);
2595 		double weight=customFETStrToDouble(tmpStr, &ok2);
2596 		assert(ok2);
2597 
2598 		QStringList teachers_namesFromFile;
2599 		if(!fieldList[FIELD_TEACHERS_SET][i].isEmpty())
2600 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2601 			teachers_namesFromFile = fieldList[FIELD_TEACHERS_SET][i].split("+", Qt::SkipEmptyParts);
2602 #else
2603 			teachers_namesFromFile = fieldList[FIELD_TEACHERS_SET][i].split("+", QString::SkipEmptyParts);
2604 #endif
2605 
2606 		QStringList teachers_names;
2607 		QSet<QString> _teachersSet;
2608 		for(const QString& teacherName : qAsConst(teachers_namesFromFile)){
2609 			//assert(teachersHash.contains(teacherName));
2610 			if(!_teachersSet.contains(teacherName)){
2611 				_teachersSet.insert(teacherName);
2612 				teachers_names<<teacherName;
2613 			} else {
2614 				lastWarning+=tr("Line %1: Activity contains duplicate teacher %2 - please correct that").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(teacherName)+"\n";
2615 			}
2616 		}
2617 
2618 		QString subject_name = fieldList[FIELD_SUBJECT_NAME][i];
2619 
2620 		QStringList activity_tags_namesFromFile;
2621 		if(!fieldList[FIELD_ACTIVITY_TAGS_SET][i].isEmpty())
2622 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2623 			activity_tags_namesFromFile = fieldList[FIELD_ACTIVITY_TAGS_SET][i].split("+", Qt::SkipEmptyParts);
2624 #else
2625 			activity_tags_namesFromFile = fieldList[FIELD_ACTIVITY_TAGS_SET][i].split("+", QString::SkipEmptyParts);
2626 #endif
2627 
2628 		QStringList activity_tags_names;
2629 		QSet<QString> _activityTagsSet;
2630 		for(const QString& activityTag : qAsConst(activity_tags_namesFromFile)){
2631 			//assert(activityTagsHash.contains(activityTag));
2632 			if(!_activityTagsSet.contains(activityTag)){
2633 				_activityTagsSet.insert(activityTag);
2634 				activity_tags_names<<activityTag;
2635 			} else {
2636 				lastWarning+=tr("Line %1: Activity contains duplicate activity tag %2 - please correct that").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(activityTag)+"\n";
2637 			}
2638 		}
2639 
2640 		QStringList students_namesFromFile;
2641 		if(!fieldList[FIELD_STUDENTS_SET][i].isEmpty())
2642 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2643 			students_namesFromFile = fieldList[FIELD_STUDENTS_SET][i].split("+", Qt::SkipEmptyParts);
2644 #else
2645 			students_namesFromFile = fieldList[FIELD_STUDENTS_SET][i].split("+", QString::SkipEmptyParts);
2646 #endif
2647 
2648 		int numberOfStudents=0;
2649 		QStringList students_names;
2650 		QSet<QString> _studentsSet;
2651 		for(const QString& studentsSet : qAsConst(students_namesFromFile)){
2652 			assert(studentsHash.contains(studentsSet));
2653 			if(!_studentsSet.contains(studentsSet)){
2654 				_studentsSet.insert(studentsSet);
2655 				students_names<<studentsSet;
2656 			} else {
2657 				lastWarning+=tr("Line %1: Activity contains duplicate students set %2 - please correct that").arg(fieldList[FIELD_LINE_NUMBER][i]).arg(studentsSet)+"\n";
2658 			}
2659 			numberOfStudents+=studentsHash.value(studentsSet)->numberOfStudents;
2660 		}
2661 
2662 		QStringList splitDurationList;
2663 		splitDurationList.clear();
2664 		assert(!fieldList[FIELD_SPLIT_DURATION][i].isEmpty());
2665 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2666 		splitDurationList = fieldList[FIELD_SPLIT_DURATION][i].split("+", Qt::SkipEmptyParts);
2667 #else
2668 		splitDurationList = fieldList[FIELD_SPLIT_DURATION][i].split("+", QString::SkipEmptyParts);
2669 #endif
2670 		int nsplit=splitDurationList.size();
2671 		if(nsplit==1){
2672 			int duration=fieldList[FIELD_TOTAL_DURATION][i].toInt(&ok2, 10);
2673 			assert(ok2);
2674 			bool active=true;
2675 			//workaround only. Please rethink. (start)
2676 			/*QStringList activity_tag_names;
2677 			activity_tag_names<<activity_tag_name;*/
2678 			//workaround only. Please rethink. (end)
2679 
2680 			/*Activity a(gt.rules, activityid, 0, teachers_names, subject_name, activity_tags_names, students_names, duration, duration, active, true, -1);
2681 
2682 			bool already_existing=false;
2683 			for(int i=0; i<gt.rules.activitiesList.size(); i++){
2684 				Activity* act=gt.rules.activitiesList[i];
2685 				if((*act)==a)
2686 					already_existing=true;
2687 			}
2688 			if(already_existing){
2689 				lastWarning+=Import::tr("Activity %1 already exists. A duplicate activity is imported. Please check the dataset!").arg(activityid)+"\n";
2690 			}*/
2691 			if(duration>0){
2692 				bool tmp=gt.rules.addSimpleActivityFast(newParent, activityid, 0, teachers_names, subject_name, activity_tags_names,
2693 					students_names, duration, duration, active, true, -1, numberOfStudents);
2694 				if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT){
2695 					assert(!gt.rules.activitiesList.isEmpty());
2696 					gt.rules.activitiesList.last()->comments=fieldList[FIELD_COMMENTS][i];
2697 				}
2698 				activityid++;
2699 				if(tmp){
2700 					count++;
2701 					count2++;
2702 				}
2703 				else
2704 					QMessageBox::critical(newParent, tr("FET information"), tr("Activity NOT added - please report error"));
2705 			} else {
2706 				lastWarning+=tr("Line %1: Activity duration is lower than 1 - please correct that").arg(fieldList[FIELD_LINE_NUMBER][i])+"\n";
2707 			}
2708 		}
2709 		else{ //split activity
2710 			int totalduration;
2711 			QList<int> durations;
2712 			QList<bool> active;
2713 
2714 			totalduration=0;
2715 			bool durationOK=true;
2716 			for(int s=0; s<nsplit; s++){
2717 				durations.append(splitDurationList[s].toInt(&ok2));
2718 				assert(ok2);
2719 				if(durations[s]<1){
2720 					durationOK=false;
2721 				}
2722 				active.append(true);
2723 				totalduration+=durations[s];
2724 			}
2725 			if(durationOK){
2726 				assert(totalduration==fieldList[FIELD_TOTAL_DURATION][i].toInt(&ok2));
2727 				assert(ok2);
2728 
2729 				int minD=fieldList[FIELD_MIN_DAYS][i].toInt(&ok2);
2730 				assert(ok2);
2731 				bool force;
2732 
2733 				if(fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="YES" ||
2734 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="Y" ||
2735 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="TRUE" ||
2736 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="T" ||
2737 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="1"
2738 				)
2739 					force=true;
2740 				else if(
2741 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="NO" ||
2742 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="N" ||
2743 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="FALSE" ||
2744 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="F" ||
2745 					fieldList[FIELD_MIN_DAYS_CONSECUTIVE][i].toUpper()=="0"
2746 				)
2747 					force=false;
2748 				else{
2749 					incorrect_bool_consecutive=true;
2750 					force=true;
2751 				}
2752 				//workaround only. Please rethink. (start)
2753 				/*QStringList activity_tag_names;
2754 				activity_tag_names<<activity_tag_name;*/
2755 				//workaround only. Please rethink. (end)
2756 				bool tmp=gt.rules.addSplitActivityFast(newParent, activityid, activityid,
2757 					teachers_names, subject_name, activity_tags_names, students_names,
2758 					nsplit, totalduration, durations,
2759 					active, minD, weight, force, true, -1, numberOfStudents);
2760 				if(fieldNumber[FIELD_COMMENTS]!=DO_NOT_IMPORT){
2761 					assert(gt.rules.activitiesList.count()>=nsplit);
2762 					for(int j=1; j<=nsplit; j++)
2763 						gt.rules.activitiesList.at(gt.rules.activitiesList.count()-j)->comments=fieldList[FIELD_COMMENTS][i];
2764 				}
2765 				activityid+=nsplit;
2766 				if(tmp){
2767 					count++;
2768 					count2+=nsplit;
2769 				}
2770 				else
2771 					QMessageBox::critical(newParent, tr("FET information"), tr("Split activity NOT added - error???"));
2772 			} else {
2773 				lastWarning+=tr("Line %1: Activity duration is lower than 1 - please correct that").arg(fieldList[FIELD_LINE_NUMBER][i])+"\n";
2774 			}
2775 		}
2776 	}
2777 	progress4.setValue(qMax(fieldList[FIELD_SUBJECT_NAME].size(), 1));
2778 	//add activities (end) - similar to Liviu's code modified by Volker
2779 ifUserCanceledProgress4:
2780 
2781 	if(incorrect_bool_consecutive){
2782 		lastWarning.insert(0, tr("Warning: found tags for the 'consecutive' field of min days which are not a valid boolean value (%1) - making them %2").arg("1, 0, yes, no, y, n, true, false, t, f").arg("true")+"\n");
2783 	}
2784 
2785 	if(!lastWarning.isEmpty())
2786 		lastWarning.insert(0,Import::tr("Notes:")+"\n");
2787 	if(count>0)
2788 		lastWarning.insert(0,Import::tr("%1 container activities (%2 total activities) added. Please check activities form.").arg(count).arg(count2)+"\n");
2789 
2790 	QDialog* newParent3=new LastWarningsDialog(newParent);
2791 	//DON'T ADD THIS! newParent3->deleteLater();
2792 	newParent=newParent3;
2793 	LastWarningsDialog& lwd=(*((LastWarningsDialog*)newParent));
2794 	int w=chooseWidth(lwd.sizeHint().width());
2795 	int h=chooseHeight(lwd.sizeHint().height());
2796 	lwd.resize(w,h);
2797 	centerWidgetOnScreen(&lwd);
2798 
2799 	ok=lwd.exec();
2800 
2801 	int tmp=fileName.lastIndexOf(FILE_SEP);
2802 	IMPORT_DIRECTORY=fileName.left(tmp);
2803 	//gt.rules.internalStructureComputed=false;
2804 }
2805