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