1 /*
2 File timetableexport.cpp
3 */
4
5 /***************************************************************************
6 timetableexport.cpp - description
7 -------------------
8 begin : Tue Apr 22 2003
9 copyright : (C) 2003 by Lalescu Liviu
10 email : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
11 ***************************************************************************/
12
13 /***************************************************************************
14 * *
15 * This program is free software: you can redistribute it and/or modify *
16 * it under the terms of the GNU Affero General Public License as *
17 * published by the Free Software Foundation, either version 3 of the *
18 * License, or (at your option) any later version. *
19 * *
20 ***************************************************************************/
21
22 //**********************************************************************************************************************/
23 //August 2007
24 //XHTML generation code by Volker Dirr (timetabling.de)
25 //Features: - XHTML 1.0 strict valid
26 // - using colspan and rowspan
27 // - table of contents with hyperlinks
28 // - CSS and JavaScript support
29 // - index HTML file
30 // - TIMETABLE_HTML_LEVEL
31 // - days/time horizontal/vertical
32 // - subgroups, groups, years, teachers, rooms, subjects, activities, activity tags timetable
33 // - teachers free periods
34 // - daily timetable
35 // - activities with same starting time
36 // - reorganized functions. now they can be also used for printing
37 // - split times tables after X names (TIMETABLE_HTML_SPLIT?) and choose if activity tags should be printed (TIMETABLE_HTML_PRINT_ACTIVITY_TAGS)
38 // - teachers and students statistics (gaps, free days, hours)
39
40 //TODO: all must be internal here. so maybe also do daysOfTheWeek and hoursPerDay also internal
41 //maybe TODO: use back_odd and back_even (or back0 and back1, because easier to code!) like in printing. so don't use the table_odd and table_even anymore
42 //maybe TODO: make TIMETABLE_HTML_SPLIT? (similar to TIMETABLE_HTML_LEVEL)
43 //maybe TODO: rename augmentedYearsList into internalYearsList to have it similar to others?
44 //maybe TODO: some "stg" stuff can be replaced by gt.rules.internalGroupsList. I don't want to do that now, because id-s will change. That is not critical, but I want to diff tables with old release.
45
46 #include "timetable_defs.h"
47 #include "timetable.h"
48 #include "timetableexport.h"
49 #include "solution.h"
50
51 #include "matrix.h"
52
53 #include <iostream>
54 using namespace std;
55
56 #include <Qt>
57
58 #include <QString>
59 #include <QTextStream>
60 #include <QFile>
61
62 #include <QList>
63
64 #include <QHash>
65
66 #include "messageboxes.h"
67
68 #include <QLocale>
69 #include <QTime>
70 #include <QDate>
71
72 #include <QDir>
73
74 //std::stable_sort
75 #include <algorithm>
76
77 //Represents the current status of the simulation - running or stopped.
78 //extern bool simulation_running;
79
80 extern bool students_schedule_ready;
81 extern bool teachers_schedule_ready;
82 extern bool rooms_schedule_ready;
83
84 extern Solution best_solution;
85 extern bool LANGUAGE_STYLE_RIGHT_TO_LEFT;
86 extern QString LANGUAGE_FOR_HTML;
87
88 extern Timetable gt;
89 extern Matrix3D<int> teachers_timetable_weekly;
90 extern Matrix3D<int> students_timetable_weekly;
91 extern Matrix3D<int> rooms_timetable_weekly;
92 extern Matrix3D<QList<int>> virtual_rooms_timetable_weekly;
93
94 extern Matrix3D<QList<int>> teachers_free_periods_timetable_weekly;
95
96 extern Matrix2D<bool> breakDayHour;
97 extern Matrix3D<bool> teacherNotAvailableDayHour;
98 extern Matrix2D<double> notAllowedRoomTimePercentages;
99 extern Matrix3D<bool> subgroupNotAvailableDayHour;
100
101 static Matrix2D<QList<int>> activitiesForCurrentSubject;
102 static Matrix2D<QList<int>> activitiesForCurrentActivityTag;
103
104 static Matrix2D<QList<int>> activitiesAtTime;
105
106 extern Rules rules2;
107
108 const QString STRING_EMPTY_SLOT="---";
109
110 const QString STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES="???";
111
112 const QString STRING_NOT_AVAILABLE_TIME_SLOT="-x-";
113
114 const QString STRING_BREAK_SLOT="-X-";
115
116 //these hashes are needed to get the IDs for html and css in timetableexport and statistics
117 static QHash<QString, QString> hashSubjectIDsTimetable;
118 static QHash<QString, QString> hashActivityTagIDsTimetable;
119 static QHash<QString, QString> hashStudentIDsTimetable;
120 static QHash<QString, QString> hashTeacherIDsTimetable;
121 static QHash<QString, QString> hashRoomIDsTimetable;
122 static QHash<QString, QString> hashDayIDsTimetable;
123
124 //static QHash<QString, QString> hashColorStringIDsTimetable;
125 QHash<int, int> hashActivityColorBySubject;
126 QList<int> activeHashActivityColorBySubject;
127 QHash<int, int> hashActivityColorBySubjectAndStudents;
128 QList<int> activeHashActivityColorBySubjectAndStudents;
129 const int COLOR_BY_SUBJECT=1;
130 const int COLOR_BY_SUBJECT_STUDENTS=2;
131
132 //this hash is needed to care about sctivities with same starting time
133 static QHash<int, QList<int>>activitiesWithSameStartingTime;
134
135 //Now the filenames of the output files are following (for xml and all html tables)
136 const QString SUBGROUPS_TIMETABLE_FILENAME_XML="subgroups.xml";
137 const QString TEACHERS_TIMETABLE_FILENAME_XML="teachers.xml";
138 const QString ACTIVITIES_TIMETABLE_FILENAME_XML="activities.xml";
139 //const QString ROOMS_TIMETABLE_FILENAME_XML="rooms.xml";
140
141 const QString CONFLICTS_FILENAME="soft_conflicts.txt";
142 const QString INDEX_HTML="index.html";
143 const QString STYLESHEET_CSS="stylesheet.css";
144
145 const QString SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="subgroups_days_horizontal.html";
146 const QString SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="subgroups_days_vertical.html";
147 const QString SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="subgroups_time_horizontal.html";
148 const QString SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="subgroups_time_vertical.html";
149
150 const QString GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="groups_days_horizontal.html";
151 const QString GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="groups_days_vertical.html";
152 const QString GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="groups_time_horizontal.html";
153 const QString GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="groups_time_vertical.html";
154
155 const QString YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="years_days_horizontal.html";
156 const QString YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="years_days_vertical.html";
157 const QString YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="years_time_horizontal.html";
158 const QString YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="years_time_vertical.html";
159
160 const QString TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="teachers_days_horizontal.html";
161 const QString TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="teachers_days_vertical.html";
162 const QString TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="teachers_time_horizontal.html";
163 const QString TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="teachers_time_vertical.html";
164
165 const QString ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="rooms_days_horizontal.html";
166 const QString ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="rooms_days_vertical.html";
167 const QString ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="rooms_time_horizontal.html";
168 const QString ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="rooms_time_vertical.html";
169
170 const QString SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="subjects_days_horizontal.html";
171 const QString SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="subjects_days_vertical.html";
172 const QString SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="subjects_time_horizontal.html";
173 const QString SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="subjects_time_vertical.html";
174
175 const QString ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="activity_tags_days_horizontal.html";
176 const QString ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="activity_tags_days_vertical.html";
177 const QString ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="activity_tags_time_horizontal.html";
178 const QString ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="activity_tags_time_vertical.html";
179
180 const QString ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="activities_days_horizontal.html";
181 const QString ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="activities_days_vertical.html";
182 const QString ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML="activities_time_horizontal.html";
183 const QString ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML="activities_time_vertical.html";
184
185 const QString TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML="teachers_free_periods_days_horizontal.html";
186 const QString TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML="teachers_free_periods_days_vertical.html";
187
188 const QString TEACHERS_STATISTICS_FILENAME_HTML="teachers_statistics.html";
189 const QString STUDENTS_STATISTICS_FILENAME_HTML="students_statistics.html";
190
191 const QString MULTIPLE_TIMETABLE_DATA_RESULTS_FILE="data_and_timetable.fet";
192
193 //now the XML tags used for identification of the output file (is that comment correct? it's the old comment)
194 const QString STUDENTS_TIMETABLE_TAG="Students_Timetable";
195 const QString TEACHERS_TIMETABLE_TAG="Teachers_Timetable";
196 const QString ACTIVITIES_TIMETABLE_TAG="Activities_Timetable";
197 const QString ROOMS_TIMETABLE_TAG="Rooms_Timetable";
198
199 const QString RANDOM_SEED_FILENAME_BEFORE="random_seed_before.txt";
200 const QString RANDOM_SEED_FILENAME_AFTER="random_seed_after.txt";
201
202 //extern int XX;
203 //extern int YY;
204 //extern MRG32k3a rng;
205
206 QString generationLocalizedTime=QString(""); //to be used in timetableprintform.cpp
207
208 //similar with the code from Marco Vassura, modified by Volker Dirr to avoid usage of QColor and QBrush, since these need QtGui.
209 //(the command-line version does not have access to QtGui.)
210 //slightly modified by Liviu Lalescu on 2021-03-01
stringToColor(const QString & s,int & r,int & g,int & b)211 void TimetableExport::stringToColor(const QString& s, int& r, int& g, int& b)
212 {
213 // CRC-24 based on RFC 2440 Section 6.1
214 unsigned long int crc = 0xB704CEUL;
215 QByteArray ba=s.toUtf8();
216 for(char c : qAsConst(ba)){
217 unsigned char uc=(unsigned char)(c);
218 crc ^= (uc & 0xFF) << 16;
219 for (int i = 0; i < 8; i++) {
220 crc <<= 1;
221 if (crc & 0x1000000UL)
222 crc ^= 0x1864CFBUL;
223 }
224 }
225
226 r = int((crc>>16) & 0xFF);
227 g = int((crc>>8) & 0xFF);
228 b = int(crc & 0xFF);
229 }
230 //similar with the code from Marco Vassura, modified by Volker Dirr
231
writeAtLeastATimetable()232 bool writeAtLeastATimetable()
233 {
234 bool t = WRITE_TIMETABLE_CONFLICTS ||
235
236 (WRITE_TIMETABLES_STATISTICS &&
237 (WRITE_TIMETABLES_SUBGROUPS ||
238 WRITE_TIMETABLES_GROUPS ||
239 WRITE_TIMETABLES_YEARS ||
240 WRITE_TIMETABLES_TEACHERS)) ||
241
242 (WRITE_TIMETABLES_XML &&
243 (WRITE_TIMETABLES_SUBGROUPS ||
244 WRITE_TIMETABLES_TEACHERS ||
245 WRITE_TIMETABLES_ACTIVITIES)) ||
246
247 ((WRITE_TIMETABLES_DAYS_HORIZONTAL ||
248 WRITE_TIMETABLES_DAYS_VERTICAL ||
249 WRITE_TIMETABLES_TIME_HORIZONTAL ||
250 WRITE_TIMETABLES_TIME_VERTICAL) &&
251 (WRITE_TIMETABLES_SUBGROUPS ||
252 WRITE_TIMETABLES_GROUPS ||
253 WRITE_TIMETABLES_YEARS ||
254 WRITE_TIMETABLES_TEACHERS ||
255 WRITE_TIMETABLES_ROOMS ||
256 WRITE_TIMETABLES_SUBJECTS ||
257 WRITE_TIMETABLES_ACTIVITY_TAGS ||
258 WRITE_TIMETABLES_ACTIVITIES)) ||
259
260 ((WRITE_TIMETABLES_DAYS_HORIZONTAL ||
261 WRITE_TIMETABLES_DAYS_VERTICAL) &&
262 WRITE_TIMETABLES_TEACHERS_FREE_PERIODS);
263
264 return t;
265 }
266
TimetableExport()267 TimetableExport::TimetableExport()
268 {
269 }
270
~TimetableExport()271 TimetableExport::~TimetableExport()
272 {
273 }
274
275 /*void TimetableExport::getStudentsTimetable(Solution &c){
276 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
277
278 c.getSubgroupsTimetable(gt.rules, students_timetable_weekly);
279 best_solution.copy(gt.rules, c);
280 students_schedule_ready=true;
281 }
282
283 void TimetableExport::getTeachersTimetable(Solution &c){
284 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
285
286 c.getTeachersTimetable(gt.rules, teachers_timetable_weekly, teachers_free_periods_timetable_weekly);
287 best_solution.copy(gt.rules, c);
288 teachers_schedule_ready=true;
289 }
290
291 void TimetableExport::getRoomsTimetable(Solution &c){
292 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
293
294 c.getRoomsTimetable(gt.rules, rooms_timetable_weekly, virtual_rooms_timetable_weekly);
295 best_solution.copy(gt.rules, c);
296 rooms_schedule_ready=true;
297 }*/
298
getStudentsTeachersRoomsTimetable(Solution & c)299 void TimetableExport::getStudentsTeachersRoomsTimetable(Solution &c){
300 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
301
302 c.getSubgroupsTimetable(gt.rules, students_timetable_weekly);
303 c.getTeachersTimetable(gt.rules, teachers_timetable_weekly, teachers_free_periods_timetable_weekly);
304 c.getRoomsTimetable(gt.rules, rooms_timetable_weekly, virtual_rooms_timetable_weekly);
305
306 best_solution.copy(gt.rules, c);
307
308 students_schedule_ready=true;
309 teachers_schedule_ready=true;
310 rooms_schedule_ready=true;
311 }
312
getNumberOfPlacedActivities(int & number1,int & number2)313 void TimetableExport::getNumberOfPlacedActivities(int& number1, int& number2)
314 {
315 number1=0;
316 for(int i=0; i<gt.rules.nInternalActivities; i++)
317 if(best_solution.times[i]!=UNALLOCATED_TIME)
318 number1++;
319
320 number2=0;
321 for(int i=0; i<gt.rules.nInternalActivities; i++)
322 if(best_solution.rooms[i]!=UNALLOCATED_SPACE)
323 number2++;
324 }
325
writeSimulationResults(QWidget * parent)326 void TimetableExport::writeSimulationResults(QWidget* parent){
327 QList<int> subgroupsSortedOrder;
328 QList<StudentsSubgroup*> lst;
329 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
330 lst.append(gt.rules.internalSubgroupsList[subgroup]);
331 if(TIMETABLES_SUBGROUPS_SORTED)
332 std::stable_sort(lst.begin(), lst.end(), subgroupsAscending);
333 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
334 subgroupsSortedOrder.append(lst.at(subgroup)->indexInInternalSubgroupsList);
335
336 QDir dir;
337
338 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
339
340 OUTPUT_DIR_TIMETABLES.append(FILE_SEP);
341 if(INPUT_FILENAME_XML=="")
342 OUTPUT_DIR_TIMETABLES.append("unnamed");
343 else{
344 OUTPUT_DIR_TIMETABLES.append(INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1));
345 if(OUTPUT_DIR_TIMETABLES.right(4)==".fet")
346 OUTPUT_DIR_TIMETABLES=OUTPUT_DIR_TIMETABLES.left(OUTPUT_DIR_TIMETABLES.length()-4);
347 //else if(INPUT_FILENAME_XML!="")
348 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
349 }
350 OUTPUT_DIR_TIMETABLES.append("-single");
351
352 //make sure that the output directory exists
353 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
354 dir.mkpath(OUTPUT_DIR_TIMETABLES);
355
356 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
357 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
358 assert(TIMETABLE_HTML_LEVEL>=0);
359 assert(TIMETABLE_HTML_LEVEL<=7);
360
361 computeHashForIDsTimetable();
362 computeActivitiesAtTime();
363 computeActivitiesWithSameStartingTime();
364
365 QString s;
366 QString bar;
367 if(INPUT_FILENAME_XML=="")
368 bar="";
369 else
370 bar="_";
371 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
372 if(s2.right(4)==".fet")
373 s2=s2.left(s2.length()-4);
374 //else if(INPUT_FILENAME_XML!="")
375 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
376
377 //now write the solution in xml files
378 //subgroups
379 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_FILENAME_XML;
380 writeSubgroupsTimetableXml(parent, s, subgroupsSortedOrder);
381 //teachers
382 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_FILENAME_XML;
383 writeTeachersTimetableXml(parent, s);
384 //activities
385 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITIES_TIMETABLE_FILENAME_XML;
386 writeActivitiesTimetableXml(parent, s);
387
388 //now get the time. TODO: maybe write it in xml too? so do it a few lines earlier!
389 QDate dat=QDate::currentDate();
390 QTime tim=QTime::currentTime();
391 QLocale loc(FET_LANGUAGE);
392 QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
393 generationLocalizedTime=sTime;
394
395 //now get the number of placed activities. TODO: maybe write it in xml too? so do it a few lines earlier!
396 int na=0;
397 int na2=0;
398 getNumberOfPlacedActivities(na, na2);
399
400 if(na==gt.rules.nInternalActivities && na==na2){
401 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+MULTIPLE_TIMETABLE_DATA_RESULTS_FILE;
402 if(VERBOSE){
403 cout<<"Since the simulation is complete, FET will write also the timetable data file"<<endl;
404 }
405 writeTimetableDataFile(parent, s);
406 }
407
408 //write the conflicts in txt mode
409 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+CONFLICTS_FILENAME;
410 writeConflictsTxt(parent, s, sTime, na);
411
412 //now write the solution in html files
413 if(TIMETABLE_HTML_LEVEL>=1){
414 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+STYLESHEET_CSS;
415 writeStylesheetCss(parent, s, sTime, na);
416 }
417
418 //indexHtml
419 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+INDEX_HTML;
420 writeIndexHtml(parent, s, sTime, na);
421
422 //subgroups
423 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
424 writeSubgroupsTimetableDaysHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
425 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
426 writeSubgroupsTimetableDaysVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
427 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
428 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
429 writeSubgroupsTimetableTimeHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
430 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
431 writeSubgroupsTimetableTimeVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
432 } else {
433 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
434 writeSubgroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
435 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
436 writeSubgroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
437 }
438 //groups
439 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
440 writeGroupsTimetableDaysHorizontalHtml(parent, s, sTime, na);
441 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
442 writeGroupsTimetableDaysVerticalHtml(parent, s, sTime, na);
443 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
444 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
445 writeGroupsTimetableTimeHorizontalHtml(parent, s, sTime, na);
446 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
447 writeGroupsTimetableTimeVerticalHtml(parent, s, sTime, na);
448 } else {
449 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
450 writeGroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
451 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
452 writeGroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
453 }
454 //years
455 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
456 writeYearsTimetableDaysHorizontalHtml(parent, s, sTime, na);
457 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
458 writeYearsTimetableDaysVerticalHtml(parent, s, sTime, na);
459 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
460 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
461 writeYearsTimetableTimeHorizontalHtml(parent, s, sTime, na);
462 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
463 writeYearsTimetableTimeVerticalHtml(parent, s, sTime, na);
464 } else {
465 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
466 writeYearsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
467 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
468 writeYearsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
469 }
470 //teachers
471 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
472 writeTeachersTimetableDaysHorizontalHtml(parent, s, sTime, na);
473 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
474 writeTeachersTimetableDaysVerticalHtml(parent, s, sTime, na);
475 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
476 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
477 writeTeachersTimetableTimeHorizontalHtml(parent, s, sTime, na);
478 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
479 writeTeachersTimetableTimeVerticalHtml(parent, s, sTime, na);
480 } else {
481 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
482 writeTeachersTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
483 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
484 writeTeachersTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
485 }
486 //rooms
487 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
488 writeRoomsTimetableDaysHorizontalHtml(parent, s, sTime, na);
489 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
490 writeRoomsTimetableDaysVerticalHtml(parent, s, sTime, na);
491 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
492 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
493 writeRoomsTimetableTimeHorizontalHtml(parent, s, sTime, na);
494 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
495 writeRoomsTimetableTimeVerticalHtml(parent, s, sTime, na);
496 } else {
497 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
498 writeRoomsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
499 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
500 writeRoomsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
501 }
502 //subjects
503 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
504 writeSubjectsTimetableDaysHorizontalHtml(parent, s, sTime, na);
505 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
506 writeSubjectsTimetableDaysVerticalHtml(parent, s, sTime, na);
507 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
508 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
509 writeSubjectsTimetableTimeHorizontalHtml(parent, s, sTime, na);
510 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
511 writeSubjectsTimetableTimeVerticalHtml(parent, s, sTime, na);
512 } else {
513 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
514 writeSubjectsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
515 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
516 writeSubjectsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
517 }
518 //activty_tags
519 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
520 writeActivityTagsTimetableDaysHorizontalHtml(parent, s, sTime, na);
521 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
522 writeActivityTagsTimetableDaysVerticalHtml(parent, s, sTime, na);
523 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
524 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
525 writeActivityTagsTimetableTimeHorizontalHtml(parent, s, sTime, na);
526 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
527 writeActivityTagsTimetableTimeVerticalHtml(parent, s, sTime, na);
528 } else {
529 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
530 writeActivityTagsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
531 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
532 writeActivityTagsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
533 }
534 //all activities
535 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
536 writeAllActivitiesTimetableDaysHorizontalHtml(parent, s, sTime, na);
537 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
538 writeAllActivitiesTimetableDaysVerticalHtml(parent, s, sTime, na);
539 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
540 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
541 writeAllActivitiesTimetableTimeHorizontalHtml(parent, s, sTime, na);
542 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
543 writeAllActivitiesTimetableTimeVerticalHtml(parent, s, sTime, na);
544 } else {
545 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
546 writeAllActivitiesTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
547 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
548 writeAllActivitiesTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
549 }
550 //teachers free periods
551 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
552 writeTeachersFreePeriodsTimetableDaysHorizontalHtml(parent, s, sTime, na);
553 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
554 writeTeachersFreePeriodsTimetableDaysVerticalHtml(parent, s, sTime, na);
555 //statistics
556 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_STATISTICS_FILENAME_HTML;
557 writeTeachersStatisticsHtml(parent, s, sTime, na);
558 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+STUDENTS_STATISTICS_FILENAME_HTML;
559 writeStudentsStatisticsHtml(parent, s, sTime, na);
560
561 /*
562 //needed for printing from the interface, so don't clear them!
563 hashSubjectIDsTimetable.clear();
564 hashActivityTagIDsTimetable.clear();
565 hashStudentIDsTimetable.clear();
566 hashTeacherIDsTimetable.clear();
567 hashRoomIDsTimetable.clear();
568 hashDayIDsTimetable.clear();
569 hashActivityColorBySubject.clear();
570 hashActivityColorBySubjectAndStudents.clear();
571 activeHashActivityColorBySubject.clear();
572 activeHashActivityColorBySubjectAndStudents.clear();
573 */
574 if(VERBOSE){
575 cout<<"Writing simulation results to disk completed successfully"<<endl;
576 }
577 }
578
writeHighestStageResults(QWidget * parent)579 void TimetableExport::writeHighestStageResults(QWidget* parent){
580 QList<int> subgroupsSortedOrder;
581 QList<StudentsSubgroup*> lst;
582 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
583 lst.append(gt.rules.internalSubgroupsList[subgroup]);
584 if(TIMETABLES_SUBGROUPS_SORTED)
585 std::stable_sort(lst.begin(), lst.end(), subgroupsAscending);
586 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
587 subgroupsSortedOrder.append(lst.at(subgroup)->indexInInternalSubgroupsList);
588 QDir dir;
589
590 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
591
592 OUTPUT_DIR_TIMETABLES.append(FILE_SEP);
593 if(INPUT_FILENAME_XML=="")
594 OUTPUT_DIR_TIMETABLES.append("unnamed");
595 else{
596 OUTPUT_DIR_TIMETABLES.append(INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1));
597 if(OUTPUT_DIR_TIMETABLES.right(4)==".fet")
598 OUTPUT_DIR_TIMETABLES=OUTPUT_DIR_TIMETABLES.left(OUTPUT_DIR_TIMETABLES.length()-4);
599 //else if(INPUT_FILENAME_XML!="")
600 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
601 }
602 OUTPUT_DIR_TIMETABLES.append("-highest");
603
604 //make sure that the output directory exists
605 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
606 dir.mkpath(OUTPUT_DIR_TIMETABLES);
607
608 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
609 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
610 assert(TIMETABLE_HTML_LEVEL>=0);
611 assert(TIMETABLE_HTML_LEVEL<=7);
612
613 computeHashForIDsTimetable();
614 computeActivitiesAtTime();
615 computeActivitiesWithSameStartingTime();
616
617 QString s;
618 QString bar;
619 if(INPUT_FILENAME_XML=="")
620 bar="";
621 else
622 bar="_";
623 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
624 if(s2.right(4)==".fet")
625 s2=s2.left(s2.length()-4);
626 //else if(INPUT_FILENAME_XML!="")
627 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
628
629 //now write the solution in xml files
630 //subgroups
631 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_FILENAME_XML;
632 writeSubgroupsTimetableXml(parent, s, subgroupsSortedOrder);
633 //teachers
634 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_FILENAME_XML;
635 writeTeachersTimetableXml(parent, s);
636 //activities
637 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITIES_TIMETABLE_FILENAME_XML;
638 writeActivitiesTimetableXml(parent, s);
639
640 //now get the time. TODO: maybe write it in xml too? so do it a few lines earlier!
641 QDate dat=QDate::currentDate();
642 QTime tim=QTime::currentTime();
643 QLocale loc(FET_LANGUAGE);
644 QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
645 generationLocalizedTime=sTime;
646
647 //now get the number of placed activities. TODO: maybe write it in xml too? so do it a few lines earlier!
648 int na=0;
649 int na2=0;
650 getNumberOfPlacedActivities(na, na2);
651
652 if(na==gt.rules.nInternalActivities && na==na2){
653 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+MULTIPLE_TIMETABLE_DATA_RESULTS_FILE;
654 if(VERBOSE){
655 cout<<"Since the simulation is complete, FET will write also the timetable data file"<<endl;
656 }
657 writeTimetableDataFile(parent, s);
658 }
659
660 //write the conflicts in txt mode
661 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+CONFLICTS_FILENAME;
662 writeConflictsTxt(parent, s, sTime, na);
663
664 //now write the solution in html files
665 if(TIMETABLE_HTML_LEVEL>=1){
666 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+STYLESHEET_CSS;
667 writeStylesheetCss(parent, s, sTime, na);
668 }
669
670 //indexHtml
671 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+INDEX_HTML;
672 writeIndexHtml(parent, s, sTime, na);
673
674 //subgroups
675 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
676 writeSubgroupsTimetableDaysHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
677 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
678 writeSubgroupsTimetableDaysVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
679 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
680 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
681 writeSubgroupsTimetableTimeHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
682 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
683 writeSubgroupsTimetableTimeVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
684 } else {
685 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
686 writeSubgroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
687 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
688 writeSubgroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
689 }
690 //groups
691 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
692 writeGroupsTimetableDaysHorizontalHtml(parent, s, sTime, na);
693 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
694 writeGroupsTimetableDaysVerticalHtml(parent, s, sTime, na);
695 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
696 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
697 writeGroupsTimetableTimeHorizontalHtml(parent, s, sTime, na);
698 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
699 writeGroupsTimetableTimeVerticalHtml(parent, s, sTime, na);
700 } else {
701 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
702 writeGroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
703 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
704 writeGroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
705 }
706 //years
707 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
708 writeYearsTimetableDaysHorizontalHtml(parent, s, sTime, na);
709 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
710 writeYearsTimetableDaysVerticalHtml(parent, s, sTime, na);
711 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
712 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
713 writeYearsTimetableTimeHorizontalHtml(parent, s, sTime, na);
714 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
715 writeYearsTimetableTimeVerticalHtml(parent, s, sTime, na);
716 } else {
717 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
718 writeYearsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
719 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
720 writeYearsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
721 }
722 //teachers
723 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
724 writeTeachersTimetableDaysHorizontalHtml(parent, s, sTime, na);
725 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
726 writeTeachersTimetableDaysVerticalHtml(parent, s, sTime, na);
727 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
728 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
729 writeTeachersTimetableTimeHorizontalHtml(parent, s, sTime, na);
730 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
731 writeTeachersTimetableTimeVerticalHtml(parent, s, sTime, na);
732 } else {
733 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
734 writeTeachersTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
735 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
736 writeTeachersTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
737 }
738 //rooms
739 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
740 writeRoomsTimetableDaysHorizontalHtml(parent, s, sTime, na);
741 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
742 writeRoomsTimetableDaysVerticalHtml(parent, s, sTime, na);
743 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
744 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
745 writeRoomsTimetableTimeHorizontalHtml(parent, s, sTime, na);
746 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
747 writeRoomsTimetableTimeVerticalHtml(parent, s, sTime, na);
748 } else {
749 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
750 writeRoomsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
751 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
752 writeRoomsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
753 }
754 //subjects
755 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
756 writeSubjectsTimetableDaysHorizontalHtml(parent, s, sTime, na);
757 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
758 writeSubjectsTimetableDaysVerticalHtml(parent, s, sTime, na);
759 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
760 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
761 writeSubjectsTimetableTimeHorizontalHtml(parent, s, sTime, na);
762 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
763 writeSubjectsTimetableTimeVerticalHtml(parent, s, sTime, na);
764 } else {
765 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
766 writeSubjectsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
767 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
768 writeSubjectsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
769 }
770 //activity_tags
771 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
772 writeActivityTagsTimetableDaysHorizontalHtml(parent, s, sTime, na);
773 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
774 writeActivityTagsTimetableDaysVerticalHtml(parent, s, sTime, na);
775 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
776 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
777 writeActivityTagsTimetableTimeHorizontalHtml(parent, s, sTime, na);
778 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
779 writeActivityTagsTimetableTimeVerticalHtml(parent, s, sTime, na);
780 } else {
781 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
782 writeActivityTagsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
783 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
784 writeActivityTagsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
785 }
786 //all activities
787 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
788 writeAllActivitiesTimetableDaysHorizontalHtml(parent, s, sTime, na);
789 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
790 writeAllActivitiesTimetableDaysVerticalHtml(parent, s, sTime, na);
791 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
792 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
793 writeAllActivitiesTimetableTimeHorizontalHtml(parent, s, sTime, na);
794 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
795 writeAllActivitiesTimetableTimeVerticalHtml(parent, s, sTime, na);
796 } else {
797 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
798 writeAllActivitiesTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
799 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
800 writeAllActivitiesTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
801 }
802 //teachers free periods
803 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
804 writeTeachersFreePeriodsTimetableDaysHorizontalHtml(parent, s, sTime, na);
805 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
806 writeTeachersFreePeriodsTimetableDaysVerticalHtml(parent, s, sTime, na);
807 //statistics
808 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+TEACHERS_STATISTICS_FILENAME_HTML;
809 writeTeachersStatisticsHtml(parent, s, sTime, na);
810 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+STUDENTS_STATISTICS_FILENAME_HTML;
811 writeStudentsStatisticsHtml(parent, s, sTime, na);
812
813 //needed for printing from the interface, so don't clear them!
814 /* hashSubjectIDsTimetable.clear();
815 hashActivityTagIDsTimetable.clear();
816 hashStudentIDsTimetable.clear();
817 hashTeacherIDsTimetable.clear();
818 hashRoomIDsTimetable.clear();
819 hashDayIDsTimetable.clear();
820 hashActivityColorBySubject.clear();
821 hashActivityColorBySubjectAndStudents.clear();
822 activeHashActivityColorBySubject.clear();
823 activeHashActivityColorBySubjectAndStudents.clear();
824 */
825 if(VERBOSE){
826 cout<<"Writing highest stage results to disk completed successfully"<<endl;
827 }
828 }
829
writeRandomSeed(QWidget * parent,const MRG32k3a & rng,bool before)830 void TimetableExport::writeRandomSeed(QWidget* parent, const MRG32k3a& rng, bool before)
831 {
832 QString RANDOM_SEED_FILENAME;
833 if(before)
834 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_BEFORE;
835 else
836 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_AFTER;
837
838 QDir dir;
839
840 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
841
842 OUTPUT_DIR_TIMETABLES.append(FILE_SEP);
843 if(INPUT_FILENAME_XML=="")
844 OUTPUT_DIR_TIMETABLES.append("unnamed");
845 else{
846 OUTPUT_DIR_TIMETABLES.append(INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1));
847 if(OUTPUT_DIR_TIMETABLES.right(4)==".fet")
848 OUTPUT_DIR_TIMETABLES=OUTPUT_DIR_TIMETABLES.left(OUTPUT_DIR_TIMETABLES.length()-4);
849 //else if(INPUT_FILENAME_XML!="")
850 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
851 }
852 OUTPUT_DIR_TIMETABLES.append("-single");
853
854 //make sure that the output directory exists
855 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
856 dir.mkpath(OUTPUT_DIR_TIMETABLES);
857
858 QString s;
859 QString bar;
860 if(INPUT_FILENAME_XML=="")
861 bar="";
862 else
863 bar="_";
864 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
865 if(s2.right(4)==".fet")
866 s2=s2.left(s2.length()-4);
867
868 s=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+bar+RANDOM_SEED_FILENAME;
869
870 writeRandomSeedFile(parent, rng, s, before);
871 }
872
writeRandomSeedFile(QWidget * parent,const MRG32k3a & rng,const QString & filename,bool before)873 void TimetableExport::writeRandomSeedFile(QWidget* parent, const MRG32k3a& rng, const QString& filename, bool before)
874 {
875 QString s=filename;
876
877 QFile file(s);
878 if(!file.open(QIODevice::WriteOnly)){
879 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
880 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(s));
881 return;
882 }
883 QTextStream tos(&file);
884 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
885 tos.setEncoding(QStringConverter::Utf8);
886 #else
887 tos.setCodec("UTF-8");
888 #endif
889 tos.setGenerateByteOrderMark(true);
890
891 QDate dat=QDate::currentDate();
892 QTime tim=QTime::currentTime();
893 QLocale loc(FET_LANGUAGE);
894 QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
895
896 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
897 if(before){
898 tos<<tr("Generation started on: %1", "%1 is the time").arg(sTime);
899 tos<<Qt::endl<<Qt::endl;
900 tos<<tr("The random seed at the start of generation is:", "The random seed has 6 components, to follow on the next 2 lines (3 values on each line).");
901 tos<<Qt::endl;
902 tos<<QString("\ts10=%1, s11=%2, s12=%3,").arg(rng.s10).arg(rng.s11).arg(rng.s12);
903 tos<<Qt::endl;
904 tos<<QString("\ts20=%1, s21=%2, s22=%3.").arg(rng.s20).arg(rng.s21).arg(rng.s22);
905 tos<<Qt::endl<<Qt::endl;
906 tos<<tr("This file was automatically generated by FET %1.").arg(FET_VERSION);
907 tos<<Qt::endl;
908 }
909 else{
910 tos<<tr("Generation ended on: %1", "%1 is the time").arg(sTime);
911 tos<<Qt::endl<<Qt::endl;
912 tos<<tr("The random seed at the end of generation is:", "The random seed has 6 components, to follow on the next 2 lines (3 values on each line).");
913 tos<<Qt::endl;
914 tos<<QString("\ts10=%1, s11=%2, s12=%3,").arg(rng.s10).arg(rng.s11).arg(rng.s12);
915 tos<<Qt::endl;
916 tos<<QString("\ts20=%1, s21=%2, s22=%3.").arg(rng.s20).arg(rng.s21).arg(rng.s22);
917 tos<<Qt::endl<<Qt::endl;
918 tos<<tr("This file was automatically generated by FET %1.").arg(FET_VERSION);
919 tos<<Qt::endl;
920 }
921 #else
922 if(before){
923 tos<<tr("Generation started on: %1", "%1 is the time").arg(sTime);
924 tos<<endl<<endl;
925 tos<<tr("The random seed at the start of generation is:", "The random seed has 6 components, to follow on the next 2 lines (3 values on each line).");
926 tos<<endl;
927 tos<<QString("\ts10=%1, s11=%2, s12=%3,").arg(rng.s10).arg(rng.s11).arg(rng.s12);
928 tos<<endl;
929 tos<<QString("\ts20=%1, s21=%2, s22=%3.").arg(rng.s20).arg(rng.s21).arg(rng.s22);
930 tos<<endl<<endl;
931 tos<<tr("This file was automatically generated by FET %1.").arg(FET_VERSION);
932 tos<<endl;
933 }
934 else{
935 tos<<tr("Generation ended on: %1", "%1 is the time").arg(sTime);
936 tos<<endl<<endl;
937 tos<<tr("The random seed at the end of generation is:", "The random seed has 6 components, to follow on the next 2 lines (3 values on each line).");
938 tos<<endl;
939 tos<<QString("\ts10=%1, s11=%2, s12=%3,").arg(rng.s10).arg(rng.s11).arg(rng.s12);
940 tos<<endl;
941 tos<<QString("\ts20=%1, s21=%2, s22=%3.").arg(rng.s20).arg(rng.s21).arg(rng.s22);
942 tos<<endl<<endl;
943 tos<<tr("This file was automatically generated by FET %1.").arg(FET_VERSION);
944 tos<<endl;
945 }
946 #endif
947
948 if(file.error()>0){
949 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
950 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(s).arg(file.error()));
951 }
952 file.close();
953 }
954
writeTimetableDataFile(QWidget * parent,const QString & filename)955 void TimetableExport::writeTimetableDataFile(QWidget* parent, const QString& filename){
956 if(!students_schedule_ready || !teachers_schedule_ready || !rooms_schedule_ready){
957 IrreconcilableCriticalMessage::critical(parent, tr("FET - Critical"), tr("Timetable not generated - cannot save it - this should not happen (please report bug)"));
958 return;
959 }
960
961 Solution* tc=&best_solution;
962
963 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
964 //Activity* act=>.rules.internalActivitiesList[ai];
965 int time=tc->times[ai];
966 if(time==UNALLOCATED_TIME){
967 IrreconcilableCriticalMessage::critical(parent, tr("FET - Critical"), tr("Incomplete timetable - this should not happen - please report bug"));
968 return;
969 }
970
971 int ri=tc->rooms[ai];
972 if(ri==UNALLOCATED_SPACE){
973 IrreconcilableCriticalMessage::critical(parent, tr("FET - Critical"), tr("Incomplete timetable - this should not happen - please report bug"));
974 return;
975 }
976 }
977
978 rules2.initialized=true;
979
980 rules2.mode=gt.rules.mode;
981
982 rules2.institutionName=gt.rules.institutionName;
983 rules2.comments=gt.rules.comments;
984
985 rules2.nTerms=gt.rules.nTerms;
986 rules2.nDaysPerTerm=gt.rules.nDaysPerTerm;
987
988 rules2.nHoursPerDay=gt.rules.nHoursPerDay;
989 rules2.hoursOfTheDay=gt.rules.hoursOfTheDay;
990 //for(int i=0; i<gt.rules.nHoursPerDay; i++)
991 // rules2.hoursOfTheDay[i]=gt.rules.hoursOfTheDay[i];
992
993 rules2.nDaysPerWeek=gt.rules.nDaysPerWeek;
994 rules2.daysOfTheWeek=gt.rules.daysOfTheWeek;
995 //for(int i=0; i<gt.rules.nDaysPerWeek; i++)
996 // rules2.daysOfTheWeek[i]=gt.rules.daysOfTheWeek[i];
997
998 rules2.yearsList=gt.rules.yearsList;
999
1000 rules2.teachersList=gt.rules.teachersList;
1001
1002 rules2.subjectsList=gt.rules.subjectsList;
1003
1004 rules2.activityTagsList=gt.rules.activityTagsList;
1005
1006 rules2.activitiesList=gt.rules.activitiesList;
1007
1008 rules2.buildingsList=gt.rules.buildingsList;
1009
1010 rules2.roomsList=gt.rules.roomsList;
1011
1012 rules2.timeConstraintsList=gt.rules.timeConstraintsList;
1013
1014 rules2.spaceConstraintsList=gt.rules.spaceConstraintsList;
1015
1016 rules2.apstHash=gt.rules.apstHash;
1017 rules2.aprHash=gt.rules.aprHash;
1018
1019 rules2.groupActivitiesInInitialOrderList=gt.rules.groupActivitiesInInitialOrderList;
1020
1021 //add locking constraints
1022 TimeConstraintsList lockTimeConstraintsList;
1023 SpaceConstraintsList lockSpaceConstraintsList;
1024
1025 //bool report=false;
1026
1027 int addedTime=0, duplicatesTime=0;
1028 int addedSpace=0, duplicatesSpace=0;
1029
1030 //lock selected activities
1031 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
1032 Activity* act=>.rules.internalActivitiesList[ai];
1033 int time=tc->times[ai];
1034 if(time>=0 && time<gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay){
1035 int hour=time/gt.rules.nDaysPerWeek;
1036 int day=time%gt.rules.nDaysPerWeek;
1037
1038 ConstraintActivityPreferredStartingTime* ctr=new ConstraintActivityPreferredStartingTime(100.0, act->id, day, hour, false); //permanently locked is false
1039 bool t=rules2.addTimeConstraint(ctr);
1040
1041 if(t){
1042 addedTime++;
1043 lockTimeConstraintsList.append(ctr);
1044 }
1045 else
1046 duplicatesTime++;
1047
1048 QString s;
1049
1050 if(t)
1051 s=tr("Added the following constraint to saved file:")+"\n"+ctr->getDetailedDescription(gt.rules);
1052 else{
1053 s=tr("Constraint\n%1 NOT added to saved file - duplicate").arg(ctr->getDetailedDescription(gt.rules));
1054 delete ctr;
1055 }
1056
1057 /*if(report){
1058 int k;
1059 if(t)
1060 k=TimetableExportMessage::information(parent, tr("FET information"), s,
1061 tr("Skip information"), tr("See next"), QString(), 1, 0 );
1062 else
1063 k=TimetableExportMessage::warning(parent, tr("FET warning"), s,
1064 tr("Skip information"), tr("See next"), QString(), 1, 0 );
1065 if(k==0)
1066 report=false;
1067 }*/
1068 }
1069
1070 int ri=tc->rooms[ai];
1071 if(ri!=UNALLOCATED_SPACE && ri!=UNSPECIFIED_ROOM && ri>=0 && ri<gt.rules.nInternalRooms){
1072 QStringList tl;
1073 if(gt.rules.internalRoomsList[ri]->isVirtual==false)
1074 assert(tc->realRoomsList[ai].isEmpty());
1075 else
1076 for(int rr : qAsConst(tc->realRoomsList[ai]))
1077 tl.append(gt.rules.internalRoomsList[rr]->name);
1078
1079 ConstraintActivityPreferredRoom* ctr=new ConstraintActivityPreferredRoom(100, act->id, (gt.rules.internalRoomsList[ri])->name, tl, false); //permanently locked is false
1080 bool t=rules2.addSpaceConstraint(ctr);
1081
1082 QString s;
1083
1084 if(t){
1085 addedSpace++;
1086 lockSpaceConstraintsList.append(ctr);
1087 }
1088 else
1089 duplicatesSpace++;
1090
1091 if(t)
1092 s=tr("Added the following constraint to saved file:")+"\n"+ctr->getDetailedDescription(gt.rules);
1093 else{
1094 s=tr("Constraint\n%1 NOT added to saved file - duplicate").arg(ctr->getDetailedDescription(gt.rules));
1095 delete ctr;
1096 }
1097
1098 /*if(report){
1099 int k;
1100 if(t)
1101 k=TimetableExportMessage::information(parent, tr("FET information"), s,
1102 tr("Skip information"), tr("See next"), QString(), 1, 0 );
1103 else
1104 k=TimetableExportMessage::warning(parent, tr("FET warning"), s,
1105 tr("Skip information"), tr("See next"), QString(), 1, 0 );
1106 if(k==0)
1107 report=false;
1108 }*/
1109 }
1110 }
1111
1112 //QMessageBox::information(parent, tr("FET information"), tr("Added %1 locking time constraints and %2 locking space constraints to saved file,"
1113 // " ignored %3 activities which were already fixed in time and %4 activities which were already fixed in space").arg(addedTime).arg(addedSpace).arg(duplicatesTime).arg(duplicatesSpace));
1114
1115 bool result=rules2.write(parent, filename);
1116
1117 for(TimeConstraint* tc : qAsConst(lockTimeConstraintsList))
1118 delete tc;
1119 lockTimeConstraintsList.clear();
1120 for(SpaceConstraint* sc : qAsConst(lockSpaceConstraintsList))
1121 delete sc;
1122 lockSpaceConstraintsList.clear();
1123 //while(!lockTimeConstraintsList.isEmpty())
1124 // delete lockTimeConstraintsList.takeFirst();
1125 //while(!lockSpaceConstraintsList.isEmpty())
1126 // delete lockSpaceConstraintsList.takeFirst();
1127
1128 //if(result)
1129 // QMessageBox::information(parent, tr("FET information"),
1130 // tr("File saved successfully. You can see it on the hard disk. Current data file remained untouched (of locking constraints),"
1131 // " so you can save it also, or generate different timetables."));
1132
1133 rules2.nHoursPerDay=0;
1134 rules2.hoursOfTheDay.clear();
1135 rules2.nDaysPerWeek=0;
1136 rules2.daysOfTheWeek.clear();
1137
1138 rules2.yearsList.clear();
1139
1140 rules2.teachersList.clear();
1141
1142 rules2.subjectsList.clear();
1143
1144 rules2.activityTagsList.clear();
1145
1146 rules2.activitiesList.clear();
1147
1148 rules2.buildingsList.clear();
1149
1150 rules2.roomsList.clear();
1151
1152 rules2.timeConstraintsList.clear();
1153
1154 rules2.spaceConstraintsList.clear();
1155
1156 rules2.apstHash.clear();
1157 rules2.aprHash.clear();
1158
1159 rules2.groupActivitiesInInitialOrderList.clear();
1160
1161 if(!result){
1162 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"), tr("Could not save the data + timetable file on the hard disk - maybe hard disk is full"));
1163 }
1164 }
1165
writeSimulationResults(QWidget * parent,int n,bool highest)1166 void TimetableExport::writeSimulationResults(QWidget* parent, int n, bool highest){
1167 QList<int> subgroupsSortedOrder;
1168 QList<StudentsSubgroup*> lst;
1169 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
1170 lst.append(gt.rules.internalSubgroupsList[subgroup]);
1171 if(TIMETABLES_SUBGROUPS_SORTED)
1172 std::stable_sort(lst.begin(), lst.end(), subgroupsAscending);
1173 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
1174 subgroupsSortedOrder.append(lst.at(subgroup)->indexInInternalSubgroupsList);
1175 QDir dir;
1176
1177 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
1178
1179 //make sure that the output directory exists
1180 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
1181 dir.mkpath(OUTPUT_DIR_TIMETABLES);
1182
1183 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
1184 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
1185 assert(TIMETABLE_HTML_LEVEL>=0);
1186 assert(TIMETABLE_HTML_LEVEL<=7);
1187
1188 computeHashForIDsTimetable();
1189 computeActivitiesAtTime();
1190 computeActivitiesWithSameStartingTime();
1191
1192 QString s;
1193 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1194 if(s2.right(4)==".fet")
1195 s2=s2.left(s2.length()-4);
1196 //else if(INPUT_FILENAME_XML!="")
1197 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1198
1199 QString destDir=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+"-multi";
1200
1201 if(!dir.exists(destDir))
1202 dir.mkpath(destDir);
1203
1204 QString finalDestDir=destDir+FILE_SEP+CustomFETString::number(n);
1205
1206 if(highest)
1207 finalDestDir+=QString("-highest");
1208
1209 if(!dir.exists(finalDestDir))
1210 dir.mkpath(finalDestDir);
1211
1212 finalDestDir+=FILE_SEP;
1213
1214 QString s3=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1215
1216 if(s3.right(4)==".fet")
1217 s3=s3.left(s3.length()-4);
1218 //else if(INPUT_FILENAME_XML!="")
1219 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1220
1221 finalDestDir+=s3+"_";
1222
1223 //write data+timetable in .fet format
1224 if(!highest)
1225 writeTimetableDataFile(parent, finalDestDir+MULTIPLE_TIMETABLE_DATA_RESULTS_FILE);
1226
1227 //now write the solution in xml files
1228 //subgroups
1229 s=finalDestDir+SUBGROUPS_TIMETABLE_FILENAME_XML;
1230 writeSubgroupsTimetableXml(parent, s, subgroupsSortedOrder);
1231 //teachers
1232 s=finalDestDir+TEACHERS_TIMETABLE_FILENAME_XML;
1233 writeTeachersTimetableXml(parent, s);
1234 //activities
1235 s=finalDestDir+ACTIVITIES_TIMETABLE_FILENAME_XML;
1236 writeActivitiesTimetableXml(parent, s);
1237
1238 //now get the time. TODO: maybe write it in xml too? so do it a few lines earlier!
1239 QDate dat=QDate::currentDate();
1240 QTime tim=QTime::currentTime();
1241 QLocale loc(FET_LANGUAGE);
1242 QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
1243 generationLocalizedTime=sTime;
1244
1245 //now get the number of placed activities. TODO: maybe write it in xml too? so do it a few lines earlier!
1246 int na=0;
1247 int na2=0;
1248 getNumberOfPlacedActivities(na, na2);
1249
1250 //write the conflicts in txt mode
1251 s=finalDestDir+CONFLICTS_FILENAME;
1252 writeConflictsTxt(parent, s, sTime, na);
1253
1254 //now write the solution in html files
1255 if(TIMETABLE_HTML_LEVEL>=1){
1256 s=finalDestDir+STYLESHEET_CSS;
1257 writeStylesheetCss(parent, s, sTime, na);
1258 }
1259 //indexHtml
1260 s=finalDestDir+INDEX_HTML;
1261 writeIndexHtml(parent, s, sTime, na);
1262 //subgroups
1263 s=finalDestDir+SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1264 writeSubgroupsTimetableDaysHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1265 s=finalDestDir+SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1266 writeSubgroupsTimetableDaysVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1267 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1268 s=finalDestDir+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1269 writeSubgroupsTimetableTimeHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1270 s=finalDestDir+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1271 writeSubgroupsTimetableTimeVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1272 } else {
1273 s=finalDestDir+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1274 writeSubgroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
1275 s=finalDestDir+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1276 writeSubgroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
1277 }
1278 //groups
1279 s=finalDestDir+GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1280 writeGroupsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1281 s=finalDestDir+GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1282 writeGroupsTimetableDaysVerticalHtml(parent, s, sTime, na);
1283 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1284 s=finalDestDir+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1285 writeGroupsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1286 s=finalDestDir+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1287 writeGroupsTimetableTimeVerticalHtml(parent, s, sTime, na);
1288 } else {
1289 s=finalDestDir+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1290 writeGroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1291 s=finalDestDir+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1292 writeGroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1293 }
1294 //years
1295 s=finalDestDir+YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1296 writeYearsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1297 s=finalDestDir+YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1298 writeYearsTimetableDaysVerticalHtml(parent, s, sTime, na);
1299 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1300 s=finalDestDir+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1301 writeYearsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1302 s=finalDestDir+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1303 writeYearsTimetableTimeVerticalHtml(parent, s, sTime, na);
1304 } else {
1305 s=finalDestDir+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1306 writeYearsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1307 s=finalDestDir+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1308 writeYearsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1309 }
1310 //teachers
1311 s=finalDestDir+TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1312 writeTeachersTimetableDaysHorizontalHtml(parent, s, sTime, na);
1313 s=finalDestDir+TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1314 writeTeachersTimetableDaysVerticalHtml(parent, s, sTime, na);
1315 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1316 s=finalDestDir+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1317 writeTeachersTimetableTimeHorizontalHtml(parent, s, sTime, na);
1318 s=finalDestDir+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1319 writeTeachersTimetableTimeVerticalHtml(parent, s, sTime, na);
1320 } else {
1321 s=finalDestDir+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1322 writeTeachersTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1323 s=finalDestDir+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1324 writeTeachersTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1325 }
1326 //rooms
1327 s=finalDestDir+ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1328 writeRoomsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1329 s=finalDestDir+ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1330 writeRoomsTimetableDaysVerticalHtml(parent, s, sTime, na);
1331 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1332 s=finalDestDir+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1333 writeRoomsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1334 s=finalDestDir+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1335 writeRoomsTimetableTimeVerticalHtml(parent, s, sTime, na);
1336 } else {
1337 s=finalDestDir+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1338 writeRoomsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1339 s=finalDestDir+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1340 writeRoomsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1341 }
1342 //subjects
1343 s=finalDestDir+SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1344 writeSubjectsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1345 s=finalDestDir+SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1346 writeSubjectsTimetableDaysVerticalHtml(parent, s, sTime, na);
1347 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1348 s=finalDestDir+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1349 writeSubjectsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1350 s=finalDestDir+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1351 writeSubjectsTimetableTimeVerticalHtml(parent, s, sTime, na);
1352 } else {
1353 s=finalDestDir+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1354 writeSubjectsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1355 s=finalDestDir+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1356 writeSubjectsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1357 }
1358 //activity_tags
1359 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1360 writeActivityTagsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1361 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1362 writeActivityTagsTimetableDaysVerticalHtml(parent, s, sTime, na);
1363 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1364 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1365 writeActivityTagsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1366 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1367 writeActivityTagsTimetableTimeVerticalHtml(parent, s, sTime, na);
1368 } else {
1369 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1370 writeActivityTagsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1371 s=finalDestDir+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1372 writeActivityTagsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1373 }
1374 //all activities
1375 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1376 writeAllActivitiesTimetableDaysHorizontalHtml(parent, s, sTime, na);
1377 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1378 writeAllActivitiesTimetableDaysVerticalHtml(parent, s, sTime, na);
1379 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1380 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1381 writeAllActivitiesTimetableTimeHorizontalHtml(parent, s, sTime, na);
1382 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1383 writeAllActivitiesTimetableTimeVerticalHtml(parent, s, sTime, na);
1384 } else {
1385 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1386 writeAllActivitiesTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1387 s=finalDestDir+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1388 writeAllActivitiesTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1389 }
1390 //teachers free periods
1391 s=finalDestDir+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1392 writeTeachersFreePeriodsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1393 s=finalDestDir+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1394 writeTeachersFreePeriodsTimetableDaysVerticalHtml(parent, s, sTime, na);
1395 //statistics
1396 s=finalDestDir+TEACHERS_STATISTICS_FILENAME_HTML;
1397 writeTeachersStatisticsHtml(parent, s, sTime, na);
1398 s=finalDestDir+STUDENTS_STATISTICS_FILENAME_HTML;
1399 writeStudentsStatisticsHtml(parent, s, sTime, na);
1400
1401 //needed for printing from the interface, so don't clear them!
1402 /* hashSubjectIDsTimetable.clear();
1403 hashActivityTagIDsTimetable.clear();
1404 hashStudentIDsTimetable.clear();
1405 hashTeacherIDsTimetable.clear();
1406 hashRoomIDsTimetable.clear();
1407 hashDayIDsTimetable.clear();
1408 hashActivityColorBySubject.clear();
1409 hashActivityColorBySubjectAndStudents.clear();
1410 activeHashActivityColorBySubject.clear();
1411 activeHashActivityColorBySubjectAndStudents.clear();
1412 */
1413 if(VERBOSE){
1414 cout<<"Writing multiple simulation results to disk completed successfully"<<endl;
1415 }
1416 }
1417
writeRandomSeed(QWidget * parent,const MRG32k3a & rng,int n,bool before)1418 void TimetableExport::writeRandomSeed(QWidget* parent, const MRG32k3a& rng, int n, bool before){
1419 QString RANDOM_SEED_FILENAME;
1420 if(before)
1421 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_BEFORE;
1422 else
1423 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_AFTER;
1424
1425 QDir dir;
1426
1427 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
1428
1429 //make sure that the output directory exists
1430 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
1431 dir.mkpath(OUTPUT_DIR_TIMETABLES);
1432
1433 QString s;
1434 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1435 if(s2.right(4)==".fet")
1436 s2=s2.left(s2.length()-4);
1437 //else if(INPUT_FILENAME_XML!="")
1438 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1439
1440 QString destDir=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+"-multi";
1441
1442 if(!dir.exists(destDir))
1443 dir.mkpath(destDir);
1444
1445 QString finalDestDir=destDir+FILE_SEP+CustomFETString::number(n);
1446
1447 if(!dir.exists(finalDestDir))
1448 dir.mkpath(finalDestDir);
1449
1450 finalDestDir+=FILE_SEP;
1451
1452 QString s3=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1453
1454 if(s3.right(4)==".fet")
1455 s3=s3.left(s3.length()-4);
1456 //else if(INPUT_FILENAME_XML!="")
1457 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1458
1459 finalDestDir+=s3+"_";
1460
1461 s=finalDestDir+RANDOM_SEED_FILENAME;
1462
1463 writeRandomSeedFile(parent, rng, s, before);
1464 }
1465
writeReportForMultiple(QWidget * parent,const QString & description,bool begin)1466 void TimetableExport::writeReportForMultiple(QWidget* parent, const QString& description, bool begin)
1467 {
1468 QDir dir;
1469
1470 QString OUTPUT_DIR_TIMETABLES=OUTPUT_DIR+FILE_SEP+"timetables";
1471
1472 //make sure that the output directory exists
1473 if(!dir.exists(OUTPUT_DIR_TIMETABLES))
1474 dir.mkpath(OUTPUT_DIR_TIMETABLES);
1475
1476 QString s;
1477 QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1478 if(s2.right(4)==".fet")
1479 s2=s2.left(s2.length()-4);
1480 //else if(INPUT_FILENAME_XML!="")
1481 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1482
1483 QString destDir=OUTPUT_DIR_TIMETABLES+FILE_SEP+s2+"-multi";
1484
1485 if(!dir.exists(destDir))
1486 dir.mkpath(destDir);
1487
1488 QString filename=destDir+FILE_SEP+QString("report.txt");
1489
1490 QFile file(filename);
1491 if(!file.open(QIODevice::Append)){
1492 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1493 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(filename));
1494 return;
1495 }
1496 QTextStream tos(&file);
1497 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
1498 tos.setEncoding(QStringConverter::Utf8);
1499 #else
1500 tos.setCodec("UTF-8");
1501 #endif
1502 if(begin){
1503 tos.setGenerateByteOrderMark(true);
1504 }
1505
1506 #if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
1507 tos<<description<<Qt::endl;
1508 #else
1509 tos<<description<<endl;
1510 #endif
1511
1512 if(file.error()>0){
1513 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1514 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(filename).arg(file.error()));
1515 }
1516 file.close();
1517 }
1518
writeSimulationResultsCommandLine(QWidget * parent,const QString & outputDirectory)1519 void TimetableExport::writeSimulationResultsCommandLine(QWidget* parent, const QString& outputDirectory){ //outputDirectory contains trailing FILE_SEP
1520 QList<int> subgroupsSortedOrder;
1521 QList<StudentsSubgroup*> lst;
1522 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
1523 lst.append(gt.rules.internalSubgroupsList[subgroup]);
1524 if(TIMETABLES_SUBGROUPS_SORTED)
1525 std::stable_sort(lst.begin(), lst.end(), subgroupsAscending);
1526 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++)
1527 subgroupsSortedOrder.append(lst.at(subgroup)->indexInInternalSubgroupsList);
1528 QString add=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1529 if(add.right(4)==".fet")
1530 add=add.left(add.length()-4);
1531 //else if(INPUT_FILENAME_XML!="")
1532 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1533
1534 if(add!="")
1535 add.append("_");
1536
1537 /////////
1538
1539 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
1540 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
1541 assert(TIMETABLE_HTML_LEVEL>=0);
1542 assert(TIMETABLE_HTML_LEVEL<=7);
1543
1544 computeHashForIDsTimetable();
1545 computeActivitiesAtTime();
1546 computeActivitiesWithSameStartingTime();
1547
1548 TimetableExport::writeSubgroupsTimetableXml(parent, outputDirectory+add+SUBGROUPS_TIMETABLE_FILENAME_XML, subgroupsSortedOrder);
1549 TimetableExport::writeTeachersTimetableXml(parent, outputDirectory+add+TEACHERS_TIMETABLE_FILENAME_XML);
1550 TimetableExport::writeActivitiesTimetableXml(parent, outputDirectory+add+ACTIVITIES_TIMETABLE_FILENAME_XML);
1551
1552 //get the time
1553 QDate dat=QDate::currentDate();
1554 QTime tim=QTime::currentTime();
1555 QLocale loc(FET_LANGUAGE);
1556 QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
1557 generationLocalizedTime=sTime; //really unneeded, but just to be similar to the other parts
1558
1559 //now get the number of placed activities. TODO: maybe write it in xml too? so do it a few lines earlier!
1560 int na=0;
1561 int na2=0;
1562 getNumberOfPlacedActivities(na, na2);
1563
1564 if(na==gt.rules.nInternalActivities && na==na2){
1565 QString s=outputDirectory+add+MULTIPLE_TIMETABLE_DATA_RESULTS_FILE;
1566 if(VERBOSE){
1567 cout<<"Since the simulation is complete, FET will write also the timetable data file"<<endl;
1568 }
1569 writeTimetableDataFile(parent, s);
1570 }
1571
1572 //write the conflicts in txt mode
1573 QString s=add+CONFLICTS_FILENAME;
1574 s.prepend(outputDirectory);
1575 TimetableExport::writeConflictsTxt(parent, s, sTime, na);
1576
1577 //now write the solution in html files
1578 if(TIMETABLE_HTML_LEVEL>=1){
1579 s=add+STYLESHEET_CSS;
1580 s.prepend(outputDirectory);
1581 TimetableExport::writeStylesheetCss(parent, s, sTime, na);
1582 }
1583 //indexHtml
1584 s=add+INDEX_HTML;
1585 s.prepend(outputDirectory);
1586 writeIndexHtml(parent, s, sTime, na);
1587 //subgroups
1588 s=add+SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1589 s.prepend(outputDirectory);
1590 TimetableExport::writeSubgroupsTimetableDaysHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1591 s=add+SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1592 s.prepend(outputDirectory);
1593 TimetableExport::writeSubgroupsTimetableDaysVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1594 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1595 s=add+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1596 s.prepend(outputDirectory);
1597 TimetableExport::writeSubgroupsTimetableTimeHorizontalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1598 s=add+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1599 s.prepend(outputDirectory);
1600 TimetableExport::writeSubgroupsTimetableTimeVerticalHtml(parent, s, sTime, na, subgroupsSortedOrder);
1601 } else {
1602 s=add+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1603 s.prepend(outputDirectory);
1604 TimetableExport::writeSubgroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
1605 s=add+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1606 s.prepend(outputDirectory);
1607 TimetableExport::writeSubgroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na, subgroupsSortedOrder);
1608 }
1609 //groups
1610 s=add+GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1611 s.prepend(outputDirectory);
1612 TimetableExport::writeGroupsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1613 s=add+GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1614 s.prepend(outputDirectory);
1615 TimetableExport::writeGroupsTimetableDaysVerticalHtml(parent, s, sTime, na);
1616 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1617 s=add+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1618 s.prepend(outputDirectory);
1619 TimetableExport::writeGroupsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1620 s=add+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1621 s.prepend(outputDirectory);
1622 TimetableExport::writeGroupsTimetableTimeVerticalHtml(parent, s, sTime, na);
1623 } else {
1624 s=add+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1625 s.prepend(outputDirectory);
1626 TimetableExport::writeGroupsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1627 s=add+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1628 s.prepend(outputDirectory);
1629 TimetableExport::writeGroupsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1630 }
1631 //years
1632 s=add+YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1633 s.prepend(outputDirectory);
1634 TimetableExport::writeYearsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1635 s=add+YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1636 s.prepend(outputDirectory);
1637 TimetableExport::writeYearsTimetableDaysVerticalHtml(parent, s, sTime, na);
1638 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1639 s=add+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1640 s.prepend(outputDirectory);
1641 TimetableExport::writeYearsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1642 s=add+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1643 s.prepend(outputDirectory);
1644 TimetableExport::writeYearsTimetableTimeVerticalHtml(parent, s, sTime, na);
1645 } else {
1646 s=add+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1647 s.prepend(outputDirectory);
1648 TimetableExport::writeYearsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1649 s=add+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1650 s.prepend(outputDirectory);
1651 TimetableExport::writeYearsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1652 }
1653 //teachers
1654 s=add+TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1655 s.prepend(outputDirectory);
1656 TimetableExport::writeTeachersTimetableDaysHorizontalHtml(parent, s, sTime, na);
1657 s=add+TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1658 s.prepend(outputDirectory);
1659 TimetableExport::writeTeachersTimetableDaysVerticalHtml(parent, s, sTime, na);
1660 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1661 s=add+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1662 s.prepend(outputDirectory);
1663 TimetableExport::writeTeachersTimetableTimeHorizontalHtml(parent, s, sTime, na);
1664 s=add+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1665 s.prepend(outputDirectory);
1666 TimetableExport::writeTeachersTimetableTimeVerticalHtml(parent, s, sTime, na);
1667 } else {
1668 s=add+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1669 s.prepend(outputDirectory);
1670 TimetableExport::writeTeachersTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1671 s=add+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1672 s.prepend(outputDirectory);
1673 TimetableExport::writeTeachersTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1674 }
1675 //rooms
1676 s=add+ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1677 s.prepend(outputDirectory);
1678 TimetableExport::writeRoomsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1679 s=add+ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1680 s.prepend(outputDirectory);
1681 TimetableExport::writeRoomsTimetableDaysVerticalHtml(parent, s, sTime, na);
1682 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1683 s=add+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1684 s.prepend(outputDirectory);
1685 TimetableExport::writeRoomsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1686 s=add+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1687 s.prepend(outputDirectory);
1688 TimetableExport::writeRoomsTimetableTimeVerticalHtml(parent, s, sTime, na);
1689 } else {
1690 s=add+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1691 s.prepend(outputDirectory);
1692 TimetableExport::writeRoomsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1693 s=add+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1694 s.prepend(outputDirectory);
1695 TimetableExport::writeRoomsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1696 }
1697 //subjects
1698 s=add+SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1699 s.prepend(outputDirectory);
1700 TimetableExport::writeSubjectsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1701 s=add+SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1702 s.prepend(outputDirectory);
1703 TimetableExport::writeSubjectsTimetableDaysVerticalHtml(parent, s, sTime, na);
1704 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1705 s=add+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1706 s.prepend(outputDirectory);
1707 TimetableExport::writeSubjectsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1708 s=add+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1709 s.prepend(outputDirectory);
1710 TimetableExport::writeSubjectsTimetableTimeVerticalHtml(parent, s, sTime, na);
1711 } else {
1712 s=add+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1713 s.prepend(outputDirectory);
1714 TimetableExport::writeSubjectsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1715 s=add+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1716 s.prepend(outputDirectory);
1717 TimetableExport::writeSubjectsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1718 }
1719 //activity_tags
1720 s=add+ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1721 s.prepend(outputDirectory);
1722 TimetableExport::writeActivityTagsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1723 s=add+ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1724 s.prepend(outputDirectory);
1725 TimetableExport::writeActivityTagsTimetableDaysVerticalHtml(parent, s, sTime, na);
1726 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1727 s=add+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1728 s.prepend(outputDirectory);
1729 TimetableExport::writeActivityTagsTimetableTimeHorizontalHtml(parent, s, sTime, na);
1730 s=add+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1731 s.prepend(outputDirectory);
1732 TimetableExport::writeActivityTagsTimetableTimeVerticalHtml(parent, s, sTime, na);
1733 } else {
1734 s=add+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1735 s.prepend(outputDirectory);
1736 TimetableExport::writeActivityTagsTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1737 s=add+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1738 s.prepend(outputDirectory);
1739 TimetableExport::writeActivityTagsTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1740 }
1741 //all activities
1742 s=add+ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1743 s.prepend(outputDirectory);
1744 TimetableExport::writeAllActivitiesTimetableDaysHorizontalHtml(parent, s, sTime, na);
1745 s=add+ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1746 s.prepend(outputDirectory);
1747 TimetableExport::writeAllActivitiesTimetableDaysVerticalHtml(parent, s, sTime, na);
1748 if(!DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS){
1749 s=add+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1750 s.prepend(outputDirectory);
1751 TimetableExport::writeAllActivitiesTimetableTimeHorizontalHtml(parent, s, sTime, na);
1752 s=add+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1753 s.prepend(outputDirectory);
1754 TimetableExport::writeAllActivitiesTimetableTimeVerticalHtml(parent, s, sTime, na);
1755 } else {
1756 s=add+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML;
1757 s.prepend(outputDirectory);
1758 TimetableExport::writeAllActivitiesTimetableTimeHorizontalDailyHtml(parent, s, sTime, na);
1759 s=add+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML;
1760 s.prepend(outputDirectory);
1761 TimetableExport::writeAllActivitiesTimetableTimeVerticalDailyHtml(parent, s, sTime, na);
1762 }
1763 //teachers free periods
1764 s=add+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML;
1765 s.prepend(outputDirectory);
1766 TimetableExport::writeTeachersFreePeriodsTimetableDaysHorizontalHtml(parent, s, sTime, na);
1767 s=add+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML;
1768 s.prepend(outputDirectory);
1769 TimetableExport::writeTeachersFreePeriodsTimetableDaysVerticalHtml(parent, s, sTime, na);
1770 //statistics
1771 s=add+TEACHERS_STATISTICS_FILENAME_HTML;
1772 s.prepend(outputDirectory);
1773 TimetableExport::writeTeachersStatisticsHtml(parent, s, sTime, na);
1774 s=add+STUDENTS_STATISTICS_FILENAME_HTML;
1775 s.prepend(outputDirectory);
1776 TimetableExport::writeStudentsStatisticsHtml(parent, s, sTime, na);
1777
1778 //we can keep it, since it is for the command line version (but in fact we can also clear or delete these lines, since command line doesn't need interface printing)
1779 /*hashSubjectIDsTimetable.clear();
1780 hashActivityTagIDsTimetable.clear();
1781 hashStudentIDsTimetable.clear();
1782 hashTeacherIDsTimetable.clear();
1783 hashRoomIDsTimetable.clear();
1784 hashDayIDsTimetable.clear();
1785 hashActivityColorBySubject.clear();
1786 hashActivityColorBySubjectAndStudents.clear();
1787 activeHashActivityColorBySubject.clear();
1788 activeHashActivityColorBySubjectAndStudents.clear();*/
1789 }
1790
writeRandomSeedCommandLine(QWidget * parent,const MRG32k3a & rng,const QString & outputDirectory,bool before)1791 void TimetableExport::writeRandomSeedCommandLine(QWidget* parent, const MRG32k3a& rng, const QString& outputDirectory, bool before){ //outputDirectory contains trailing FILE_SEP
1792 QString RANDOM_SEED_FILENAME;
1793 if(before)
1794 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_BEFORE;
1795 else
1796 RANDOM_SEED_FILENAME=RANDOM_SEED_FILENAME_AFTER;
1797
1798 QString add=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1799 if(add.right(4)==".fet")
1800 add=add.left(add.length()-4);
1801 //else if(INPUT_FILENAME_XML!="")
1802 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
1803
1804 if(add!="")
1805 add.append("_");
1806
1807 QString s=add+RANDOM_SEED_FILENAME;
1808 s.prepend(outputDirectory);
1809
1810 writeRandomSeedFile(parent, rng, s, before);
1811 }
1812
1813 //by Volker Dirr (timetabling.de)
writeConflictsTxt(QWidget * parent,const QString & filename,const QString & saveTime,int placedActivities)1814 void TimetableExport::writeConflictsTxt(QWidget* parent, const QString& filename, const QString& saveTime, int placedActivities){
1815 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
1816 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
1817
1818 if(!WRITE_TIMETABLE_CONFLICTS){
1819 if(QFile::exists(filename))
1820 QFile::remove(filename);
1821
1822 return;
1823 }
1824
1825 QFile file(filename);
1826 if(!file.open(QIODevice::WriteOnly)){
1827 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1828 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(filename));
1829 return;
1830 }
1831 QTextStream tos(&file);
1832 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
1833 tos.setEncoding(QStringConverter::Utf8);
1834 #else
1835 tos.setCodec("UTF-8");
1836 #endif
1837 tos.setGenerateByteOrderMark(true);
1838
1839 if(placedActivities==gt.rules.nInternalActivities){
1840 QString tt=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1841 if(INPUT_FILENAME_XML=="")
1842 tt=tr("unnamed");
1843 tos<<TimetableExport::tr("Soft conflicts of %1", "%1 is the file name").arg(tt);
1844 tos<<"\n";
1845 tos<<TimetableExport::tr("Generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)<<"\n\n";
1846
1847 tos<<TimetableExport::tr("Number of broken soft constraints: %1").arg(best_solution.conflictsWeightList.count())<<"\n";
1848 tos<<TimetableExport::tr("Total soft conflicts: %1").arg(CustomFETString::numberPlusTwoDigitsPrecision(best_solution.conflictsTotal))<<"\n\n";
1849 tos<<TimetableExport::tr("Soft conflicts list (in decreasing order):")<<"\n\n";
1850 for(const QString& t : qAsConst(best_solution.conflictsDescriptionList))
1851 tos<<t<<"\n";
1852 tos<<"\n"<<TimetableExport::tr("End of file.")<<"\n";
1853 }
1854 else{
1855 QString tt=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
1856 if(INPUT_FILENAME_XML=="")
1857 tt=tr("unnamed");
1858 tos<<TimetableExport::tr("Conflicts of %1").arg(tt);
1859 tos<<"\n";
1860 tos<<TimetableExport::tr("Warning! Only %1 out of %2 activities placed!").arg(placedActivities).arg(gt.rules.nInternalActivities)<<"\n";
1861 tos<<TimetableExport::tr("Generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)<<"\n\n";
1862
1863 tos<<TimetableExport::tr("Number of broken constraints: %1").arg(best_solution.conflictsWeightList.count())<<"\n";
1864 tos<<TimetableExport::tr("Total conflicts: %1").arg(CustomFETString::numberPlusTwoDigitsPrecision(best_solution.conflictsTotal))<<"\n\n";
1865 tos<<TimetableExport::tr("Conflicts list (in decreasing order):")<<"\n\n";
1866 for(const QString& t : qAsConst(best_solution.conflictsDescriptionList))
1867 tos<<t<<"\n";
1868 tos<<"\n"<<TimetableExport::tr("End of file.")<<"\n";
1869 }
1870
1871 if(file.error()>0){
1872 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1873 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(filename).arg(file.error()));
1874 }
1875 file.close();
1876 }
1877
writeSubgroupsTimetableXml(QWidget * parent,const QString & xmlfilename,const QList<int> & subgroupsSortedOrder)1878 void TimetableExport::writeSubgroupsTimetableXml(QWidget* parent, const QString& xmlfilename, const QList<int>& subgroupsSortedOrder){
1879 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
1880 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
1881
1882 if(!WRITE_TIMETABLES_XML || !WRITE_TIMETABLES_SUBGROUPS){
1883 if(QFile::exists(xmlfilename))
1884 QFile::remove(xmlfilename);
1885
1886 return;
1887 }
1888
1889 //Now we print the results to an XML file
1890 QFile file(xmlfilename);
1891 if(!file.open(QIODevice::WriteOnly)){
1892 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1893 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(xmlfilename));
1894 return;
1895 }
1896 QTextStream tos(&file);
1897 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
1898 tos.setEncoding(QStringConverter::Utf8);
1899 #else
1900 tos.setCodec("UTF-8");
1901 #endif
1902 tos.setGenerateByteOrderMark(true);
1903 tos<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
1904 tos<<"<"<<protect(STUDENTS_TIMETABLE_TAG)<<">\n";
1905
1906 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
1907 int realSubgroup;
1908 if(subgroupsSortedOrder!=QList<int>())
1909 realSubgroup=subgroupsSortedOrder.at(subgroup);
1910 else
1911 realSubgroup=subgroup;
1912
1913 tos<< " <Subgroup name=\"";
1914 QString subgroup_name = gt.rules.internalSubgroupsList[realSubgroup]->name;
1915 tos<< protect(subgroup_name) << "\">\n";
1916
1917 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
1918 tos<<" <Day name=\""<<protect(gt.rules.daysOfTheWeek[day])<<"\">\n";
1919 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
1920 tos << " <Hour name=\"" << protect(gt.rules.hoursOfTheDay[hour]) << "\">\n";
1921 tos<<" ";
1922 int ai=students_timetable_weekly[realSubgroup][day][hour]; //activity index
1923 if(ai!=UNALLOCATED_ACTIVITY){
1924 //Activity* act=gt.rules.activitiesList.at(ai);
1925 Activity* act=>.rules.internalActivitiesList[ai];
1926 for(QStringList::const_iterator it=act->teachersNames.constBegin(); it!=act->teachersNames.constEnd(); it++)
1927 tos<<"<Teacher name=\""<<protect(*it)<<"\"></Teacher>";
1928 tos<<"<Subject name=\""<<protect(act->subjectName)<<"\"></Subject>";
1929 for(const QString& atn : qAsConst(act->activityTagsNames))
1930 tos<<"<Activity_Tag name=\""<<protect(atn)<<"\"></Activity_Tag>";
1931
1932 int r=best_solution.rooms[ai];
1933 if(r!=UNALLOCATED_SPACE && r!=UNSPECIFIED_ROOM){
1934 tos<<"<Room name=\""<<protect(gt.rules.internalRoomsList[r]->name)<<"\"></Room>";
1935 if(gt.rules.internalRoomsList[r]->isVirtual==true)
1936 for(int rr : qAsConst(best_solution.realRoomsList[ai]))
1937 tos<<"<Real_Room name=\""<<protect(gt.rules.internalRoomsList[rr]->name)<<"\"></Real_Room>";
1938 }
1939 }
1940 tos<<"\n";
1941 tos << " </Hour>\n";
1942 }
1943 tos<<" </Day>\n";
1944 }
1945 tos<<" </Subgroup>\n";
1946 }
1947
1948 tos << "</" << protect(STUDENTS_TIMETABLE_TAG) << ">\n";
1949
1950 if(file.error()>0){
1951 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1952 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(xmlfilename).arg(file.error()));
1953 }
1954 file.close();
1955 }
1956
writeTeachersTimetableXml(QWidget * parent,const QString & xmlfilename)1957 void TimetableExport::writeTeachersTimetableXml(QWidget* parent, const QString& xmlfilename){
1958 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
1959 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
1960
1961 if(!WRITE_TIMETABLES_XML || !WRITE_TIMETABLES_TEACHERS){
1962 if(QFile::exists(xmlfilename))
1963 QFile::remove(xmlfilename);
1964
1965 return;
1966 }
1967
1968 //Writing the timetable in xml format
1969 QFile file(xmlfilename);
1970 if(!file.open(QIODevice::WriteOnly)){
1971 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
1972 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(xmlfilename));
1973 return;
1974 }
1975 QTextStream tos(&file);
1976 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
1977 tos.setEncoding(QStringConverter::Utf8);
1978 #else
1979 tos.setCodec("UTF-8");
1980 #endif
1981 tos.setGenerateByteOrderMark(true);
1982 tos<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
1983 tos << "<" << protect(TEACHERS_TIMETABLE_TAG) << ">\n";
1984
1985 for(int i=0; i<gt.rules.nInternalTeachers; i++){
1986 tos << " <Teacher name=\"" << protect(gt.rules.internalTeachersList[i]->name) << "\">\n";
1987 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
1988 tos << " <Day name=\"" << protect(gt.rules.daysOfTheWeek[day]) << "\">\n";
1989 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
1990 tos << " <Hour name=\"" << protect(gt.rules.hoursOfTheDay[hour]) << "\">\n";
1991
1992 tos<<" ";
1993 int ai=teachers_timetable_weekly[i][day][hour]; //activity index
1994 //Activity* act=gt.rules.activitiesList.at(ai);
1995 if(ai!=UNALLOCATED_ACTIVITY){
1996 Activity* act=>.rules.internalActivitiesList[ai];
1997 tos<<"<Subject name=\""<<protect(act->subjectName)<<"\"></Subject>";
1998 for(const QString& atn : qAsConst(act->activityTagsNames))
1999 tos<<"<Activity_Tag name=\""<<protect(atn)<<"\"></Activity_Tag>";
2000 for(QStringList::const_iterator it=act->studentsNames.constBegin(); it!=act->studentsNames.constEnd(); it++)
2001 tos << "<Students name=\"" << protect(*it) << "\"></Students>";
2002
2003 int r=best_solution.rooms[ai];
2004 if(r!=UNALLOCATED_SPACE && r!=UNSPECIFIED_ROOM){
2005 tos<<"<Room name=\""<<protect(gt.rules.internalRoomsList[r]->name)<<"\"></Room>";
2006 if(gt.rules.internalRoomsList[r]->isVirtual==true)
2007 for(int rr : qAsConst(best_solution.realRoomsList[ai]))
2008 tos<<"<Real_Room name=\""<<protect(gt.rules.internalRoomsList[rr]->name)<<"\"></Real_Room>";
2009 }
2010 }
2011 tos<<"\n";
2012 tos << " </Hour>\n";
2013 }
2014 tos << " </Day>\n";
2015 }
2016 tos<<" </Teacher>\n";
2017 }
2018
2019 tos << "</" << protect(TEACHERS_TIMETABLE_TAG) << ">\n";
2020
2021 if(file.error()>0){
2022 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2023 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(xmlfilename).arg(file.error()));
2024 }
2025 file.close();
2026 }
2027
writeActivitiesTimetableXml(QWidget * parent,const QString & xmlfilename)2028 void TimetableExport::writeActivitiesTimetableXml(QWidget* parent, const QString& xmlfilename){
2029 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2030 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2031
2032 if(!WRITE_TIMETABLES_XML || !WRITE_TIMETABLES_ACTIVITIES){
2033 if(QFile::exists(xmlfilename))
2034 QFile::remove(xmlfilename);
2035
2036 return;
2037 }
2038
2039 //Writing the timetable in xml format
2040 QFile file(xmlfilename);
2041 if(!file.open(QIODevice::WriteOnly)){
2042 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2043 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(xmlfilename));
2044 return;
2045 }
2046 QTextStream tos(&file);
2047 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2048 tos.setEncoding(QStringConverter::Utf8);
2049 #else
2050 tos.setCodec("UTF-8");
2051 #endif
2052 tos.setGenerateByteOrderMark(true);
2053 tos<<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
2054 tos << "<" << protect(ACTIVITIES_TIMETABLE_TAG) << ">\n";
2055
2056 for(int i=0; i<gt.rules.nInternalActivities; i++){
2057 tos<<"<Activity>\n";
2058
2059 tos<<" <Id>"<<gt.rules.internalActivitiesList[i].id<<"</Id>\n";
2060
2061 QString day="";
2062 if(best_solution.times[i]!=UNALLOCATED_TIME){
2063 int d=best_solution.times[i]%gt.rules.nDaysPerWeek;
2064 day=gt.rules.daysOfTheWeek[d];
2065 }
2066 tos<<" <Day>"<<protect(day)<<"</Day>\n";
2067
2068 QString hour="";
2069 if(best_solution.times[i]!=UNALLOCATED_TIME){
2070 int h=best_solution.times[i]/gt.rules.nDaysPerWeek;
2071 hour=gt.rules.hoursOfTheDay[h];
2072 }
2073 tos<<" <Hour>"<<protect(hour)<<"</Hour>\n";
2074
2075 QString room="";
2076 if(best_solution.rooms[i]!=UNALLOCATED_SPACE && best_solution.rooms[i]!=UNSPECIFIED_ROOM){
2077 int r=best_solution.rooms[i];
2078 room=gt.rules.internalRoomsList[r]->name;
2079 }
2080 tos<<" <Room>"<<protect(room)<<"</Room>\n";
2081 if(best_solution.rooms[i]!=UNALLOCATED_SPACE && best_solution.rooms[i]!=UNSPECIFIED_ROOM){
2082 int r=best_solution.rooms[i];
2083 if(gt.rules.internalRoomsList[r]->isVirtual==true){
2084 assert(gt.rules.internalRoomsList[r]->rrsl.count()==best_solution.realRoomsList[i].count());
2085 for(int rr : qAsConst(best_solution.realRoomsList[i])){
2086 assert(rr>=0 && rr<gt.rules.nInternalRooms);
2087 tos<<" <Real_Room>"<<protect(gt.rules.internalRoomsList[rr]->name)<<"</Real_Room>\n";
2088 }
2089 }
2090 }
2091
2092 tos<<"</Activity>\n";
2093 }
2094
2095 tos << "</" << protect(ACTIVITIES_TIMETABLE_TAG) << ">\n";
2096
2097 if(file.error()>0){
2098 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2099 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(xmlfilename).arg(file.error()));
2100 }
2101 file.close();
2102 }
2103
2104 // writing the index html file by Volker Dirr.
writeIndexHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)2105 void TimetableExport::writeIndexHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
2106 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2107 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2108
2109 bool _writeAtLeastATimetable = writeAtLeastATimetable();
2110
2111 //Now we print the results to an HTML file
2112 QFile file(htmlfilename);
2113 if(!file.open(QIODevice::WriteOnly)){
2114 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2115 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2116 return;
2117 }
2118 QTextStream tos(&file);
2119 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2120 tos.setEncoding(QStringConverter::Utf8);
2121 #else
2122 tos.setCodec("UTF-8");
2123 #endif
2124 tos.setGenerateByteOrderMark(true);
2125
2126 tos<<writeHead(false, placedActivities, true);
2127
2128 QString bar;
2129 QString s2="";
2130 if(INPUT_FILENAME_XML=="")
2131 bar="";
2132 else{
2133 bar="_";
2134 s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
2135
2136 if(s2.right(4)==".fet")
2137 s2=s2.left(s2.length()-4);
2138 //else if(INPUT_FILENAME_XML!="")
2139 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
2140 }
2141 tos<<" <p>\n";
2142
2143 if(!_writeAtLeastATimetable){
2144 tos<<" "<<TimetableExport::tr("No timetable was written, because from the settings you disabled writing any timetable.")<<"\n";
2145 tos<<" "<<TimetableExport::tr("The exception is that after each successful (complete) timetable generation the %1 file"
2146 " will be written.").arg("data_and_timetable.fet")<<"\n";
2147 tos<<" </p>\n";
2148 tos<<" <p>\n";
2149 tos<<" "<<TimetableExport::tr("File generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)<<"\n";
2150 tos<<" </p>\n";
2151 }
2152 else{
2153 if(WRITE_TIMETABLE_CONFLICTS)
2154 tos<<" <a href=\""<<s2+bar+CONFLICTS_FILENAME<<"\">"<<tr("View the soft conflicts list.")<<"</a><br />\n";
2155 else
2156 tos<<" "<<TimetableExport::tr("Soft conflicts list - disabled.")<<"<br />\n";
2157
2158 ///////////////////////////
2159
2160 QString tmps1, tmps2;
2161 if(WRITE_TIMETABLES_STATISTICS && (WRITE_TIMETABLES_YEARS || WRITE_TIMETABLES_GROUPS || WRITE_TIMETABLES_SUBGROUPS) )
2162 tmps1=" <a href=\""+s2+bar+STUDENTS_STATISTICS_FILENAME_HTML+"\">"+tr("students")+"</a>";
2163 else
2164 tmps1=tr("students - disabled");
2165
2166 if(WRITE_TIMETABLES_STATISTICS && WRITE_TIMETABLES_TEACHERS)
2167 tmps2="<a href=\""+s2+bar+TEACHERS_STATISTICS_FILENAME_HTML+"\">"+tr("teachers")+"</a>";
2168 else
2169 tmps2=tr("teachers - disabled");
2170
2171 QString tmps3=tr("View statistics: %1, %2.", "%1 and %2 are two files in HTML format, to show statistics for students and teachers. The user can click on one file to view it")
2172 .arg(tmps1).arg(tmps2);
2173
2174 tos<<" "<<tmps3<<"<br />\n";
2175
2176 ///////////////////////////
2177
2178 QString tmp1, tmp2, tmp3;
2179 if(WRITE_TIMETABLES_XML && WRITE_TIMETABLES_SUBGROUPS)
2180 tmp1="<a href=\""+s2+bar+SUBGROUPS_TIMETABLE_FILENAME_XML+"\">"+tr("subgroups")+"</a>";
2181 else
2182 tmp1=tr("subgroups - disabled", "It means the subgroups XML timetables are disabled");
2183 if(WRITE_TIMETABLES_XML && WRITE_TIMETABLES_TEACHERS)
2184 tmp2="<a href=\""+s2+bar+TEACHERS_TIMETABLE_FILENAME_XML+"\">"+tr("teachers")+"</a>";
2185 else
2186 tmp2=tr("teachers - disabled", "It means the teachers XML timetables are disabled");
2187 if(WRITE_TIMETABLES_XML && WRITE_TIMETABLES_ACTIVITIES)
2188 tmp3="<a href=\""+s2+bar+ACTIVITIES_TIMETABLE_FILENAME_XML+"\">"+tr("activities")+"</a>";
2189 else
2190 tmp3=tr("activities - disabled", "It means the activities XML timetables are disabled");
2191 QString tmp4=TimetableExport::tr("View XML: %1, %2, %3.", "%1, %2 and %3 are three files in XML format, subgroups, teachers and activities timetables. The user can click on one file to view it").arg(tmp1).arg(tmp2).arg(tmp3);
2192 tos<<" "<<tmp4<<"\n";
2193
2194 tos<<" </p>\n\n";
2195
2196 tos<<" <table border=\"1\">\n";
2197
2198 tos<<" <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
2199
2200 tos<<" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\"4\">"+tr("Timetables")+"</th></tr>\n";
2201 tos<<" <tr>\n <!-- span -->\n";
2202 tos<<" <th>"+tr("Days Horizontal")+"</th><th>"+tr("Days Vertical")+"</th><th>"+tr("Time Horizontal")+"</th><th>"+tr("Time Vertical")+"</th>";
2203 tos<<" </tr>\n";
2204 tos<<" </thead>\n";
2205 tos<<" <tbody>\n";
2206
2207 /* workaround
2208 tos<<" <tfoot><tr><td></td><td colspan=\"4\">"<<TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)<<"</td></tr></tfoot>\n";
2209 */
2210
2211 tos<<" <tr>\n";
2212 tos<<" <th>"+tr("Subgroups")+"</th>\n";
2213 if(WRITE_TIMETABLES_SUBGROUPS){
2214 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2215 tos<<" <td><a href=\""<<s2+bar+SUBGROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2216 else
2217 tos<<" <td>"+tr("disabled")+"</td>\n";
2218 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2219 tos<<" <td><a href=\""<<s2+bar+SUBGROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2220 else
2221 tos<<" <td>"+tr("disabled")+"</td>\n";
2222 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2223 tos<<" <td><a href=\""<<s2+bar+SUBGROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2224 else
2225 tos<<" <td>"+tr("disabled")+"</td>\n";
2226 if(WRITE_TIMETABLES_TIME_VERTICAL)
2227 tos<<" <td><a href=\""<<s2+bar+SUBGROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2228 else
2229 tos<<" <td>"+tr("disabled")+"</td>\n";
2230 } else {
2231 tos<<" <td>"+tr("disabled")+"</td>\n";
2232 tos<<" <td>"+tr("disabled")+"</td>\n";
2233 tos<<" <td>"+tr("disabled")+"</td>\n";
2234 tos<<" <td>"+tr("disabled")+"</td>\n";
2235 }
2236 tos<<" </tr>\n";
2237 tos<<" <tr>\n";
2238 tos<<" <th>"+tr("Groups")+"</th>\n";
2239 if(WRITE_TIMETABLES_GROUPS){
2240 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2241 tos<<" <td><a href=\""<<s2+bar+GROUPS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2242 else
2243 tos<<" <td>"+tr("disabled")+"</td>\n";
2244 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2245 tos<<" <td><a href=\""<<s2+bar+GROUPS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2246 else
2247 tos<<" <td>"+tr("disabled")+"</td>\n";
2248 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2249 tos<<" <td><a href=\""<<s2+bar+GROUPS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2250 else
2251 tos<<" <td>"+tr("disabled")+"</td>\n";
2252 if(WRITE_TIMETABLES_TIME_VERTICAL)
2253 tos<<" <td><a href=\""<<s2+bar+GROUPS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2254 else
2255 tos<<" <td>"+tr("disabled")+"</td>\n";
2256 } else {
2257 tos<<" <td>"+tr("disabled")+"</td>\n";
2258 tos<<" <td>"+tr("disabled")+"</td>\n";
2259 tos<<" <td>"+tr("disabled")+"</td>\n";
2260 tos<<" <td>"+tr("disabled")+"</td>\n";
2261 }
2262 tos<<" </tr>\n";
2263 tos<<" <tr>\n";
2264 tos<<" <th>"+tr("Years")+"</th>\n";
2265 if(WRITE_TIMETABLES_YEARS){
2266 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2267 tos<<" <td><a href=\""<<s2+bar+YEARS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2268 else
2269 tos<<" <td>"+tr("disabled")+"</td>\n";
2270 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2271 tos<<" <td><a href=\""<<s2+bar+YEARS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2272 else
2273 tos<<" <td>"+tr("disabled")+"</td>\n";
2274 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2275 tos<<" <td><a href=\""<<s2+bar+YEARS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2276 else
2277 tos<<" <td>"+tr("disabled")+"</td>\n";
2278 if(WRITE_TIMETABLES_TIME_VERTICAL)
2279 tos<<" <td><a href=\""<<s2+bar+YEARS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2280 else
2281 tos<<" <td>"+tr("disabled")+"</td>\n";
2282 } else {
2283 tos<<" <td>"+tr("disabled")+"</td>\n";
2284 tos<<" <td>"+tr("disabled")+"</td>\n";
2285 tos<<" <td>"+tr("disabled")+"</td>\n";
2286 tos<<" <td>"+tr("disabled")+"</td>\n";
2287 }
2288 tos<<" </tr>\n";
2289 tos<<" <tr>\n";
2290 tos<<" <th>"+tr("Teachers")+"</th>\n";
2291 if(WRITE_TIMETABLES_TEACHERS){
2292 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2293 tos<<" <td><a href=\""<<s2+bar+TEACHERS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2294 else
2295 tos<<" <td>"+tr("disabled")+"</td>\n";
2296 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2297 tos<<" <td><a href=\""<<s2+bar+TEACHERS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2298 else
2299 tos<<" <td>"+tr("disabled")+"</td>\n";
2300 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2301 tos<<" <td><a href=\""<<s2+bar+TEACHERS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2302 else
2303 tos<<" <td>"+tr("disabled")+"</td>\n";
2304 if(WRITE_TIMETABLES_TIME_VERTICAL)
2305 tos<<" <td><a href=\""<<s2+bar+TEACHERS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2306 else
2307 tos<<" <td>"+tr("disabled")+"</td>\n";
2308 } else {
2309 tos<<" <td>"+tr("disabled")+"</td>\n";
2310 tos<<" <td>"+tr("disabled")+"</td>\n";
2311 tos<<" <td>"+tr("disabled")+"</td>\n";
2312 tos<<" <td>"+tr("disabled")+"</td>\n";
2313 }
2314 tos<<" </tr>\n";
2315 tos<<" <tr>\n";
2316 tos<<" <th>"+tr("Teachers' Free Periods")+"</th>\n";
2317 if(WRITE_TIMETABLES_TEACHERS_FREE_PERIODS){
2318 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2319 tos<<" <td><a href=\""<<s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2320 else
2321 tos<<" <td>"+tr("disabled")+"</td>\n";
2322 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2323 tos<<" <td><a href=\""<<s2+bar+TEACHERS_FREE_PERIODS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2324 else
2325 tos<<" <td>"+tr("disabled")+"</td>\n";
2326 } else {
2327 tos<<" <td>"+tr("disabled")+"</td>\n";
2328 tos<<" <td>"+tr("disabled")+"</td>\n";
2329 }
2330 tos<<" <td>"<<protect2(STRING_EMPTY_SLOT)<<"</td>\n";
2331 tos<<" <td>"<<protect2(STRING_EMPTY_SLOT)<<"</td>\n";
2332 tos<<" </tr>\n";
2333 tos<<" <tr>\n";
2334 tos<<" <th>"+tr("Rooms")+"</th>\n";
2335 if(WRITE_TIMETABLES_ROOMS){
2336 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2337 tos<<" <td><a href=\""<<s2+bar+ROOMS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2338 else
2339 tos<<" <td>"+tr("disabled")+"</td>\n";
2340 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2341 tos<<" <td><a href=\""<<s2+bar+ROOMS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2342 else
2343 tos<<" <td>"+tr("disabled")+"</td>\n";
2344 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2345 tos<<" <td><a href=\""<<s2+bar+ROOMS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2346 else
2347 tos<<" <td>"+tr("disabled")+"</td>\n";
2348 if(WRITE_TIMETABLES_TIME_VERTICAL)
2349 tos<<" <td><a href=\""<<s2+bar+ROOMS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2350 else
2351 tos<<" <td>"+tr("disabled")+"</td>\n";
2352 } else {
2353 tos<<" <td>"+tr("disabled")+"</td>\n";
2354 tos<<" <td>"+tr("disabled")+"</td>\n";
2355 tos<<" <td>"+tr("disabled")+"</td>\n";
2356 tos<<" <td>"+tr("disabled")+"</td>\n";
2357 }
2358 tos<<" </tr>\n";
2359 tos<<" <tr>\n";
2360 tos<<" <th>"+tr("Subjects")+"</th>\n";
2361 if(WRITE_TIMETABLES_SUBJECTS){
2362 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2363 tos<<" <td><a href=\""<<s2+bar+SUBJECTS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2364 else
2365 tos<<" <td>"+tr("disabled")+"</td>\n";
2366 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2367 tos<<" <td><a href=\""<<s2+bar+SUBJECTS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2368 else
2369 tos<<" <td>"+tr("disabled")+"</td>\n";
2370 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2371 tos<<" <td><a href=\""<<s2+bar+SUBJECTS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2372 else
2373 tos<<" <td>"+tr("disabled")+"</td>\n";
2374 if(WRITE_TIMETABLES_TIME_VERTICAL)
2375 tos<<" <td><a href=\""<<s2+bar+SUBJECTS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2376 else
2377 tos<<" <td>"+tr("disabled")+"</td>\n";
2378 } else {
2379 tos<<" <td>"+tr("disabled")+"</td>\n";
2380 tos<<" <td>"+tr("disabled")+"</td>\n";
2381 tos<<" <td>"+tr("disabled")+"</td>\n";
2382 tos<<" <td>"+tr("disabled")+"</td>\n";
2383 }
2384 tos<<" </tr>\n";
2385 tos<<" <tr>\n";
2386 tos<<" <th>"+tr("Activity Tags")+"</th>\n";
2387 if(WRITE_TIMETABLES_ACTIVITY_TAGS){
2388 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2389 tos<<" <td><a href=\""<<s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2390 else
2391 tos<<" <td>"+tr("disabled")+"</td>\n";
2392 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2393 tos<<" <td><a href=\""<<s2+bar+ACTIVITY_TAGS_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2394 else
2395 tos<<" <td>"+tr("disabled")+"</td>\n";
2396 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2397 tos<<" <td><a href=\""<<s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2398 else
2399 tos<<" <td>"+tr("disabled")+"</td>\n";
2400 if(WRITE_TIMETABLES_TIME_VERTICAL)
2401 tos<<" <td><a href=\""<<s2+bar+ACTIVITY_TAGS_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2402 else
2403 tos<<" <td>"+tr("disabled")+"</td>\n";
2404 } else {
2405 tos<<" <td>"+tr("disabled")+"</td>\n";
2406 tos<<" <td>"+tr("disabled")+"</td>\n";
2407 tos<<" <td>"+tr("disabled")+"</td>\n";
2408 tos<<" <td>"+tr("disabled")+"</td>\n";
2409 }
2410 tos<<" </tr>\n";
2411 tos<<" <tr>\n";
2412 tos<<" <th>"+tr("Activities")+"</th>\n";
2413 if(WRITE_TIMETABLES_ACTIVITIES){
2414 if(WRITE_TIMETABLES_DAYS_HORIZONTAL)
2415 tos<<" <td><a href=\""<<s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2416 else
2417 tos<<" <td>"+tr("disabled")+"</td>\n";
2418 if(WRITE_TIMETABLES_DAYS_VERTICAL)
2419 tos<<" <td><a href=\""<<s2+bar+ALL_ACTIVITIES_TIMETABLE_DAYS_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2420 else
2421 tos<<" <td>"+tr("disabled")+"</td>\n";
2422 if(WRITE_TIMETABLES_TIME_HORIZONTAL)
2423 tos<<" <td><a href=\""<<s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_HORIZONTAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2424 else
2425 tos<<" <td>"+tr("disabled")+"</td>\n";
2426 if(WRITE_TIMETABLES_TIME_VERTICAL)
2427 tos<<" <td><a href=\""<<s2+bar+ALL_ACTIVITIES_TIMETABLE_TIME_VERTICAL_FILENAME_HTML<<"\">"+tr("view")+"</a></td>\n";
2428 else
2429 tos<<" <td>"+tr("disabled")+"</td>\n";
2430 } else {
2431 tos<<" <td>"+tr("disabled")+"</td>\n";
2432 tos<<" <td>"+tr("disabled")+"</td>\n";
2433 tos<<" <td>"+tr("disabled")+"</td>\n";
2434 tos<<" <td>"+tr("disabled")+"</td>\n";
2435 }
2436 tos<<" </tr>\n";
2437 //workaround begin.
2438 tos<<" <tr class=\"foot\"><td></td><td colspan=\"4\">"<<TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)<<"</td></tr>\n";
2439 //workaround end.
2440 tos<<" </tbody>\n";
2441 tos<<" </table>\n";
2442 }
2443
2444 tos<<" </body>\n</html>\n";
2445
2446 if(file.error()>0){
2447 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2448 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2449 }
2450 file.close();
2451 }
2452
2453 // writing the stylesheet in css format to a file by Volker Dirr.
writeStylesheetCss(QWidget * parent,const QString & cssfilename,const QString & saveTime,int placedActivities)2454 void TimetableExport::writeStylesheetCss(QWidget* parent, const QString& cssfilename, const QString& saveTime, int placedActivities){
2455 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2456 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2457
2458 bool _writeAtLeastATimetable = writeAtLeastATimetable();
2459
2460 if(!_writeAtLeastATimetable){
2461 if(QFile::exists(cssfilename))
2462 QFile::remove(cssfilename);
2463
2464 return;
2465 }
2466
2467 //get used students //TODO: do it the same way in statistics.cpp
2468 QSet<QString> usedStudents;
2469 for(int i=0; i<gt.rules.nInternalActivities; i++){
2470 for(const QString& st : qAsConst(gt.rules.internalActivitiesList[i].studentsNames)){
2471 if(!usedStudents.contains(st))
2472 usedStudents<<st;
2473 }
2474 }
2475
2476 //Now we print the results to a CSS file
2477 QFile file(cssfilename);
2478 if(!file.open(QIODevice::WriteOnly)){
2479 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2480 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(cssfilename));
2481 return;
2482 }
2483 QTextStream tos(&file);
2484 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2485 tos.setEncoding(QStringConverter::Utf8);
2486 #else
2487 tos.setCodec("UTF-8");
2488 #endif
2489 tos.setGenerateByteOrderMark(true);
2490
2491 tos<<"@charset \"UTF-8\";"<<"\n\n";
2492
2493 QString tt=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
2494 if(INPUT_FILENAME_XML=="")
2495 tt=tr("unnamed");
2496 tos<<"/* "<<TimetableExport::tr("CSS Stylesheet of %1", "%1 is the file name").arg(tt);
2497 tos<<"\n";
2498 if(placedActivities!=gt.rules.nInternalActivities)
2499 tos<<" "<<TimetableExport::tr("Warning! Only %1 out of %2 activities placed!").arg(placedActivities).arg(gt.rules.nInternalActivities)<<"\n";
2500 tos<<" "<<TimetableExport::tr("Stylesheet generated with FET %1 on %2", "%1 is FET version, %2 is date and time").arg(FET_VERSION).arg(saveTime)<<" */\n\n";
2501
2502 tos<<"/* "<<TimetableExport::tr("To do a page-break only after every second timetable, delete \"page-break-before: always;\" in \"table.even_table\".",
2503 "Please keep fields in quotes as they are, untranslated.")<<" */\n";
2504 tos<<"/* "<<TimetableExport::tr("Delete \"page-break-before: always;\" in \"table.even_table\" and in \"table.odd_table\" to skip page-breaks.",
2505 "Please keep fields in quotes as they are, untranslated.")<<" */\n";
2506 tos<<"/* "<<TimetableExport::tr("To hide an element just write the following phrase into the element: %1 (without quotes).",
2507 "%1 is a short phrase beginning and ending with quotes, and we want the user to be able to add it, but without quotes").arg("\"display: none;\"")<<" */\n\n";
2508 tos<<"p.back {\n margin-top: 4ex;\n margin-bottom: 5ex;\n}\n\n";
2509 tos<<"table {\n text-align: center;\n page-break-inside: avoid;\n}\n\n";
2510 tos<<"table.odd_table {\n page-break-before: always;\n}\n\n";
2511 tos<<"table.even_table {\n page-break-before: always;\n}\n\n";
2512 tos<<"table.detailed {\n margin-left: auto; margin-right: auto;\n text-align: center;\n border: 0px;\n border-spacing: 0;\n border-collapse: collapse;\n}\n\n";
2513 tos<<"caption {\n\n}\n\n";
2514 tos<<"thead {\n\n}\n\n";
2515
2516 //workaround begin.
2517 tos<<"/* "<<TimetableExport::tr("Some programs import \"tfoot\" incorrectly. So we use \"tr.foot\" instead of \"tfoot\".",
2518 "Please keep tfoot and tr.foot untranslated, as they are in the original English phrase")<<" */\n\n";
2519 //tos<<"tfoot {\n\n}\n\n";
2520 tos<<"tr.foot {\n\n}\n\n";
2521 //workaround end
2522
2523 tos<<"tbody {\n\n}\n\n";
2524 tos<<"th {\n\n}\n\n";
2525 tos<<"td {\n\n}\n\n";
2526 tos<<"td.detailed {\n border: 1px dashed silver;\n border-bottom: 0;\n border-top: 0;\n}\n\n";
2527 if(TIMETABLE_HTML_LEVEL>=2){
2528 tos<<"th.xAxis {\n/* width: 8em; */\n}\n\n";
2529 tos<<"th.yAxis {\n height: 8ex;\n}\n\n";
2530 }
2531
2532 //By Liviu, with ideas from Volker
2533 if(TIMETABLE_HTML_LEVEL==7){ //must be written before LEVEL 3, because LEVEL 3 should have higher priority
2534 int cnt=0;
2535 for(int i : qAsConst(activeHashActivityColorBySubject)){
2536 Activity* act=>.rules.internalActivitiesList[i];
2537
2538 QString tmpString=act->subjectName;
2539
2540 //similar to the coloring by Marco Vassura (start)
2541 int r,g,b;
2542 stringToColor(tmpString, r, g, b);
2543 tos << "td.c_"<<QString::number(cnt+1)<<" { /* Activity id: "<<QString::number(act->id)<<" (subject) */\n ";
2544 tos<<"background-color: rgb("<<QString::number(r)<<", "<<QString::number(g)<<", "<<QString::number(b)<<");\n";
2545 double brightness = double(r)*0.299 + double(g)*0.587 + double(b)*0.114;
2546 if (brightness<127.5)
2547 tos<<" color: white;\n";
2548 else
2549 tos<<" color: black;\n";
2550 tos<<"}\n\n";
2551 //similar to the coloring by Marco Vassura (end)
2552 cnt++;
2553 }
2554 for(int i : qAsConst(activeHashActivityColorBySubjectAndStudents)){
2555 Activity* act=>.rules.internalActivitiesList[i];
2556
2557 QString tmpString=act->subjectName+" "+act->studentsNames.join(", ");
2558
2559 //similar to the coloring by Marco Vassura (start)
2560 int r,g,b;
2561 stringToColor(tmpString, r, g, b);
2562 tos << "td.c_"<<QString::number(cnt+1)<<" { /* Activity id: "<<QString::number(act->id)<<" (subject+students) */\n ";
2563 tos<<"background-color: rgb("<<QString::number(r)<<", "<<QString::number(g)<<", "<<QString::number(b)<<");\n";
2564 double brightness = double(r)*0.299 + double(g)*0.587 + double(b)*0.114;
2565 if (brightness<127.5)
2566 tos<<" color: white;\n";
2567 else
2568 tos<<" color: black;\n";
2569 tos<<"}\n\n";
2570 //similar to the coloring by Marco Vassura (end)
2571 cnt++;
2572 }
2573 }
2574 // if(TIMETABLE_HTML_LEVEL==7){ // must be written before LEVEL 3, because LEVEL 3 should have higher priority
2575 // QHashIterator<QString, QString> i(hashColorStringIDsTimetable);
2576 // while(i.hasNext()) {
2577 // i.next();
2578 // tos << "td.c_"<<i.value()<<" { /* "<<i.key()<<" */\n ";
2579 //
2580 // //similar to the coloring by Marco Vassura (start)
2581 // int r, g, b;
2582 // stringToColor(i.key(), r, g, b);
2583 // tos<<"background-color: rgb("<<QString::number(r)<<", "<<QString::number(g)<<", "<<QString::number(b)<<");\n";
2584 // double brightness = double(r)*0.299 + double(g)*0.587 + double(b)*0.114;
2585 // if (brightness<127.5)
2586 // tos<<" color: white;\n";
2587 // else
2588 // tos<<" color: black;\n";
2589 // //similar to the coloring by Marco Vassura (end)
2590 // tos<<"}\n\n";
2591 // }
2592 // }
2593 else if(TIMETABLE_HTML_LEVEL>=4){ // must be written before LEVEL 3, because LEVEL 3 should have higher priority
2594 for(int i=0; i<gt.rules.nInternalSubjects; i++){
2595 tos << "span.s_"<<hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[i]->name)<<" { /* subject "<<gt.rules.internalSubjectsList[i]->name<<" */\n\n}\n\n";
2596 }
2597 for(int i=0; i<gt.rules.nInternalActivityTags; i++){
2598 if(gt.rules.internalActivityTagsList[i]->printable){
2599 tos << "span.at_"<<hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[i]->name)<<" { /* activity tag "<<gt.rules.internalActivityTagsList[i]->name<<" */\n\n}\n\n";
2600 }
2601 }
2602 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
2603 StudentsYear* sty=gt.rules.augmentedYearsList[i];
2604 if(usedStudents.contains(sty->name))
2605 tos << "span.ss_"<<hashStudentIDsTimetable.value(sty->name)<<" { /* students set "<<sty->name<<" */\n\n}\n\n";
2606 for(int j=0; j<sty->groupsList.size(); j++){
2607 StudentsGroup* stg=sty->groupsList[j];
2608 if(usedStudents.contains(stg->name))
2609 tos << "span.ss_"<<hashStudentIDsTimetable.value(stg->name)<<" { /* students set "<<stg->name<<" */\n\n}\n\n";
2610 for(int k=0; k<stg->subgroupsList.size(); k++){
2611 StudentsSubgroup* sts=stg->subgroupsList[k];
2612 if(usedStudents.contains(sts->name))
2613 tos << "span.ss_"<<hashStudentIDsTimetable.value(sts->name)<<" { /* students set "<<sts->name<<" */\n\n}\n\n";
2614 }
2615 }
2616 }
2617 for(int i=0; i<gt.rules.nInternalTeachers; i++){
2618 tos << "span.t_"<<hashTeacherIDsTimetable.value(gt.rules.internalTeachersList[i]->name)<<" { /* teacher "<<gt.rules.internalTeachersList[i]->name<<" */\n\n}\n\n";
2619 }
2620 for(int room=0; room<gt.rules.nInternalRooms; room++){
2621 tos << "span.r_"<<hashRoomIDsTimetable.value(gt.rules.internalRoomsList[room]->name)<<" { /* room "<<gt.rules.internalRoomsList[room]->name<<" */\n\n}\n\n";
2622 }
2623 }
2624 if(TIMETABLE_HTML_LEVEL>=3){
2625 tos<<"span.subject {\n\n}\n\n";
2626 tos<<"span.activitytag {\n\n}\n\n";
2627
2628 tos<<"span.empty {\n color: gray;\n}\n\n";
2629 tos<<"td.empty {\n border-color: silver;\n border-right-style: none;\n border-bottom-style: none;\n border-left-style: dotted;\n border-top-style: dotted;\n}\n\n";
2630
2631 tos<<"span.notAvailable {\n color: gray;\n}\n\n";
2632 tos<<"td.notAvailable {\n border-color: silver;\n border-right-style: none;\n border-bottom-style: none;\n border-left-style: dotted;\n border-top-style: dotted;\n}\n\n";
2633
2634 tos<<"span.break {\n color: gray;\n}\n\n";
2635 tos<<"td.break {\n border-color: silver;\n border-right-style: none;\n border-bottom-style: none;\n border-left-style: dotted;\n border-top-style: dotted;\n}\n\n";
2636
2637 tos<<"tr.studentsset, div.studentsset {\n\n}\n\n";
2638 tos<<"tr.teacher, div.teacher {\n\n}\n\n";
2639 tos<<"tr.room, div.room {\n\n}\n\n";
2640 if(TIMETABLE_HTML_LEVEL!=7){
2641 tos<<"tr.line0, div.line0 {\n font-size: smaller;\n}\n\n";
2642 tos<<"tr.line1, div.line1 {\n\n}\n\n";
2643 tos<<"tr.line2, div.line2 {\n font-size: smaller;\n color: gray;\n}\n\n";
2644 tos<<"tr.line3, div.line3 {\n font-size: smaller;\n color: silver;\n}\n\n";
2645 } else {
2646 tos<<"tr.line0, div.line0 {\n font-size: smaller;\n}\n\n";
2647 tos<<"tr.line1, div.line1 {\n\n}\n\n";
2648 tos<<"tr.line2, div.line2 {\n font-size: smaller;\n}\n\n";
2649 tos<<"tr.line3, div.line3 {\n font-size: smaller;\n}\n\n";
2650 }
2651 }
2652 if(TIMETABLE_HTML_LEVEL==6){
2653 tos<<"/* "<<TimetableExport::tr("Be careful. You might get mutual and ambiguous styles. CSS means that the last definition will be used.")<<" */\n\n";
2654 for(int i=0; i<gt.rules.nInternalSubjects; i++){
2655 tos << "td.s_"<<hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[i]->name)<<" { /* subject "<<gt.rules.internalSubjectsList[i]->name<<" */\n\n}\n\n";
2656 }
2657 for(int i=0; i<gt.rules.nInternalActivityTags; i++){
2658 if(gt.rules.internalActivityTagsList[i]->printable){
2659 tos << "td.at_"<<hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[i]->name)<<" { /* activity tag "<<gt.rules.internalActivityTagsList[i]->name<<" */\n\n}\n\n";
2660 }
2661 }
2662 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
2663 StudentsYear* sty=gt.rules.augmentedYearsList[i];
2664 if(usedStudents.contains(sty->name))
2665 tos << "td.ss_"<<hashStudentIDsTimetable.value(sty->name)<<" { /* students set "<<sty->name<<" */\n\n}\n\n";
2666 for(int j=0; j<sty->groupsList.size(); j++){
2667 StudentsGroup* stg=sty->groupsList[j];
2668 if(usedStudents.contains(stg->name))
2669 tos << "td.ss_"<<hashStudentIDsTimetable.value(stg->name)<<" { /* students set "<<stg->name<<" */\n\n}\n\n";
2670 for(int k=0; k<stg->subgroupsList.size(); k++){
2671 StudentsSubgroup* sts=stg->subgroupsList[k];
2672 if(usedStudents.contains(sts->name))
2673 tos << "td.ss_"<<hashStudentIDsTimetable.value(sts->name)<<" { /* students set "<<sts->name<<" */\n\n}\n\n";
2674 }
2675 }
2676 }
2677 for(int i=0; i<gt.rules.nInternalTeachers; i++){
2678 tos << "td.t_"<<hashTeacherIDsTimetable.value(gt.rules.internalTeachersList[i]->name)<<" { /* teacher "<<gt.rules.internalTeachersList[i]->name<<" */\n\n}\n\n";
2679 }
2680
2681 //not included yet
2682 //for(int room=0; room<gt.rules.nInternalRooms; room++){
2683 // tos << "span.r_"<<hashRoomIDsTimetable.value(gt.rules.internalRoomsList[room]->name)<<" { /* room "<<gt.rules.internalRoomsList[room]->name<<" */\n\n}\n\n";
2684 //}
2685 }
2686 tos<<"/* "<<TimetableExport::tr("Style the teachers' free periods")<<" */\n\n";
2687 if(TIMETABLE_HTML_LEVEL>=2){
2688 tos<<"div.DESCRIPTION {\n text-align: left;\n font-size: smaller;\n}\n\n";
2689 }
2690 if(TIMETABLE_HTML_LEVEL>=3){
2691 tos<<"div.TEACHER_HAS_SINGLE_GAP {\n color: black;\n}\n\n";
2692 tos<<"div.TEACHER_HAS_BORDER_GAP {\n color: gray;\n}\n\n";
2693 tos<<"div.TEACHER_HAS_BIG_GAP {\n color: silver;\n}\n\n";
2694 tos<<"div.TEACHER_MUST_COME_EARLIER {\n color: purple;\n}\n\n";
2695 tos<<"div.TEACHER_MUST_COME_MUCH_EARLIER {\n font-size: smaller;\n color: fuchsia;\n}\n\n";
2696 tos<<"div.TEACHER_MUST_STAY_LONGER {\n color: teal;\n}\n\n";
2697 tos<<"div.TEACHER_MUST_STAY_MUCH_LONGER {\n font-size: smaller;\n color: aqua;\n}\n\n";
2698 tos<<"div.TEACHER_HAS_A_FREE_DAY {\n font-size: smaller;\n color: red;\n}\n\n";
2699 tos<<"div.TEACHER_IS_NOT_AVAILABLE {\n font-size: smaller;\n color: olive;\n}\n\n";
2700 }
2701 tos<<"/* "<<TimetableExport::tr("End of file.")<<" */\n";
2702
2703 if(file.error()>0){
2704 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2705 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(cssfilename).arg(file.error()));
2706 }
2707 file.close();
2708 }
2709
2710 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeSubgroupsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2711 void TimetableExport::writeSubgroupsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2712 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2713 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2714
2715 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_SUBGROUPS){
2716 if(QFile::exists(htmlfilename))
2717 QFile::remove(htmlfilename);
2718
2719 return;
2720 }
2721
2722 //Now we print the results to an HTML file
2723 QFile file(htmlfilename);
2724 if(!file.open(QIODevice::WriteOnly)){
2725 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2726 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2727 return;
2728 }
2729 QTextStream tos(&file);
2730 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2731 tos.setEncoding(QStringConverter::Utf8);
2732 #else
2733 tos.setCodec("UTF-8");
2734 #endif
2735 tos.setGenerateByteOrderMark(true);
2736
2737 tos<<writeHead(true, placedActivities, true);
2738
2739 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
2740 tos<<" <ul>\n";
2741 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
2742 StudentsYear* sty=gt.rules.augmentedYearsList[i];
2743 tos<<" <li>\n "<<TimetableExport::tr("Year")<<" "<<protect2(sty->name)<<"\n <ul>\n";
2744 for(int j=0; j<sty->groupsList.size(); j++){
2745 StudentsGroup* stg=sty->groupsList[j];
2746 tos<<" <li>\n "<<TimetableExport::tr("Group")<<" "<<protect2(stg->name)<<":\n";
2747 for(int k=0; k<stg->subgroupsList.size(); k++){
2748 StudentsSubgroup* sts=stg->subgroupsList[k];
2749 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(sts->name)<<"\">"<<protect2(sts->name)<<"</a>\n";
2750 }
2751 tos<<" </li>\n";
2752 }
2753 tos<<" </ul>\n </li>\n";
2754 }
2755 tos<<" </ul>\n <p> </p>\n\n";
2756
2757 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
2758 tos<<singleSubgroupsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, subgroup, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2759 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
2760 }
2761 tos<<" </body>\n</html>\n";
2762
2763 if(file.error()>0){
2764 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2765 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2766 }
2767 file.close();
2768 }
2769
2770 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeSubgroupsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2771 void TimetableExport::writeSubgroupsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2772 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2773 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2774
2775 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_SUBGROUPS){
2776 if(QFile::exists(htmlfilename))
2777 QFile::remove(htmlfilename);
2778
2779 return;
2780 }
2781
2782 //Now we print the results to an HTML file
2783 QFile file(htmlfilename);
2784 if(!file.open(QIODevice::WriteOnly)){
2785 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2786 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2787 return;
2788 }
2789 QTextStream tos(&file);
2790 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2791 tos.setEncoding(QStringConverter::Utf8);
2792 #else
2793 tos.setCodec("UTF-8");
2794 #endif
2795 tos.setGenerateByteOrderMark(true);
2796
2797 tos<<writeHead(true, placedActivities, true);
2798
2799 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
2800 tos<<" <ul>\n";
2801 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
2802 StudentsYear* sty=gt.rules.augmentedYearsList[i];
2803 tos<<" <li>\n "<<TimetableExport::tr("Year")<<" "<<protect2(sty->name)<<"\n <ul>\n";
2804 for(int j=0; j<sty->groupsList.size(); j++){
2805 StudentsGroup* stg=sty->groupsList[j];
2806 tos<<" <li>\n "<<TimetableExport::tr("Group")<<" "<<protect2(stg->name)<<":\n";
2807 for(int k=0; k<stg->subgroupsList.size(); k++){
2808 StudentsSubgroup* sts=stg->subgroupsList[k];
2809 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(sts->name)<<"\">"<<protect2(sts->name)<<"</a>\n";
2810 }
2811 tos<<" </li>\n";
2812 }
2813 tos<<" </ul>\n </li>\n";
2814 }
2815 tos<<" </ul>\n <p> </p>\n";
2816
2817 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
2818 tos<<singleSubgroupsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, subgroup, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2819 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
2820 }
2821
2822 tos<<" </body>\n</html>\n";
2823
2824 if(file.error()>0){
2825 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2826 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2827 }
2828 file.close();
2829 }
2830
2831 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubgroupsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2832 void TimetableExport::writeSubgroupsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2833 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2834 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2835
2836 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_SUBGROUPS){
2837 if(QFile::exists(htmlfilename))
2838 QFile::remove(htmlfilename);
2839
2840 return;
2841 }
2842
2843 //Now we print the results to an HTML file
2844 QFile file(htmlfilename);
2845 if(!file.open(QIODevice::WriteOnly)){
2846 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2847 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2848 return;
2849 }
2850 QTextStream tos(&file);
2851 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2852 tos.setEncoding(QStringConverter::Utf8);
2853 #else
2854 tos.setCodec("UTF-8");
2855 #endif
2856 tos.setGenerateByteOrderMark(true);
2857
2858 tos<<writeHead(true, placedActivities, false);
2859
2860 QSet<int> tmp;
2861 tos << singleSubgroupsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalSubgroups, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2862
2863 tos << " </body>\n</html>\n";
2864
2865 if(file.error()>0){
2866 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2867 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2868 }
2869 file.close();
2870 }
2871
2872 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeSubgroupsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2873 void TimetableExport::writeSubgroupsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2874 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2875 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2876
2877 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_SUBGROUPS){
2878 if(QFile::exists(htmlfilename))
2879 QFile::remove(htmlfilename);
2880
2881 return;
2882 }
2883
2884 //Now we print the results to an HTML file
2885 QFile file(htmlfilename);
2886 if(!file.open(QIODevice::WriteOnly)){
2887 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2888 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2889 return;
2890 }
2891 QTextStream tos(&file);
2892 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2893 tos.setEncoding(QStringConverter::Utf8);
2894 #else
2895 tos.setCodec("UTF-8");
2896 #endif
2897 tos.setGenerateByteOrderMark(true);
2898
2899 tos<<writeHead(true, placedActivities, false);
2900
2901 QSet<int> tmp;
2902 tos << singleSubgroupsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalSubgroups, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2903
2904 tos << " </body>\n</html>\n";
2905
2906 if(file.error()>0){
2907 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2908 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2909 }
2910 file.close();
2911 }
2912
2913 // by Volker Dirr
writeSubgroupsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2914 void TimetableExport::writeSubgroupsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2915 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2916 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2917
2918 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_SUBGROUPS){
2919 if(QFile::exists(htmlfilename))
2920 QFile::remove(htmlfilename);
2921
2922 return;
2923 }
2924
2925 //Now we print the results to an HTML file
2926 QFile file(htmlfilename);
2927 if(!file.open(QIODevice::WriteOnly)){
2928 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2929 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2930 return;
2931 }
2932 QTextStream tos(&file);
2933 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2934 tos.setEncoding(QStringConverter::Utf8);
2935 #else
2936 tos.setCodec("UTF-8");
2937 #endif
2938 tos.setGenerateByteOrderMark(true);
2939
2940 tos<<writeHead(true, placedActivities, true);
2941 tos<<writeTOCDays();
2942
2943 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
2944 QSet<int> tmp;
2945 tos<<singleSubgroupsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalSubgroups, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2946 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
2947 }
2948
2949 tos << " </body>\n</html>\n";
2950
2951 if(file.error()>0){
2952 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2953 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2954 }
2955 file.close();
2956 }
2957
2958 // by Volker Dirr
writeSubgroupsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities,const QList<int> & subgroupsSortedOrder)2959 void TimetableExport::writeSubgroupsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities, const QList<int>& subgroupsSortedOrder){
2960 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
2961 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
2962
2963 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_SUBGROUPS){
2964 if(QFile::exists(htmlfilename))
2965 QFile::remove(htmlfilename);
2966
2967 return;
2968 }
2969
2970 //Now we print the results to an HTML file
2971 QFile file(htmlfilename);
2972 if(!file.open(QIODevice::WriteOnly)){
2973 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2974 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
2975 return;
2976 }
2977 QTextStream tos(&file);
2978 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
2979 tos.setEncoding(QStringConverter::Utf8);
2980 #else
2981 tos.setCodec("UTF-8");
2982 #endif
2983 tos.setGenerateByteOrderMark(true);
2984
2985 tos<<writeHead(true, placedActivities, true);
2986 tos<<writeTOCDays();
2987
2988 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
2989 QSet<int> tmp;
2990 tos<<singleSubgroupsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalSubgroups, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES, subgroupsSortedOrder);
2991 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
2992 }
2993 tos << " </body>\n</html>\n";
2994
2995 if(file.error()>0){
2996 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
2997 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
2998 }
2999 file.close();
3000 }
3001
3002 //Now print the groups
3003 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3004 void TimetableExport::writeGroupsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3005 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3006 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3007
3008 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_GROUPS){
3009 if(QFile::exists(htmlfilename))
3010 QFile::remove(htmlfilename);
3011
3012 return;
3013 }
3014
3015 //Now we print the results to an HTML file
3016 QFile file(htmlfilename);
3017 if(!file.open(QIODevice::WriteOnly)){
3018 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3019 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3020 return;
3021 }
3022 QTextStream tos(&file);
3023 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3024 tos.setEncoding(QStringConverter::Utf8);
3025 #else
3026 tos.setCodec("UTF-8");
3027 #endif
3028 tos.setGenerateByteOrderMark(true);
3029
3030 tos<<writeHead(true, placedActivities, true);
3031
3032 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3033 tos<<" <ul>\n";
3034 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
3035 StudentsYear* sty=gt.rules.augmentedYearsList[i];
3036 tos<<" <li>\n "<<TimetableExport::tr("Year")<<" "<<protect2(sty->name)<<"\n <ul>\n";
3037 for(int j=0; j<sty->groupsList.size(); j++){
3038 StudentsGroup* stg=sty->groupsList[j];
3039 tos<<" <li>\n "<<TimetableExport::tr("Group");
3040 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(stg->name)<<"\">"<<protect2(stg->name)<<"</a>\n";
3041 tos<<" </li>\n";
3042 }
3043 tos<<" </ul>\n </li>\n";
3044 }
3045 tos<<" </ul>\n <p> </p>\n\n";
3046
3047 for(int group=0; group<gt.rules.internalGroupsList.size(); group++){
3048 tos << singleGroupsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, group, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3049 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3050 }
3051
3052 tos<<" </body>\n</html>\n";
3053
3054 if(file.error()>0){
3055 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3056 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3057 }
3058 file.close();
3059 }
3060
3061 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3062 void TimetableExport::writeGroupsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3063 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3064 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3065
3066 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_GROUPS){
3067 if(QFile::exists(htmlfilename))
3068 QFile::remove(htmlfilename);
3069
3070 return;
3071 }
3072
3073 //Now we print the results to an HTML file
3074 QFile file(htmlfilename);
3075 if(!file.open(QIODevice::WriteOnly)){
3076 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3077 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3078 return;
3079 }
3080 QTextStream tos(&file);
3081 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3082 tos.setEncoding(QStringConverter::Utf8);
3083 #else
3084 tos.setCodec("UTF-8");
3085 #endif
3086 tos.setGenerateByteOrderMark(true);
3087
3088 tos<<writeHead(true, placedActivities, true);
3089
3090 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3091 tos<<" <ul>\n";
3092 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
3093 StudentsYear* sty=gt.rules.augmentedYearsList[i];
3094 tos<<" <li>\n "<<TimetableExport::tr("Year")<<" "<<protect2(sty->name)<<"\n <ul>\n";
3095 for(int j=0; j<sty->groupsList.size(); j++){
3096 StudentsGroup* stg=sty->groupsList[j];
3097 tos<<" <li>\n "<<TimetableExport::tr("Group");
3098 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(stg->name)<<"\">"<<protect2(stg->name)<<"</a>\n";
3099 tos<<" </li>\n";
3100 }
3101 tos<<" </ul>\n </li>\n";
3102 }
3103 tos<<" </ul>\n <p> </p>\n";
3104
3105 for(int group=0; group<gt.rules.internalGroupsList.size(); group++){
3106 tos<<singleGroupsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, group, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3107 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3108 }
3109
3110 tos<<" </body>\n</html>\n";
3111
3112 if(file.error()>0){
3113 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3114 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3115 }
3116 file.close();
3117 }
3118
3119 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3120 void TimetableExport::writeGroupsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3121 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3122 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3123
3124 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_GROUPS){
3125 if(QFile::exists(htmlfilename))
3126 QFile::remove(htmlfilename);
3127
3128 return;
3129 }
3130
3131 //Now we print the results to an HTML file
3132 QFile file(htmlfilename);
3133 if(!file.open(QIODevice::WriteOnly)){
3134 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3135 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3136 return;
3137 }
3138 QTextStream tos(&file);
3139 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3140 tos.setEncoding(QStringConverter::Utf8);
3141 #else
3142 tos.setCodec("UTF-8");
3143 #endif
3144 tos.setGenerateByteOrderMark(true);
3145
3146 tos<<writeHead(true, placedActivities, false);
3147
3148 QSet<int> tmp;
3149 tos<<singleGroupsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.internalGroupsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3150
3151 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3152
3153 tos << " </body>\n</html>\n";
3154
3155 if(file.error()>0){
3156 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3157 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3158 }
3159 file.close();
3160 }
3161
3162 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3163 void TimetableExport::writeGroupsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3164 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3165 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3166
3167 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_GROUPS){
3168 if(QFile::exists(htmlfilename))
3169 QFile::remove(htmlfilename);
3170
3171 return;
3172 }
3173
3174 //Now we print the results to an HTML file
3175 QFile file(htmlfilename);
3176 if(!file.open(QIODevice::WriteOnly)){
3177 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3178 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3179 return;
3180 }
3181 QTextStream tos(&file);
3182 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3183 tos.setEncoding(QStringConverter::Utf8);
3184 #else
3185 tos.setCodec("UTF-8");
3186 #endif
3187 tos.setGenerateByteOrderMark(true);
3188
3189 tos<<writeHead(true, placedActivities, false);
3190
3191 QSet<int> tmp;
3192 tos<<singleGroupsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.internalGroupsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3193 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3194
3195 tos << " </body>\n</html>\n";
3196
3197 if(file.error()>0){
3198 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3199 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3200 }
3201 file.close();
3202 }
3203
3204 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3205 void TimetableExport::writeGroupsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3206 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3207 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3208
3209 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_GROUPS){
3210 if(QFile::exists(htmlfilename))
3211 QFile::remove(htmlfilename);
3212
3213 return;
3214 }
3215
3216 //Now we print the results to an HTML file
3217 QFile file(htmlfilename);
3218 if(!file.open(QIODevice::WriteOnly)){
3219 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3220 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3221 return;
3222 }
3223 QTextStream tos(&file);
3224 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3225 tos.setEncoding(QStringConverter::Utf8);
3226 #else
3227 tos.setCodec("UTF-8");
3228 #endif
3229 tos.setGenerateByteOrderMark(true);
3230
3231 tos<<writeHead(true, placedActivities, true);
3232 tos<<writeTOCDays();
3233
3234 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3235 QSet<int> tmp;
3236 tos<<singleGroupsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.internalGroupsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3237 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3238 }
3239
3240 tos << " </body>\n</html>\n";
3241
3242 if(file.error()>0){
3243 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3244 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3245 }
3246 file.close();
3247 }
3248
3249 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeGroupsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3250 void TimetableExport::writeGroupsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3251 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3252 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3253
3254 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_GROUPS){
3255 if(QFile::exists(htmlfilename))
3256 QFile::remove(htmlfilename);
3257
3258 return;
3259 }
3260
3261 //Now we print the results to an HTML file
3262 QFile file(htmlfilename);
3263 if(!file.open(QIODevice::WriteOnly)){
3264 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3265 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3266 return;
3267 }
3268 QTextStream tos(&file);
3269 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3270 tos.setEncoding(QStringConverter::Utf8);
3271 #else
3272 tos.setCodec("UTF-8");
3273 #endif
3274 tos.setGenerateByteOrderMark(true);
3275
3276 tos<<writeHead(true, placedActivities, true);
3277 tos<<writeTOCDays();
3278
3279 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3280 QSet<int> tmp;
3281 tos<<singleGroupsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.internalGroupsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3282 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3283 }
3284
3285 tos << " </body>\n</html>\n";
3286
3287 if(file.error()>0){
3288 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3289 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3290 }
3291 file.close();
3292 }
3293
3294 //Now print the years
3295
3296 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3297 void TimetableExport::writeYearsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3298 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3299 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3300
3301 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_YEARS){
3302 if(QFile::exists(htmlfilename))
3303 QFile::remove(htmlfilename);
3304
3305 return;
3306 }
3307
3308 //Now we print the results to an HTML file
3309 QFile file(htmlfilename);
3310 if(!file.open(QIODevice::WriteOnly)){
3311 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3312 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3313 return;
3314 }
3315 QTextStream tos(&file);
3316 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3317 tos.setEncoding(QStringConverter::Utf8);
3318 #else
3319 tos.setCodec("UTF-8");
3320 #endif
3321 tos.setGenerateByteOrderMark(true);
3322
3323 tos<<writeHead(true, placedActivities, true);
3324
3325 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3326 tos<<" <ul>\n";
3327 for(int year=0; year<gt.rules.augmentedYearsList.size(); year++){
3328 StudentsYear* sty=gt.rules.augmentedYearsList[year];
3329 tos<<" <li>\n "<<TimetableExport::tr("Year");
3330 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(sty->name)<<"\">"<<protect2(sty->name)<<"</a>\n";
3331 tos<<" </li>\n";
3332 }
3333 tos<<" </ul>\n <p> </p>\n\n";
3334
3335 for(int year=0; year<gt.rules.augmentedYearsList.size(); year++){
3336 tos << singleYearsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, year, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3337 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3338 }
3339
3340 tos<<" </body>\n</html>\n";
3341
3342 if(file.error()>0){
3343 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3344 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3345 }
3346 file.close();
3347 }
3348
3349 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3350 void TimetableExport::writeYearsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3351 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3352 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3353
3354 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_YEARS){
3355 if(QFile::exists(htmlfilename))
3356 QFile::remove(htmlfilename);
3357
3358 return;
3359 }
3360
3361 //Now we print the results to an HTML file
3362 QFile file(htmlfilename);
3363 if(!file.open(QIODevice::WriteOnly)){
3364 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3365 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3366 return;
3367 }
3368 QTextStream tos(&file);
3369 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3370 tos.setEncoding(QStringConverter::Utf8);
3371 #else
3372 tos.setCodec("UTF-8");
3373 #endif
3374 tos.setGenerateByteOrderMark(true);
3375
3376 tos<<writeHead(true, placedActivities, true);
3377
3378 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3379 tos<<" <ul>\n";
3380 for(int year=0; year<gt.rules.augmentedYearsList.size(); year++){
3381 StudentsYear* sty=gt.rules.augmentedYearsList[year];
3382 tos<<" <li>\n "<<TimetableExport::tr("Year");
3383 tos<<" <a href=\""<<"#table_"<<hashStudentIDsTimetable.value(sty->name)<<"\">"<<protect2(sty->name)<<"</a>\n";
3384 tos<<" </li>\n";
3385 }
3386 tos<<" </ul>\n <p> </p>\n\n";
3387
3388 for(int year=0; year<gt.rules.augmentedYearsList.size(); year++){
3389 tos << singleYearsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, year, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3390 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3391 }
3392
3393 tos<<" </body>\n</html>\n";
3394
3395 if(file.error()>0){
3396 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3397 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3398 }
3399 file.close();
3400 }
3401
3402 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3403 void TimetableExport::writeYearsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3404 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3405 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3406
3407 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_YEARS){
3408 if(QFile::exists(htmlfilename))
3409 QFile::remove(htmlfilename);
3410
3411 return;
3412 }
3413
3414 //Now we print the results to an HTML file
3415 QFile file(htmlfilename);
3416 if(!file.open(QIODevice::WriteOnly)){
3417 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3418 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3419 return;
3420 }
3421 QTextStream tos(&file);
3422 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3423 tos.setEncoding(QStringConverter::Utf8);
3424 #else
3425 tos.setCodec("UTF-8");
3426 #endif
3427 tos.setGenerateByteOrderMark(true);
3428
3429 tos<<writeHead(true, placedActivities, false);
3430
3431 QSet<int> tmp;
3432 tos<<singleYearsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.augmentedYearsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3433
3434 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3435
3436 tos << " </body>\n</html>\n";
3437
3438 if(file.error()>0){
3439 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3440 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3441 }
3442 file.close();
3443 }
3444
3445 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3446 void TimetableExport::writeYearsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3447 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3448 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3449
3450 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_YEARS){
3451 if(QFile::exists(htmlfilename))
3452 QFile::remove(htmlfilename);
3453
3454 return;
3455 }
3456
3457 //Now we print the results to an HTML file
3458 QFile file(htmlfilename);
3459 if(!file.open(QIODevice::WriteOnly)){
3460 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3461 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3462 return;
3463 }
3464 QTextStream tos(&file);
3465 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3466 tos.setEncoding(QStringConverter::Utf8);
3467 #else
3468 tos.setCodec("UTF-8");
3469 #endif
3470 tos.setGenerateByteOrderMark(true);
3471
3472 tos<<writeHead(true, placedActivities, false);
3473
3474 QSet<int> tmp;
3475 tos<<singleYearsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.augmentedYearsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3476
3477 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3478
3479 tos << " </body>\n</html>\n";
3480
3481 if(file.error()>0){
3482 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3483 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3484 }
3485 file.close();
3486 }
3487
3488 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3489 void TimetableExport::writeYearsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3490 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3491 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3492
3493 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_YEARS){
3494 if(QFile::exists(htmlfilename))
3495 QFile::remove(htmlfilename);
3496
3497 return;
3498 }
3499
3500 //Now we print the results to an HTML file
3501 QFile file(htmlfilename);
3502 if(!file.open(QIODevice::WriteOnly)){
3503 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3504 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3505 return;
3506 }
3507 QTextStream tos(&file);
3508 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3509 tos.setEncoding(QStringConverter::Utf8);
3510 #else
3511 tos.setCodec("UTF-8");
3512 #endif
3513 tos.setGenerateByteOrderMark(true);
3514
3515 tos<<writeHead(true, placedActivities, true);
3516 tos<<writeTOCDays();
3517
3518 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3519 QSet<int> tmp;
3520 tos<<singleYearsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.augmentedYearsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3521 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3522 }
3523
3524 tos << " </body>\n</html>\n";
3525
3526 if(file.error()>0){
3527 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3528 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3529 }
3530 file.close();
3531 }
3532
3533 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeYearsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3534 void TimetableExport::writeYearsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3535 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3536 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3537
3538 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_YEARS){
3539 if(QFile::exists(htmlfilename))
3540 QFile::remove(htmlfilename);
3541
3542 return;
3543 }
3544
3545 //Now we print the results to an HTML file
3546 QFile file(htmlfilename);
3547 if(!file.open(QIODevice::WriteOnly)){
3548 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3549 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3550 return;
3551 }
3552 QTextStream tos(&file);
3553 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3554 tos.setEncoding(QStringConverter::Utf8);
3555 #else
3556 tos.setCodec("UTF-8");
3557 #endif
3558 tos.setGenerateByteOrderMark(true);
3559
3560 tos<<writeHead(true, placedActivities, true);
3561 tos<<writeTOCDays();
3562
3563 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3564 QSet<int> tmp;
3565 tos<<singleYearsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.augmentedYearsList.size(), tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, PRINT_DETAILED_HTML_TIMETABLES, TIMETABLE_HTML_REPEAT_NAMES);
3566 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3567 }
3568
3569 tos << " </body>\n</html>\n";
3570
3571 if(file.error()>0){
3572 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3573 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3574 }
3575 file.close();
3576 }
3577
3578 //Print all activities
3579
3580 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3581 void TimetableExport::writeAllActivitiesTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3582 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3583 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3584
3585 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITIES){
3586 if(QFile::exists(htmlfilename))
3587 QFile::remove(htmlfilename);
3588
3589 return;
3590 }
3591
3592 //Now we print the results to an HTML file
3593 QFile file(htmlfilename);
3594 if(!file.open(QIODevice::WriteOnly)){
3595 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3596 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3597 return;
3598 }
3599 QTextStream tos(&file);
3600 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3601 tos.setEncoding(QStringConverter::Utf8);
3602 #else
3603 tos.setCodec("UTF-8");
3604 #endif
3605 tos.setGenerateByteOrderMark(true);
3606
3607 tos<<writeHead(true, placedActivities, true);
3608 tos<<singleAllActivitiesTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3609 tos<<" </body>\n</html>\n";
3610
3611 if(file.error()>0){
3612 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3613 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3614 }
3615 file.close();
3616 }
3617
3618 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3619 void TimetableExport::writeAllActivitiesTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3620 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3621 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3622
3623 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_ACTIVITIES){
3624 if(QFile::exists(htmlfilename))
3625 QFile::remove(htmlfilename);
3626
3627 return;
3628 }
3629
3630 //Now we print the results to an HTML file
3631 QFile file(htmlfilename);
3632 if(!file.open(QIODevice::WriteOnly)){
3633 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3634 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3635 return;
3636 }
3637 QTextStream tos(&file);
3638 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3639 tos.setEncoding(QStringConverter::Utf8);
3640 #else
3641 tos.setCodec("UTF-8");
3642 #endif
3643 tos.setGenerateByteOrderMark(true);
3644
3645 tos<<writeHead(true, placedActivities, true);
3646 tos<<singleAllActivitiesTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3647 tos<<" </body>\n</html>\n";
3648
3649 if(file.error()>0){
3650 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3651 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3652 }
3653 file.close();
3654 }
3655
3656 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3657 void TimetableExport::writeAllActivitiesTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3658 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3659 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3660
3661 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ACTIVITIES){
3662 if(QFile::exists(htmlfilename))
3663 QFile::remove(htmlfilename);
3664
3665 return;
3666 }
3667
3668 //Now we print the results to an HTML file
3669 QFile file(htmlfilename);
3670 if(!file.open(QIODevice::WriteOnly)){
3671 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3672 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3673 return;
3674 }
3675 QTextStream tos(&file);
3676 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3677 tos.setEncoding(QStringConverter::Utf8);
3678 #else
3679 tos.setCodec("UTF-8");
3680 #endif
3681 tos.setGenerateByteOrderMark(true);
3682
3683 tos<<writeHead(true, placedActivities, false);
3684
3685 tos<<singleAllActivitiesTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3686
3687 tos<<" </body>\n</html>\n";
3688
3689 if(file.error()>0){
3690 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3691 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3692 }
3693 file.close();
3694 }
3695
3696 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3697 void TimetableExport::writeAllActivitiesTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3698 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3699 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3700
3701 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITIES){
3702 if(QFile::exists(htmlfilename))
3703 QFile::remove(htmlfilename);
3704
3705 return;
3706 }
3707
3708 //Now we print the results to an HTML file
3709 QFile file(htmlfilename);
3710 if(!file.open(QIODevice::WriteOnly)){
3711 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3712 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3713 return;
3714 }
3715 QTextStream tos(&file);
3716 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3717 tos.setEncoding(QStringConverter::Utf8);
3718 #else
3719 tos.setCodec("UTF-8");
3720 #endif
3721 tos.setGenerateByteOrderMark(true);
3722
3723 tos<<writeHead(true, placedActivities, false);
3724
3725 tos<<singleAllActivitiesTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3726
3727 tos<<" </body>\n</html>\n";
3728
3729 if(file.error()>0){
3730 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3731 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3732 }
3733 file.close();
3734 }
3735
3736 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3737 void TimetableExport::writeAllActivitiesTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3738 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3739 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3740
3741 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ACTIVITIES){
3742 if(QFile::exists(htmlfilename))
3743 QFile::remove(htmlfilename);
3744
3745 return;
3746 }
3747
3748 //Now we print the results to an HTML file
3749 QFile file(htmlfilename);
3750 if(!file.open(QIODevice::WriteOnly)){
3751 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3752 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3753 return;
3754 }
3755 QTextStream tos(&file);
3756 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3757 tos.setEncoding(QStringConverter::Utf8);
3758 #else
3759 tos.setCodec("UTF-8");
3760 #endif
3761 tos.setGenerateByteOrderMark(true);
3762
3763 tos<<writeHead(true, placedActivities, true);
3764 tos<<writeTOCDays();
3765
3766 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3767 tos<<singleAllActivitiesTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3768 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3769 }
3770 tos<<" </body>\n</html>\n";
3771
3772 if(file.error()>0){
3773 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3774 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3775 }
3776 file.close();
3777 }
3778
3779 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeAllActivitiesTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3780 void TimetableExport::writeAllActivitiesTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3781 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3782 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3783
3784 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITIES){
3785 if(QFile::exists(htmlfilename))
3786 QFile::remove(htmlfilename);
3787
3788 return;
3789 }
3790
3791 //Now we print the results to an HTML file
3792 QFile file(htmlfilename);
3793 if(!file.open(QIODevice::WriteOnly)){
3794 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3795 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3796 return;
3797 }
3798 QTextStream tos(&file);
3799 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3800 tos.setEncoding(QStringConverter::Utf8);
3801 #else
3802 tos.setCodec("UTF-8");
3803 #endif
3804 tos.setGenerateByteOrderMark(true);
3805
3806 tos<<writeHead(true, placedActivities, true);
3807 tos<<writeTOCDays();
3808
3809 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
3810 tos<<singleAllActivitiesTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3811
3812 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3813 }
3814
3815 tos<<" </body>\n</html>\n";
3816
3817 if(file.error()>0){
3818 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3819 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3820 }
3821 file.close();
3822 }
3823
3824 //Print the teachers
3825
3826 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeTeachersTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3827 void TimetableExport::writeTeachersTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3828 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3829 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3830
3831 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_TEACHERS){
3832 if(QFile::exists(htmlfilename))
3833 QFile::remove(htmlfilename);
3834
3835 return;
3836 }
3837
3838 //Now we print the results to an HTML file
3839 QFile file(htmlfilename);
3840 if(!file.open(QIODevice::WriteOnly)){
3841 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3842 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3843 return;
3844 }
3845 QTextStream tos(&file);
3846 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3847 tos.setEncoding(QStringConverter::Utf8);
3848 #else
3849 tos.setCodec("UTF-8");
3850 #endif
3851 tos.setGenerateByteOrderMark(true);
3852
3853 tos<<writeHead(true, placedActivities, true);
3854
3855 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3856 tos<<" <ul>\n";
3857 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
3858 QString teacher_name = gt.rules.internalTeachersList[teacher]->name;
3859 tos<<" <li><a href=\""<<"#table_"<<hashTeacherIDsTimetable.value(teacher_name)<<"\">"<<protect2(teacher_name)<<"</a></li>\n";
3860 }
3861 tos<<" </ul>\n <p> </p>\n\n";
3862
3863 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
3864 tos<<singleTeachersTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, teacher, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3865
3866 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3867 }
3868 tos<<" </body>\n</html>\n";
3869
3870 if(file.error()>0){
3871 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3872 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3873 }
3874 file.close();
3875 }
3876
3877 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeTeachersTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3878 void TimetableExport::writeTeachersTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3879 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3880 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3881
3882 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_TEACHERS){
3883 if(QFile::exists(htmlfilename))
3884 QFile::remove(htmlfilename);
3885
3886 return;
3887 }
3888
3889 //Now we print the results to an HTML file
3890 QFile file(htmlfilename);
3891 if(!file.open(QIODevice::WriteOnly)){
3892 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3893 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3894 return;
3895 }
3896 QTextStream tos(&file);
3897 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3898 tos.setEncoding(QStringConverter::Utf8);
3899 #else
3900 tos.setCodec("UTF-8");
3901 #endif
3902 tos.setGenerateByteOrderMark(true);
3903
3904 tos<<writeHead(true, placedActivities, true);
3905
3906 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
3907 tos<<" <ul>\n";
3908 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
3909 QString teacher_name = gt.rules.internalTeachersList[teacher]->name;
3910 tos<<" <li><a href=\""<<"#table_"<<hashTeacherIDsTimetable.value(teacher_name)<<"\">"<<protect2(teacher_name)<<"</a></li>\n";
3911 }
3912 tos<<" </ul>\n <p> </p>\n\n";
3913
3914 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
3915 tos<<singleTeachersTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, teacher, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3916 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
3917 }
3918 tos<<" </body>\n</html>\n";
3919
3920 if(file.error()>0){
3921 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3922 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3923 }
3924 file.close();
3925 }
3926
3927 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeTeachersTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3928 void TimetableExport::writeTeachersTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3929 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3930 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3931
3932 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_TEACHERS){
3933 if(QFile::exists(htmlfilename))
3934 QFile::remove(htmlfilename);
3935
3936 return;
3937 }
3938
3939 //Now we print the results to an HTML file
3940 QFile file(htmlfilename);
3941 if(!file.open(QIODevice::WriteOnly)){
3942 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3943 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3944 return;
3945 }
3946 QTextStream tos(&file);
3947 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3948 tos.setEncoding(QStringConverter::Utf8);
3949 #else
3950 tos.setCodec("UTF-8");
3951 #endif
3952 tos.setGenerateByteOrderMark(true);
3953
3954 tos<<writeHead(true, placedActivities, false);
3955 QSet<int> tmp;
3956 tos<<singleTeachersTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalTeachers, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3957 tos << " </body>\n</html>\n";
3958
3959 if(file.error()>0){
3960 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3961 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
3962 }
3963 file.close();
3964 }
3965
3966 //XHTML generation code modified by Volker Dirr (timetabling.de) from old html generation code
writeTeachersTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)3967 void TimetableExport::writeTeachersTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
3968 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
3969 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
3970
3971 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_TEACHERS){
3972 if(QFile::exists(htmlfilename))
3973 QFile::remove(htmlfilename);
3974
3975 return;
3976 }
3977
3978 //Now we print the results to an HTML file
3979 QFile file(htmlfilename);
3980 if(!file.open(QIODevice::WriteOnly)){
3981 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
3982 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
3983 return;
3984 }
3985 QTextStream tos(&file);
3986 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
3987 tos.setEncoding(QStringConverter::Utf8);
3988 #else
3989 tos.setCodec("UTF-8");
3990 #endif
3991 tos.setGenerateByteOrderMark(true);
3992
3993 tos<<writeHead(true, placedActivities, false);
3994 QSet<int> tmp;
3995 tos<<singleTeachersTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalTeachers, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
3996 tos << " </body>\n</html>\n";
3997
3998 if(file.error()>0){
3999 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4000 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4001 }
4002 file.close();
4003 }
4004
4005 //by Volker Dirr
writeTeachersTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4006 void TimetableExport::writeTeachersTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4007 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4008 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4009
4010 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_TEACHERS){
4011 if(QFile::exists(htmlfilename))
4012 QFile::remove(htmlfilename);
4013
4014 return;
4015 }
4016
4017 //Now we print the results to an HTML file
4018 QFile file(htmlfilename);
4019 if(!file.open(QIODevice::WriteOnly)){
4020 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4021 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4022 return;
4023 }
4024 QTextStream tos(&file);
4025 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4026 tos.setEncoding(QStringConverter::Utf8);
4027 #else
4028 tos.setCodec("UTF-8");
4029 #endif
4030 tos.setGenerateByteOrderMark(true);
4031
4032 tos<<writeHead(true, placedActivities, true);
4033 tos<<writeTOCDays();
4034
4035 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4036 QSet<int> tmp;
4037 tos<<singleTeachersTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalTeachers, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4038 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4039 }
4040 tos << " </body>\n</html>\n";
4041
4042 if(file.error()>0){
4043 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4044 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4045 }
4046 file.close();
4047 }
4048
4049 //by Volker Dirr
writeTeachersTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4050 void TimetableExport::writeTeachersTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4051 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4052 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4053
4054 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_TEACHERS){
4055 if(QFile::exists(htmlfilename))
4056 QFile::remove(htmlfilename);
4057
4058 return;
4059 }
4060
4061 //Now we print the results to an HTML file
4062 QFile file(htmlfilename);
4063 if(!file.open(QIODevice::WriteOnly)){
4064 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4065 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4066 return;
4067 }
4068 QTextStream tos(&file);
4069 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4070 tos.setEncoding(QStringConverter::Utf8);
4071 #else
4072 tos.setCodec("UTF-8");
4073 #endif
4074 tos.setGenerateByteOrderMark(true);
4075
4076 tos<<writeHead(true, placedActivities, true);
4077 tos<<writeTOCDays();
4078
4079 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4080 QSet<int> tmp;
4081 tos<<singleTeachersTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalTeachers, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4082 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4083 }
4084
4085 tos << " </body>\n</html>\n";
4086
4087 if(file.error()>0){
4088 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4089 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4090 }
4091 file.close();
4092 }
4093
4094 //writing the rooms' timetable html format to a file by Volker Dirr
writeRoomsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4095 void TimetableExport::writeRoomsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4096 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4097 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4098
4099 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_ROOMS){
4100 if(QFile::exists(htmlfilename))
4101 QFile::remove(htmlfilename);
4102
4103 return;
4104 }
4105
4106 //Now we print the results to an HTML file
4107 QFile file(htmlfilename);
4108 if(!file.open(QIODevice::WriteOnly)){
4109 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4110 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4111 return;
4112 }
4113 QTextStream tos(&file);
4114 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4115 tos.setEncoding(QStringConverter::Utf8);
4116 #else
4117 tos.setCodec("UTF-8");
4118 #endif
4119 tos.setGenerateByteOrderMark(true);
4120
4121 tos<<writeHead(true, placedActivities, true);
4122
4123 if(gt.rules.nInternalRooms==0)
4124 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4125 else {
4126 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4127 tos<<" <ul>\n";
4128 for(int room=0; room<gt.rules.nInternalRooms; room++){
4129 QString room_name = gt.rules.internalRoomsList[room]->name;
4130 tos<<" <li><a href=\""<<"#table_"<<hashRoomIDsTimetable.value(room_name)<<"\">"<<protect2(room_name)<<"</a></li>\n";
4131 }
4132 tos<<" </ul>\n <p> </p>\n\n";
4133
4134 for(int room=0; room<gt.rules.nInternalRooms; room++){
4135 tos<<singleRoomsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, room, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4136 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4137 }
4138 }
4139 tos<<" </body>\n</html>\n";
4140
4141 if(file.error()>0){
4142 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4143 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4144 }
4145 file.close();
4146 }
4147
4148 //writing the rooms' timetable html format to a file by Volker Dirr
writeRoomsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4149 void TimetableExport::writeRoomsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4150 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4151 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4152
4153 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_ROOMS){
4154 if(QFile::exists(htmlfilename))
4155 QFile::remove(htmlfilename);
4156
4157 return;
4158 }
4159
4160 //Now we print the results to an HTML file
4161 QFile file(htmlfilename);
4162 if(!file.open(QIODevice::WriteOnly)){
4163 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4164 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4165 return;
4166
4167 assert(0);
4168 }
4169 QTextStream tos(&file);
4170 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4171 tos.setEncoding(QStringConverter::Utf8);
4172 #else
4173 tos.setCodec("UTF-8");
4174 #endif
4175 tos.setGenerateByteOrderMark(true);
4176
4177 tos<<writeHead(true, placedActivities, true);
4178
4179 if(gt.rules.nInternalRooms==0)
4180 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4181 else {
4182 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4183 tos<<" <ul>\n";
4184 for(int room=0; room<gt.rules.nInternalRooms; room++){
4185 QString room_name = gt.rules.internalRoomsList[room]->name;
4186 tos<<" <li><a href=\""<<"#table_"<<hashRoomIDsTimetable.value(room_name)<<"\">"<<protect2(room_name)<<"</a></li>\n";
4187 }
4188 tos<<" </ul>\n <p> </p>\n\n";
4189
4190 for(int room=0; room<gt.rules.nInternalRooms; room++){
4191 tos<<singleRoomsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, room, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4192 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4193 }
4194 }
4195 tos<<" </body>\n</html>\n";
4196
4197 if(file.error()>0){
4198 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4199 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4200 }
4201 file.close();
4202 }
4203
4204 //writing the rooms' timetable html format to a file by Volker Dirr
writeRoomsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4205 void TimetableExport::writeRoomsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4206 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4207 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4208
4209 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ROOMS){
4210 if(QFile::exists(htmlfilename))
4211 QFile::remove(htmlfilename);
4212
4213 return;
4214 }
4215
4216 //Now we print the results to an HTML file
4217 QFile file(htmlfilename);
4218 if(!file.open(QIODevice::WriteOnly)){
4219 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4220 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4221 return;
4222 }
4223 QTextStream tos(&file);
4224 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4225 tos.setEncoding(QStringConverter::Utf8);
4226 #else
4227 tos.setCodec("UTF-8");
4228 #endif
4229 tos.setGenerateByteOrderMark(true);
4230
4231 tos<<writeHead(true, placedActivities, false);
4232
4233 if(gt.rules.nInternalRooms==0)
4234 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4235 else {
4236 QSet<int> tmp;
4237 tos<<singleRoomsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalRooms, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4238 }
4239 tos << " </body>\n</html>\n";
4240
4241 if(file.error()>0){
4242 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4243 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4244 }
4245 file.close();
4246 }
4247
4248 // writing the rooms' timetable html format to a file by Volker Dirr
writeRoomsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4249 void TimetableExport::writeRoomsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4250 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4251 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4252
4253 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ROOMS){
4254 if(QFile::exists(htmlfilename))
4255 QFile::remove(htmlfilename);
4256
4257 return;
4258 }
4259
4260 //Now we print the results to an HTML file
4261 QFile file(htmlfilename);
4262 if(!file.open(QIODevice::WriteOnly)){
4263 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4264 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4265 return;
4266 }
4267 QTextStream tos(&file);
4268 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4269 tos.setEncoding(QStringConverter::Utf8);
4270 #else
4271 tos.setCodec("UTF-8");
4272 #endif
4273 tos.setGenerateByteOrderMark(true);
4274
4275 tos<<writeHead(true, placedActivities, false);
4276
4277 if(gt.rules.nInternalRooms==0)
4278 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4279 else {
4280 QSet<int> tmp;
4281 tos<<singleRoomsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalRooms, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4282
4283 }
4284 tos << " </body>\n</html>\n";
4285
4286 if(file.error()>0){
4287 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4288 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4289 }
4290 file.close();
4291 }
4292
4293 //by Volker Dirr
writeRoomsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4294 void TimetableExport::writeRoomsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4295 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4296 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4297
4298 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ROOMS){
4299 if(QFile::exists(htmlfilename))
4300 QFile::remove(htmlfilename);
4301
4302 return;
4303 }
4304
4305 //Now we print the results to an HTML file
4306 QFile file(htmlfilename);
4307 if(!file.open(QIODevice::WriteOnly)){
4308 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4309 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4310 return;
4311 }
4312 QTextStream tos(&file);
4313 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4314 tos.setEncoding(QStringConverter::Utf8);
4315 #else
4316 tos.setCodec("UTF-8");
4317 #endif
4318 tos.setGenerateByteOrderMark(true);
4319
4320 tos<<writeHead(true, placedActivities, true);
4321 tos<<writeTOCDays();
4322
4323 if(gt.rules.nInternalRooms==0)
4324 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4325 else {
4326 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4327 QSet<int> tmp;
4328 tos<<singleRoomsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalRooms, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4329
4330 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4331 }
4332 }
4333 tos << " </body>\n</html>\n";
4334
4335 if(file.error()>0){
4336 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4337 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4338 }
4339 file.close();
4340 }
4341
4342 //by Volker Dirr
writeRoomsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4343 void TimetableExport::writeRoomsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4344 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4345 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4346
4347 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ROOMS){
4348 if(QFile::exists(htmlfilename))
4349 QFile::remove(htmlfilename);
4350
4351 return;
4352 }
4353
4354 //Now we print the results to an HTML file
4355 QFile file(htmlfilename);
4356 if(!file.open(QIODevice::WriteOnly)){
4357 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4358 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4359 return;
4360 }
4361 QTextStream tos(&file);
4362 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4363 tos.setEncoding(QStringConverter::Utf8);
4364 #else
4365 tos.setCodec("UTF-8");
4366 #endif
4367 tos.setGenerateByteOrderMark(true);
4368
4369 tos<<writeHead(true, placedActivities, true);
4370 tos<<writeTOCDays();
4371
4372 if(gt.rules.nInternalRooms==0)
4373 tos<<" <h1>"<<TimetableExport::tr("No rooms recorded in FET for %1.", "%1 is the institution name").arg(protect2(gt.rules.institutionName))<<"</h1>\n";
4374 else {
4375 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4376 QSet<int> tmp;
4377 tos<<singleRoomsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalRooms, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4378
4379 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4380 }
4381
4382 }
4383 tos << " </body>\n</html>\n";
4384
4385 if(file.error()>0){
4386 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4387 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4388 }
4389 file.close();
4390 }
4391
4392 //Print the subjects
4393
4394 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4395 void TimetableExport::writeSubjectsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4396 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4397 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4398
4399 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_SUBJECTS){
4400 if(QFile::exists(htmlfilename))
4401 QFile::remove(htmlfilename);
4402
4403 return;
4404 }
4405
4406 //Now we print the results to an HTML file
4407 QFile file(htmlfilename);
4408 if(!file.open(QIODevice::WriteOnly)){
4409 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4410 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4411 return;
4412 }
4413 QTextStream tos(&file);
4414 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4415 tos.setEncoding(QStringConverter::Utf8);
4416 #else
4417 tos.setCodec("UTF-8");
4418 #endif
4419 tos.setGenerateByteOrderMark(true);
4420
4421 tos<<writeHead(true, placedActivities, true);
4422
4423 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4424 tos<<" <ul>\n";
4425 for(int i=0; i<gt.rules.nInternalSubjects; i++){
4426 tos<<" <li>\n "<<TimetableExport::tr("Subject");
4427 tos<<" <a href=\""<<"#table_"<<hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[i]->name)<<"\">"<<gt.rules.internalSubjectsList[i]->name<<"</a>\n";
4428 tos<<" </li>\n";
4429 }
4430 tos<<" </ul>\n <p> </p>\n\n";
4431
4432
4433 for(int subject=0; subject<gt.rules.nInternalSubjects; subject++){
4434 tos<<singleSubjectsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, subject, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4435 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4436 }
4437 tos<<" </body>\n</html>\n";
4438
4439 if(file.error()>0){
4440 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4441 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4442 }
4443 file.close();
4444 }
4445
4446 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4447 void TimetableExport::writeSubjectsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4448 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4449 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4450
4451 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_SUBJECTS){
4452 if(QFile::exists(htmlfilename))
4453 QFile::remove(htmlfilename);
4454
4455 return;
4456 }
4457
4458 //Now we print the results to an HTML file
4459 QFile file(htmlfilename);
4460 if(!file.open(QIODevice::WriteOnly)){
4461 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4462 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4463 return;
4464 }
4465 QTextStream tos(&file);
4466 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4467 tos.setEncoding(QStringConverter::Utf8);
4468 #else
4469 tos.setCodec("UTF-8");
4470 #endif
4471 tos.setGenerateByteOrderMark(true);
4472
4473 tos<<writeHead(true, placedActivities, true);
4474
4475 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4476 tos<<" <ul>\n";
4477 for(int i=0; i<gt.rules.nInternalSubjects; i++){
4478 tos<<" <li>\n "<<TimetableExport::tr("Subject");
4479 tos<<" <a href=\""<<"#table_"<<hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[i]->name)<<"\">"<<gt.rules.internalSubjectsList[i]->name<<"</a>\n";
4480 tos<<" </li>\n";
4481 }
4482 tos<<" </ul>\n <p> </p>\n\n";
4483
4484 for(int subject=0; subject<gt.rules.nInternalSubjects; subject++){
4485 tos<<singleSubjectsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, subject, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4486 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4487 }
4488 tos << " </body>\n</html>\n";
4489
4490 if(file.error()>0){
4491 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4492 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4493 }
4494 file.close();
4495 }
4496
4497 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4498 void TimetableExport::writeSubjectsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4499 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4500 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4501
4502 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_SUBJECTS){
4503 if(QFile::exists(htmlfilename))
4504 QFile::remove(htmlfilename);
4505
4506 return;
4507 }
4508
4509 //Now we print the results to an HTML file
4510 QFile file(htmlfilename);
4511 if(!file.open(QIODevice::WriteOnly)){
4512 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4513 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4514 return;
4515 }
4516 QTextStream tos(&file);
4517 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4518 tos.setEncoding(QStringConverter::Utf8);
4519 #else
4520 tos.setCodec("UTF-8");
4521 #endif
4522 tos.setGenerateByteOrderMark(true);
4523
4524 tos<<writeHead(true, placedActivities, false);
4525
4526 QSet<int> tmp;
4527 tos<<singleSubjectsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalSubjects, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4528 tos << " </body>\n</html>\n";
4529
4530 if(file.error()>0){
4531 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4532 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4533 }
4534 file.close();
4535 }
4536
4537 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4538 void TimetableExport::writeSubjectsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4539 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4540 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4541
4542 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_SUBJECTS){
4543 if(QFile::exists(htmlfilename))
4544 QFile::remove(htmlfilename);
4545
4546 return;
4547 }
4548
4549 //Now we print the results to an HTML file
4550 QFile file(htmlfilename);
4551 if(!file.open(QIODevice::WriteOnly)){
4552 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4553 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4554 return;
4555 }
4556 QTextStream tos(&file);
4557 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4558 tos.setEncoding(QStringConverter::Utf8);
4559 #else
4560 tos.setCodec("UTF-8");
4561 #endif
4562 tos.setGenerateByteOrderMark(true);
4563
4564 tos<<writeHead(true, placedActivities, false);
4565
4566 QSet<int> tmp;
4567 tos<<singleSubjectsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalSubjects, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4568
4569 tos << " </body>\n</html>\n";
4570
4571 if(file.error()>0){
4572 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4573 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4574 }
4575 file.close();
4576 }
4577
4578 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4579 void TimetableExport::writeSubjectsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4580 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4581 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4582
4583 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_SUBJECTS){
4584 if(QFile::exists(htmlfilename))
4585 QFile::remove(htmlfilename);
4586
4587 return;
4588 }
4589
4590 //Now we print the results to an HTML file
4591 QFile file(htmlfilename);
4592 if(!file.open(QIODevice::WriteOnly)){
4593 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4594 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4595 return;
4596 }
4597 QTextStream tos(&file);
4598 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4599 tos.setEncoding(QStringConverter::Utf8);
4600 #else
4601 tos.setCodec("UTF-8");
4602 #endif
4603 tos.setGenerateByteOrderMark(true);
4604
4605 tos<<writeHead(true, placedActivities, true);
4606 tos<<writeTOCDays();
4607
4608 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4609 QSet<int> tmp;
4610 tos<<singleSubjectsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalSubjects, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4611
4612 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4613 }
4614
4615 tos << " </body>\n</html>\n";
4616
4617 if(file.error()>0){
4618 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4619 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4620 }
4621 file.close();
4622 }
4623
4624 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeSubjectsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4625 void TimetableExport::writeSubjectsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4626 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4627 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4628
4629 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_SUBJECTS){
4630 if(QFile::exists(htmlfilename))
4631 QFile::remove(htmlfilename);
4632
4633 return;
4634 }
4635
4636 //Now we print the results to an HTML file
4637 QFile file(htmlfilename);
4638 if(!file.open(QIODevice::WriteOnly)){
4639 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4640 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4641 return;
4642 }
4643 QTextStream tos(&file);
4644 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4645 tos.setEncoding(QStringConverter::Utf8);
4646 #else
4647 tos.setCodec("UTF-8");
4648 #endif
4649 tos.setGenerateByteOrderMark(true);
4650
4651 tos<<writeHead(true, placedActivities, true);
4652 tos<<writeTOCDays();
4653
4654 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4655 QSet<int> tmp;
4656 tos<<singleSubjectsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalSubjects, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4657
4658 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4659 }
4660 tos << " </body>\n</html>\n";
4661
4662 if(file.error()>0){
4663 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4664 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4665 }
4666 file.close();
4667 }
4668
4669 //Print the activity tags
4670
4671 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4672 void TimetableExport::writeActivityTagsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4673 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4674 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4675
4676 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4677 if(QFile::exists(htmlfilename))
4678 QFile::remove(htmlfilename);
4679
4680 return;
4681 }
4682
4683 //Now we print the results to an HTML file
4684 QFile file(htmlfilename);
4685 if(!file.open(QIODevice::WriteOnly)){
4686 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4687 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4688 return;
4689 }
4690 QTextStream tos(&file);
4691 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4692 tos.setEncoding(QStringConverter::Utf8);
4693 #else
4694 tos.setCodec("UTF-8");
4695 #endif
4696 tos.setGenerateByteOrderMark(true);
4697
4698 tos<<writeHead(true, placedActivities, true);
4699
4700 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4701 tos<<" <ul>\n";
4702 for(int i=0; i<gt.rules.nInternalActivityTags; i++){
4703 if(gt.rules.internalActivityTagsList[i]->printable){
4704 tos<<" <li>\n "<<TimetableExport::tr("Activity Tag");
4705 tos<<" <a href=\""<<"#table_"<<hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[i]->name)<<"\">"<<gt.rules.internalActivityTagsList[i]->name<<"</a>\n";
4706 tos<<" </li>\n";
4707 }
4708 }
4709 tos<<" </ul>\n <p> </p>\n\n";
4710
4711
4712 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags; activityTag++){
4713 if(gt.rules.internalActivityTagsList[activityTag]->printable){
4714 tos<<singleActivityTagsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, activityTag, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4715 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4716 }
4717 }
4718 tos<<" </body>\n</html>\n";
4719
4720 if(file.error()>0){
4721 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4722 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4723 }
4724 file.close();
4725 }
4726
4727 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4728 void TimetableExport::writeActivityTagsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4729 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4730 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4731
4732 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4733 if(QFile::exists(htmlfilename))
4734 QFile::remove(htmlfilename);
4735
4736 return;
4737 }
4738
4739 //Now we print the results to an HTML file
4740 QFile file(htmlfilename);
4741 if(!file.open(QIODevice::WriteOnly)){
4742 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4743 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4744 return;
4745 }
4746 QTextStream tos(&file);
4747 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4748 tos.setEncoding(QStringConverter::Utf8);
4749 #else
4750 tos.setCodec("UTF-8");
4751 #endif
4752 tos.setGenerateByteOrderMark(true);
4753
4754 tos<<writeHead(true, placedActivities, true);
4755
4756 tos<<" <p><strong>"<<TimetableExport::tr("Table of contents")<<"</strong></p>\n";
4757 tos<<" <ul>\n";
4758 for(int i=0; i<gt.rules.nInternalActivityTags; i++){
4759 if(gt.rules.internalActivityTagsList[i]->printable){
4760 tos<<" <li>\n "<<TimetableExport::tr("Activity Tag");
4761 tos<<" <a href=\""<<"#table_"<<hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[i]->name)<<"\">"<<gt.rules.internalActivityTagsList[i]->name<<"</a>\n";
4762 tos<<" </li>\n";
4763 }
4764 }
4765 tos<<" </ul>\n <p> </p>\n\n";
4766
4767 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags; activityTag++){
4768 if(gt.rules.internalActivityTagsList[activityTag]->printable){
4769 tos<<singleActivityTagsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, activityTag, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4770 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4771 }
4772 }
4773 tos << " </body>\n</html>\n";
4774
4775 if(file.error()>0){
4776 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4777 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4778 }
4779 file.close();
4780 }
4781
4782 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableTimeVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4783 void TimetableExport::writeActivityTagsTimetableTimeVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4784 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4785 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4786
4787 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4788 if(QFile::exists(htmlfilename))
4789 QFile::remove(htmlfilename);
4790
4791 return;
4792 }
4793
4794 //Now we print the results to an HTML file
4795 QFile file(htmlfilename);
4796 if(!file.open(QIODevice::WriteOnly)){
4797 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4798 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4799 return;
4800 }
4801 QTextStream tos(&file);
4802 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4803 tos.setEncoding(QStringConverter::Utf8);
4804 #else
4805 tos.setCodec("UTF-8");
4806 #endif
4807 tos.setGenerateByteOrderMark(true);
4808
4809 tos<<writeHead(true, placedActivities, false);
4810
4811 QSet<int> tmp;
4812 tos<<singleActivityTagsTimetableTimeVerticalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalActivityTags, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4813 tos << " </body>\n</html>\n";
4814
4815 if(file.error()>0){
4816 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4817 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4818 }
4819 file.close();
4820 }
4821
4822 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableTimeHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4823 void TimetableExport::writeActivityTagsTimetableTimeHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4824 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4825 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4826
4827 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4828 if(QFile::exists(htmlfilename))
4829 QFile::remove(htmlfilename);
4830
4831 return;
4832 }
4833
4834 //Now we print the results to an HTML file
4835 QFile file(htmlfilename);
4836 if(!file.open(QIODevice::WriteOnly)){
4837 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4838 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4839 return;
4840 }
4841 QTextStream tos(&file);
4842 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4843 tos.setEncoding(QStringConverter::Utf8);
4844 #else
4845 tos.setCodec("UTF-8");
4846 #endif
4847 tos.setGenerateByteOrderMark(true);
4848
4849 tos<<writeHead(true, placedActivities, false);
4850
4851 QSet<int> tmp;
4852 tos<<singleActivityTagsTimetableTimeHorizontalHtml(TIMETABLE_HTML_LEVEL, gt.rules.nInternalActivityTags, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4853
4854 tos << " </body>\n</html>\n";
4855
4856 if(file.error()>0){
4857 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4858 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4859 }
4860 file.close();
4861 }
4862
4863 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableTimeVerticalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4864 void TimetableExport::writeActivityTagsTimetableTimeVerticalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4865 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4866 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4867
4868 if(!WRITE_TIMETABLES_TIME_VERTICAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4869 if(QFile::exists(htmlfilename))
4870 QFile::remove(htmlfilename);
4871
4872 return;
4873 }
4874
4875 //Now we print the results to an HTML file
4876 QFile file(htmlfilename);
4877 if(!file.open(QIODevice::WriteOnly)){
4878 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4879 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4880 return;
4881 }
4882 QTextStream tos(&file);
4883 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4884 tos.setEncoding(QStringConverter::Utf8);
4885 #else
4886 tos.setCodec("UTF-8");
4887 #endif
4888 tos.setGenerateByteOrderMark(true);
4889
4890 tos<<writeHead(true, placedActivities, true);
4891 tos<<writeTOCDays();
4892
4893 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4894 QSet<int> tmp;
4895 tos<<singleActivityTagsTimetableTimeVerticalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalActivityTags, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4896
4897 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4898 }
4899
4900 tos << " </body>\n</html>\n";
4901
4902 if(file.error()>0){
4903 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4904 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4905 }
4906 file.close();
4907 }
4908
4909 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeActivityTagsTimetableTimeHorizontalDailyHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4910 void TimetableExport::writeActivityTagsTimetableTimeHorizontalDailyHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4911 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4912 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4913
4914 if(!WRITE_TIMETABLES_TIME_HORIZONTAL || !WRITE_TIMETABLES_ACTIVITY_TAGS){
4915 if(QFile::exists(htmlfilename))
4916 QFile::remove(htmlfilename);
4917
4918 return;
4919 }
4920
4921 //Now we print the results to an HTML file
4922 QFile file(htmlfilename);
4923 if(!file.open(QIODevice::WriteOnly)){
4924 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4925 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4926 return;
4927 }
4928 QTextStream tos(&file);
4929 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4930 tos.setEncoding(QStringConverter::Utf8);
4931 #else
4932 tos.setCodec("UTF-8");
4933 #endif
4934 tos.setGenerateByteOrderMark(true);
4935
4936 tos<<writeHead(true, placedActivities, true);
4937 tos<<writeTOCDays();
4938
4939 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
4940 QSet<int> tmp;
4941 tos<<singleActivityTagsTimetableTimeHorizontalDailyHtml(TIMETABLE_HTML_LEVEL, day, gt.rules.nInternalActivityTags, tmp, saveTime, TIMETABLE_HTML_PRINT_ACTIVITY_TAGS, TIMETABLE_HTML_REPEAT_NAMES);
4942
4943 tos<<" <p class=\"back\"><a href=\""<<"#top\">"<<TimetableExport::tr("back to the top")<<"</a></p>\n\n";
4944 }
4945 tos << " </body>\n</html>\n";
4946
4947 if(file.error()>0){
4948 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4949 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
4950 }
4951 file.close();
4952 }
4953
4954 //Print the teachers free periods. Code by Volker Dirr (https://timetabling.de/)
writeTeachersFreePeriodsTimetableDaysHorizontalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)4955 void TimetableExport::writeTeachersFreePeriodsTimetableDaysHorizontalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
4956 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
4957 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
4958
4959 if(!WRITE_TIMETABLES_DAYS_HORIZONTAL || !WRITE_TIMETABLES_TEACHERS_FREE_PERIODS){
4960 if(QFile::exists(htmlfilename))
4961 QFile::remove(htmlfilename);
4962
4963 return;
4964 }
4965
4966 //Now we print the results to an HTML file
4967 QFile file(htmlfilename);
4968 if(!file.open(QIODevice::WriteOnly)){
4969 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
4970 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
4971 return;
4972 }
4973 QTextStream tos(&file);
4974 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
4975 tos.setEncoding(QStringConverter::Utf8);
4976 #else
4977 tos.setCodec("UTF-8");
4978 #endif
4979 tos.setGenerateByteOrderMark(true);
4980
4981 tos<<writeHead(true, placedActivities, true);
4982
4983 tos<<" <div class=\"TEACHER_HAS_SINGLE_GAP\">"<<TimetableExport::tr("Teacher has a single gap")<<"</div>\n";
4984 tos<<" <div class=\"TEACHER_HAS_BORDER_GAP\">"<<TimetableExport::tr("Teacher has a border gap")<<"</div>\n";
4985 tos<<" <div class=\"TEACHER_HAS_BIG_GAP\">"<<TimetableExport::tr("Teacher has a big gap")<<"</div>\n";
4986 tos<<" <div class=\"TEACHER_MUST_COME_EARLIER\">"<<TimetableExport::tr("Teacher must come earlier")<<"</div>\n";
4987 tos<<" <div class=\"TEACHER_MUST_COME_MUCH_EARLIER\">"<<TimetableExport::tr("Teacher must come much earlier")<<"</div>\n";
4988 tos<<" <div class=\"TEACHER_MUST_STAY_LONGER\">"<<TimetableExport::tr("Teacher must stay longer")<<"</div>\n";
4989 tos<<" <div class=\"TEACHER_MUST_STAY_MUCH_LONGER\">"<<TimetableExport::tr("Teacher must stay much longer")<<"</div>\n";
4990 tos<<" <div class=\"TEACHER_HAS_A_FREE_DAY\">"<<TimetableExport::tr("Teacher has a free day")<<"</div>\n";
4991 tos<<" <div class=\"TEACHER_IS_NOT_AVAILABLE\">"<<TimetableExport::tr("Teacher is not available")<<"</div>\n";
4992
4993 tos<<" <p> </p>\n\n";
4994
4995 tos<<singleTeachersFreePeriodsTimetableDaysHorizontalHtml(TIMETABLE_HTML_LEVEL, saveTime, PRINT_DETAILED_HTML_TEACHERS_FREE_PERIODS, TIMETABLE_HTML_REPEAT_NAMES);
4996
4997 tos<<" </body>\n</html>\n";
4998
4999 if(file.error()>0){
5000 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5001 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
5002 }
5003 file.close();
5004 }
5005
5006 //XHTML generation code by Volker Dirr (https://timetabling.de/)
writeTeachersFreePeriodsTimetableDaysVerticalHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)5007 void TimetableExport::writeTeachersFreePeriodsTimetableDaysVerticalHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
5008 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5009 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5010
5011 if(!WRITE_TIMETABLES_DAYS_VERTICAL || !WRITE_TIMETABLES_TEACHERS_FREE_PERIODS){
5012 if(QFile::exists(htmlfilename))
5013 QFile::remove(htmlfilename);
5014
5015 return;
5016 }
5017
5018 //Now we print the results to an HTML file
5019 QFile file(htmlfilename);
5020 if(!file.open(QIODevice::WriteOnly)){
5021 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5022 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
5023 return;
5024 }
5025 QTextStream tos(&file);
5026 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
5027 tos.setEncoding(QStringConverter::Utf8);
5028 #else
5029 tos.setCodec("UTF-8");
5030 #endif
5031 tos.setGenerateByteOrderMark(true);
5032
5033 tos<<writeHead(true, placedActivities, true);
5034
5035 tos<<" <div class=\"TEACHER_HAS_SINGLE_GAP\">"<<TimetableExport::tr("Teacher has a single gap")<<"</div>\n";
5036 tos<<" <div class=\"TEACHER_HAS_BORDER_GAP\">"<<TimetableExport::tr("Teacher has a border gap")<<"</div>\n";
5037 tos<<" <div class=\"TEACHER_HAS_BIG_GAP\">"<<TimetableExport::tr("Teacher has a big gap")<<"</div>\n";
5038 tos<<" <div class=\"TEACHER_MUST_COME_EARLIER\">"<<TimetableExport::tr("Teacher must come earlier")<<"</div>\n";
5039 tos<<" <div class=\"TEACHER_MUST_COME_MUCH_EARLIER\">"<<TimetableExport::tr("Teacher must come much earlier")<<"</div>\n";
5040 tos<<" <div class=\"TEACHER_MUST_STAY_LONGER\">"<<TimetableExport::tr("Teacher must stay longer")<<"</div>\n";
5041 tos<<" <div class=\"TEACHER_MUST_STAY_MUCH_LONGER\">"<<TimetableExport::tr("Teacher must stay much longer")<<"</div>\n";
5042 tos<<" <div class=\"TEACHER_HAS_A_FREE_DAY\">"<<TimetableExport::tr("Teacher has a free day")<<"</div>\n";
5043 tos<<" <div class=\"TEACHER_IS_NOT_AVAILABLE\">"<<TimetableExport::tr("Teacher is not available")<<"</div>\n";
5044
5045 tos<<" <p> </p>\n\n";
5046
5047 tos<<singleTeachersFreePeriodsTimetableDaysVerticalHtml(TIMETABLE_HTML_LEVEL, saveTime, PRINT_DETAILED_HTML_TEACHERS_FREE_PERIODS, TIMETABLE_HTML_REPEAT_NAMES);
5048
5049 tos<<" </body>\n</html>\n";
5050
5051 if(file.error()>0){
5052 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5053 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
5054 }
5055 file.close();
5056 }
5057
5058 //Code contributed by Volker Dirr (https://timetabling.de/)
writeTeachersStatisticsHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)5059 void TimetableExport::writeTeachersStatisticsHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
5060 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5061 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5062
5063 if(!WRITE_TIMETABLES_STATISTICS || !WRITE_TIMETABLES_TEACHERS){
5064 if(QFile::exists(htmlfilename))
5065 QFile::remove(htmlfilename);
5066
5067 return;
5068 }
5069
5070 //Now we print the results to an HTML file
5071 QFile file(htmlfilename);
5072 if(!file.open(QIODevice::WriteOnly)){
5073 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5074 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
5075 return;
5076 }
5077 QTextStream tos(&file);
5078 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
5079 tos.setEncoding(QStringConverter::Utf8);
5080 #else
5081 tos.setCodec("UTF-8");
5082 #endif
5083 tos.setGenerateByteOrderMark(true);
5084
5085 tos<<writeHead(true, placedActivities, true);
5086
5087 bool PRINT_DETAILED=true;
5088 tos<<singleTeachersStatisticsHtml(TIMETABLE_HTML_LEVEL, saveTime, PRINT_DETAILED, TIMETABLE_HTML_REPEAT_NAMES, true);
5089 tos<<" </body>\n</html>\n";
5090
5091 if(file.error()>0){
5092 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5093 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
5094 }
5095 file.close();
5096 }
5097
5098 //Code contributed by Volker Dirr (https://timetabling.de/)
writeStudentsStatisticsHtml(QWidget * parent,const QString & htmlfilename,const QString & saveTime,int placedActivities)5099 void TimetableExport::writeStudentsStatisticsHtml(QWidget* parent, const QString& htmlfilename, const QString& saveTime, int placedActivities){
5100 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5101 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5102
5103 if(!WRITE_TIMETABLES_STATISTICS || !(WRITE_TIMETABLES_YEARS || WRITE_TIMETABLES_GROUPS || WRITE_TIMETABLES_SUBGROUPS) ){
5104 if(QFile::exists(htmlfilename))
5105 QFile::remove(htmlfilename);
5106
5107 return;
5108 }
5109
5110 //Now we print the results to an HTML file
5111 QFile file(htmlfilename);
5112 if(!file.open(QIODevice::WriteOnly)){
5113 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5114 TimetableExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
5115 return;
5116 }
5117 QTextStream tos(&file);
5118 #if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
5119 tos.setEncoding(QStringConverter::Utf8);
5120 #else
5121 tos.setCodec("UTF-8");
5122 #endif
5123 tos.setGenerateByteOrderMark(true);
5124
5125 tos<<writeHead(true, placedActivities, true);
5126 bool PRINT_DETAILED=true;
5127 tos<<singleStudentsStatisticsHtml(TIMETABLE_HTML_LEVEL, saveTime, PRINT_DETAILED, TIMETABLE_HTML_REPEAT_NAMES, true);
5128
5129 tos<<" </body>\n</html>\n";
5130
5131 if(file.error()>0){
5132 IrreconcilableCriticalMessage::critical(parent, tr("FET critical"),
5133 TimetableExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
5134 }
5135 file.close();
5136 }
5137
5138 //------------------------------------------------------------------
5139 //------------------------------------------------------------------
5140
computeHashForIDsTimetable()5141 void TimetableExport::computeHashForIDsTimetable(){
5142 // by Volker Dirr
5143
5144 //TODO This is unneeded if you use a relational data base, because we can use the primary key id of the database.
5145 //This is very similar to statistics compute hash. So always check it if you change something here!
5146
5147 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5148 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5149 hashStudentIDsTimetable.clear();
5150 int cnt=1;
5151 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
5152 StudentsYear* sty=gt.rules.augmentedYearsList[i];
5153 if(!hashStudentIDsTimetable.contains(sty->name)){
5154 hashStudentIDsTimetable.insert(sty->name, CustomFETString::number(cnt));
5155 cnt++;
5156 }
5157 for(int j=0; j<sty->groupsList.size(); j++){
5158 StudentsGroup* stg=sty->groupsList[j];
5159 if(!hashStudentIDsTimetable.contains(stg->name)){
5160 hashStudentIDsTimetable.insert(stg->name, CustomFETString::number(cnt));
5161 cnt++;
5162 }
5163 for(int k=0; k<stg->subgroupsList.size(); k++){
5164 StudentsSubgroup* sts=stg->subgroupsList[k];
5165 if(!hashStudentIDsTimetable.contains(sts->name)){
5166 hashStudentIDsTimetable.insert(sts->name, CustomFETString::number(cnt));
5167 cnt++;
5168 }
5169 }
5170 }
5171 }
5172
5173 hashSubjectIDsTimetable.clear();
5174 for(int i=0; i<gt.rules.nInternalSubjects; i++){
5175 hashSubjectIDsTimetable.insert(gt.rules.internalSubjectsList[i]->name, CustomFETString::number(i+1));
5176 }
5177 hashActivityTagIDsTimetable.clear();
5178 for(int i=0; i<gt.rules.nInternalActivityTags; i++){
5179 // if(gt.rules.internalActivityTagsList[i]->printable){
5180 hashActivityTagIDsTimetable.insert(gt.rules.internalActivityTagsList[i]->name, CustomFETString::number(i+1));
5181 // }
5182 }
5183 hashTeacherIDsTimetable.clear();
5184 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5185 hashTeacherIDsTimetable.insert(gt.rules.internalTeachersList[i]->name, CustomFETString::number(i+1));
5186 }
5187 hashRoomIDsTimetable.clear();
5188 for(int room=0; room<gt.rules.nInternalRooms; room++){
5189 hashRoomIDsTimetable.insert(gt.rules.internalRoomsList[room]->name, CustomFETString::number(room+1));
5190 }
5191 hashDayIDsTimetable.clear();
5192 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
5193 hashDayIDsTimetable.insert(gt.rules.daysOfTheWeek[day], CustomFETString::number(day+1));
5194 }
5195 if(TIMETABLE_HTML_LEVEL==7){
5196 computeHashActivityColorBySubject();
5197 computeHashActivityColorBySubjectAndStudents();
5198 }
5199 }
5200
5201 //By Liviu, with ideas from Volker
computeHashActivityColorBySubject()5202 void TimetableExport::computeHashActivityColorBySubject(){
5203 QHash<QString, int> tmpHash;
5204
5205 hashActivityColorBySubject.clear();
5206 activeHashActivityColorBySubject.clear();
5207
5208 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5209 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5210
5211 QSet<QString> alreadyAdded;
5212
5213 for(int i=0; i<gt.rules.nInternalActivities; i++){
5214 if(best_solution.times[i]!=UNALLOCATED_TIME){
5215 Activity* act=>.rules.internalActivitiesList[i];
5216 QString tmpString=act->subjectName;
5217 if(!alreadyAdded.contains(tmpString)){
5218 alreadyAdded.insert(tmpString);
5219 hashActivityColorBySubject.insert(i, alreadyAdded.count());
5220 activeHashActivityColorBySubject.append(i);
5221 tmpHash.insert(tmpString, alreadyAdded.count());
5222 }
5223 else{
5224 assert(tmpHash.contains(tmpString));
5225 int k=tmpHash.value(tmpString);
5226 hashActivityColorBySubject.insert(i, k);
5227 }
5228 }
5229 }
5230
5231 //cout<<"hashActivityColorBySubject.count()=="<<hashActivityColorBySubject.count()<<endl;
5232 }
5233
5234 //By Liviu, with ideas from Volker
computeHashActivityColorBySubjectAndStudents()5235 void TimetableExport::computeHashActivityColorBySubjectAndStudents(){
5236 QHash<QString, int> tmpHash;
5237
5238 hashActivityColorBySubjectAndStudents.clear();
5239 activeHashActivityColorBySubjectAndStudents.clear();
5240
5241 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5242 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5243
5244 QSet<QString> alreadyAdded;
5245
5246 for(int i=0; i<gt.rules.nInternalActivities; i++){
5247 if(best_solution.times[i]!=UNALLOCATED_TIME){
5248 Activity* act=>.rules.internalActivitiesList[i];
5249
5250 QString tmpString=act->subjectName+" "+act->studentsNames.join(", ");
5251 if(!alreadyAdded.contains(tmpString)){
5252 alreadyAdded.insert(tmpString);
5253 hashActivityColorBySubjectAndStudents.insert(i, alreadyAdded.count());
5254 activeHashActivityColorBySubjectAndStudents.append(i);
5255 tmpHash.insert(tmpString, alreadyAdded.count());
5256 }
5257 else{
5258 assert(tmpHash.contains(tmpString));
5259 int k=tmpHash.value(tmpString);
5260 hashActivityColorBySubjectAndStudents.insert(i, k);
5261 }
5262 }
5263 }
5264
5265 //cout<<"hashActivityColorBySubjectAndStudents.count()=="<<hashActivityColorBySubjectAndStudents.count()<<endl;
5266 }
5267
5268 /*void TimetableExport::computeHashForColors(QHash<QString, QString>& hashColorStringIDsTimetable){
5269 // by Volker Dirr
5270 qWarning("compute hash for colors");
5271 hashColorStringIDsTimetable.clear();
5272 assert(gt.rules.initialized && gt.rules.internalStructureComputed);
5273 assert(students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready);
5274 QSet<QString> alreadyAddedString;
5275 for(int i=0; i<gt.rules.nInternalActivities; i++) {
5276 Activity* act=>.rules.internalActivitiesList[i];
5277 if(best_solution.times[i]!=UNALLOCATED_TIME) {
5278 qWarning("add a hash");
5279 //coloring for students
5280 QString tmpString=act->subjectName;
5281 if(!alreadyAddedString.contains(tmpString)){
5282 alreadyAddedString<<tmpString;
5283 hashColorStringIDsTimetable.insert(tmpString, CustomFETString::number(alreadyAddedString.count()));
5284 }
5285 //coloring for teachers
5286 tmpString=act->subjectName+" "+act->studentsNames.join(", ");
5287 if(!alreadyAddedString.contains(tmpString)){
5288 alreadyAddedString<<tmpString;
5289 hashColorStringIDsTimetable.insert(tmpString, CustomFETString::number(alreadyAddedString.count()));
5290 }
5291 //coloring for rooms
5292 // it is similar to students
5293 // tmpString=act->subjectName+" "+act->studentsNames.join(", ");
5294 // if(!alreadyAddedString.contains(tmpString)){
5295 // alreadyAddedString<<tmpString;
5296 // hashColorStringIDsTimetable.insert(tmpString, CustomFETString::number(alreadyAddedString.count()));
5297 // }
5298 }
5299 }
5300 }*/
5301
computeActivitiesAtTime()5302 void TimetableExport::computeActivitiesAtTime(){ // by Liviu Lalescu
5303 activitiesAtTime.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
5304 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
5305 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++)
5306 activitiesAtTime[day][hour].clear();
5307 for(int i=0; i<gt.rules.nInternalActivities; i++) { //maybe TODO: maybe it is better to do this sorted by students or teachers?
5308 Activity* act=>.rules.internalActivitiesList[i];
5309 if(best_solution.times[i]!=UNALLOCATED_TIME) {
5310 int hour=best_solution.times[i]/gt.rules.nDaysPerWeek;
5311 int day=best_solution.times[i]%gt.rules.nDaysPerWeek;
5312 for(int dd=0; dd < act->duration && hour+dd < gt.rules.nHoursPerDay; dd++)
5313 activitiesAtTime[day][hour+dd].append(i);
5314 }
5315 }
5316 }
5317
computeActivitiesWithSameStartingTime()5318 void TimetableExport::computeActivitiesWithSameStartingTime(){
5319 // by Volker Dirr
5320 activitiesWithSameStartingTime.clear();
5321
5322 if(PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME){
5323 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5324 TimeConstraint* tc=gt.rules.internalTimeConstraintsList[i];
5325 if(tc->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME){ //not needed anymore: && tc->weightPercentage==100
5326 ConstraintActivitiesSameStartingTime* c=(ConstraintActivitiesSameStartingTime*) tc;
5327 for(int a=0; a<c->_n_activities; a++){
5328 //speed improvement
5329 QList<int> & tmpList=activitiesWithSameStartingTime[c->_activities[a]];
5330 for(int b=0; b<c->_n_activities; b++){
5331 if(a!=b){
5332 if(best_solution.times[c->_activities[a]]==best_solution.times[c->_activities[b]]){ //because constraint is maybe not with 100% weight and failed
5333 if(!tmpList.contains(c->_activities[b])){
5334 tmpList<<c->_activities[b];
5335 }
5336 }
5337 }
5338 }
5339 /*
5340 QList<int> tmpList;
5341 if(activitiesWithSameStartingTime.contains(c->_activities[a]))
5342 tmpList=activitiesWithSameStartingTime.value(c->_activities[a]);
5343 for(int b=0; b<c->_n_activities; b++){
5344 if(a!=b){
5345 if(best_solution.times[c->_activities[a]]==best_solution.times[c->_activities[b]]){ //because constraint is maybe not with 100% weight and failed
5346 if(!tmpList.contains(c->_activities[b])){
5347 tmpList<<c->_activities[b];
5348 }
5349 }
5350 }
5351 }
5352 activitiesWithSameStartingTime.insert(c->_activities[a], tmpList);
5353 */
5354 }
5355 }
5356 }
5357 }
5358 }
5359
addActivitiesWithSameStartingTime(QList<int> & allActivities,int hour)5360 bool TimetableExport::addActivitiesWithSameStartingTime(QList<int>& allActivities, int hour){
5361 // by Volker Dirr
5362 if(PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME){
5363 bool activitiesWithSameStartingtime=false;
5364 QList<int> allActivitiesNew;
5365 for(int tmpAct : qAsConst(allActivities)){
5366 allActivitiesNew<<tmpAct;
5367 if(activitiesWithSameStartingTime.contains(tmpAct)){
5368 QList<int> sameTimeList=activitiesWithSameStartingTime.value(tmpAct);
5369 for(int sameTimeAct : qAsConst(sameTimeList)){
5370 if(!allActivitiesNew.contains(sameTimeAct) && !allActivities.contains(sameTimeAct)){
5371 if(best_solution.times[sameTimeAct]!=UNALLOCATED_TIME){
5372 Activity* act=>.rules.internalActivitiesList[sameTimeAct];
5373 assert(best_solution.times[tmpAct]==best_solution.times[sameTimeAct]);//{
5374 if((best_solution.times[sameTimeAct]/gt.rules.nDaysPerWeek+(act->duration-1))>=hour){
5375 allActivitiesNew<<sameTimeAct;
5376 }
5377 activitiesWithSameStartingtime=true; //don't add this line in previous if command because of activities with different duration!
5378 //}
5379 }
5380 }
5381 }
5382 }
5383 }
5384 //allActivities.clear();
5385 allActivities=allActivitiesNew;
5386 //allActivitiesNew.clear();
5387 return activitiesWithSameStartingtime;
5388 }
5389 else
5390 return false;
5391 }
5392
5393 // by Volker Dirr
writeHead(bool java,int placedActivities,bool printInstitution)5394 QString TimetableExport::writeHead(bool java, int placedActivities, bool printInstitution){
5395 QString tmp;
5396 tmp+="<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
5397 tmp+=" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
5398
5399 if(!LANGUAGE_STYLE_RIGHT_TO_LEFT)
5400 tmp+="<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""+LANGUAGE_FOR_HTML+"\" xml:lang=\""+LANGUAGE_FOR_HTML+"\">\n";
5401 else
5402 tmp+="<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""+LANGUAGE_FOR_HTML+"\" xml:lang=\""+LANGUAGE_FOR_HTML+"\" dir=\"rtl\">\n";
5403 tmp+=" <head>\n";
5404 tmp+=" <title>"+protect2(gt.rules.institutionName)+"</title>\n";
5405 tmp+=" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
5406 if(TIMETABLE_HTML_LEVEL>=1){
5407 QString cssfilename=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
5408
5409 if(cssfilename.right(4)==".fet")
5410 cssfilename=cssfilename.left(cssfilename.length()-4);
5411 //else if(INPUT_FILENAME_XML!="")
5412 // cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
5413
5414 cssfilename+="_"+STYLESHEET_CSS;
5415 if(INPUT_FILENAME_XML=="")
5416 cssfilename=STYLESHEET_CSS;
5417 tmp+=" <link rel=\"stylesheet\" media=\"all\" href=\""+cssfilename+"\" type=\"text/css\" />\n";
5418 }
5419 if(java){
5420 if(TIMETABLE_HTML_LEVEL>=5 && TIMETABLE_HTML_LEVEL!=7){ // the following JavaScript code is pretty similar to an example of Les Richardson
5421 tmp+=" <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
5422 tmp+=" <script type=\"text/javascript\">\n";
5423 tmp+=" function highlight(classval) {\n";
5424 tmp+=" var spans = document.getElementsByTagName('span');\n";
5425 tmp+=" for(var i=0; spans.length>i; i++) {\n";
5426 tmp+=" if (spans[i].className == classval) {\n";
5427 tmp+=" spans[i].style.backgroundColor = 'lime';\n";
5428 tmp+=" } else {\n";
5429 tmp+=" spans[i].style.backgroundColor = 'white';\n";
5430 tmp+=" }\n";
5431 tmp+=" }\n";
5432 tmp+=" }\n";
5433 tmp+=" </script>\n";
5434 }
5435 }
5436 tmp+=" </head>\n\n";
5437 tmp+=" <body id=\"top\">\n";
5438 if(placedActivities!=gt.rules.nInternalActivities)
5439 tmp+=" <h1>"+TimetableExport::tr("Warning! Only %1 out of %2 activities placed!").arg(placedActivities).arg(gt.rules.nInternalActivities)+"</h1>\n";
5440 if(printInstitution){
5441 tmp+=" <table>\n <tr align=\"left\" valign=\"top\">\n <th>"+TimetableExport::tr("Institution name")+":</th>\n <td>"+protect2(gt.rules.institutionName)+"</td>\n </tr>\n </table>\n";
5442 tmp+=" <table>\n <tr align=\"left\" valign=\"top\">\n <th>"+TimetableExport::tr("Comments")+":</th>\n <td>"+protect2(gt.rules.comments).replace(QString("\n"), QString("<br />\n"))+"</td>\n </tr>\n </table>\n";
5443 }
5444 return tmp;
5445 }
5446
5447 // by Volker Dirr
writeTOCDays()5448 QString TimetableExport::writeTOCDays(){
5449 QString tmp;
5450 tmp+=" <p><strong>"+TimetableExport::tr("Table of contents")+"</strong></p>\n";
5451 tmp+=" <ul>\n";
5452 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
5453 tmp+=" <li>\n ";
5454 tmp+=" <a href=\"#table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</a>\n";
5455 tmp+=" </li>\n";
5456 }
5457 tmp+=" </ul>\n <p> </p>\n";
5458 return tmp;
5459 }
5460
5461 // by Volker Dirr
writeStartTagTDofActivities(int htmlLevel,const Activity * act,bool detailed,bool colspan,bool rowspan,int colorBy)5462 QString TimetableExport::writeStartTagTDofActivities(int htmlLevel, const Activity* act, bool detailed, bool colspan, bool rowspan, int colorBy){
5463 QString tmp;
5464 assert(!(colspan && rowspan));
5465 if(detailed)
5466 assert(!colspan && !rowspan);
5467 else
5468 tmp+=" ";
5469 tmp+="<td";
5470 if(rowspan && act->duration>1)
5471 tmp+=" rowspan=\""+CustomFETString::number(act->duration)+"\"";
5472 if(colspan && act->duration>1)
5473 tmp+=" colspan=\""+CustomFETString::number(act->duration)+"\"";
5474 if(htmlLevel==6){
5475 tmp+=" class=\"";
5476 if(act->subjectName.size()>0){
5477 tmp+="s_"+hashSubjectIDsTimetable.value(act->subjectName);
5478 }
5479 if(act->activityTagsNames.size()>0){
5480 for(const QString& atn : qAsConst(act->activityTagsNames)){
5481 assert(hashActivityTagIDsTimetable.contains(atn));
5482 int id=hashActivityTagIDsTimetable.value(atn, "0").toInt()-1;
5483 assert(id>=0);
5484 assert(id<gt.rules.nInternalActivityTags);
5485 if(gt.rules.internalActivityTagsList[id]->printable){
5486 tmp+=" at_"+hashActivityTagIDsTimetable.value(atn);
5487 }
5488 }
5489 }
5490 if(act->studentsNames.size()>0){
5491 for(const QString& st : qAsConst(act->studentsNames))
5492 tmp+=" ss_"+hashStudentIDsTimetable.value(st);
5493 }
5494 if(act->teachersNames.size()>0){
5495 for(const QString& t : qAsConst(act->teachersNames))
5496 tmp+=" t_"+hashTeacherIDsTimetable.value(t);
5497 }
5498 //i need ai for this!!! so i need a parameter ai?! //TODO
5499 /*int r=best_solution.rooms[ai];
5500 if(r!=UNALLOCATED_SPACE && r!=UNSPECIFIED_ROOM){
5501 tmp+=" room_"+protect2id(gt.rules.internalRoomsList[r]->name);
5502 }*/
5503 if(detailed)
5504 tmp+=" detailed";
5505 tmp+="\"";
5506 }
5507 if(htmlLevel==7){
5508 assert(gt.rules.activitiesHash.contains(act->id));
5509 int index=gt.rules.activitiesHash.value(act->id);
5510 switch(colorBy){
5511 case COLOR_BY_SUBJECT_STUDENTS: tmp+=" class=\"c_"+QString::number(activeHashActivityColorBySubject.count()+hashActivityColorBySubjectAndStudents.value(index)); break;
5512 case COLOR_BY_SUBJECT: tmp+=" class=\"c_"+QString::number(hashActivityColorBySubject.value(index)); break;
5513 default: assert(0==1);
5514 }
5515
5516 if(detailed)
5517 tmp+=" detailed";
5518 tmp+="\"";
5519 }
5520 if(detailed && htmlLevel>=1 && htmlLevel<=5)
5521 tmp+=" class=\"detailed\"";
5522 tmp+=">";
5523 return tmp;
5524 }
5525
5526 // by Volker Dirr
writeSubjectAndActivityTags(int htmlLevel,const Activity * act,const QString & startTag,const QString & startTagAttribute,bool activityTagsOnly,bool printActivityTags)5527 QString TimetableExport::writeSubjectAndActivityTags(int htmlLevel, const Activity* act, const QString& startTag, const QString& startTagAttribute, bool activityTagsOnly, bool printActivityTags){
5528 QString tmp;
5529 if(act->subjectName.size()>0||act->activityTagsNames.size()>0){
5530 if(startTag=="div" && htmlLevel>=3)
5531 tmp+="<"+startTag+startTagAttribute+">";
5532 if(act->subjectName.size()>0 && !activityTagsOnly){
5533 switch(htmlLevel){
5534 case 3 : tmp+="<span class=\"subject\">"+protect2(act->subjectName)+"</span>"; break;
5535 case 4 : tmp+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsTimetable.value(act->subjectName)+"\">"+protect2(act->subjectName)+"</span></span>"; break;
5536 case 5 : ;
5537 case 6 : tmp+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsTimetable.value(act->subjectName)+"\" onmouseover=\"highlight('s_"+hashSubjectIDsTimetable.value(act->subjectName)+"')\">"+protect2(act->subjectName)+"</span></span>"; break;
5538 case 7 : tmp+="<span class=\"subject\">"+protect2(act->subjectName)+"</span>"; break;
5539 default: tmp+=protect2(act->subjectName); break;
5540 }
5541 if(act->activityTagsNames.size()>0 && printActivityTags){
5542 tmp+=" ";
5543 }
5544 }
5545 if(act->activityTagsNames.size()>0 && printActivityTags){
5546 bool writeTags=false;
5547 for(const QString& atn : qAsConst(act->activityTagsNames)){
5548 assert(hashActivityTagIDsTimetable.contains(atn));
5549 int id=hashActivityTagIDsTimetable.value(atn, "0").toInt()-1;
5550 assert(id>=0);
5551 assert(id<gt.rules.nInternalActivityTags);
5552 if(gt.rules.internalActivityTagsList[id]->printable){
5553 writeTags=true;
5554 }
5555 }
5556 if(writeTags){
5557 if(!activityTagsOnly){
5558 if(htmlLevel>=3){
5559 tmp+="<span class=\"activitytag\">";
5560 }
5561 }
5562 for(const QString& atn : qAsConst(act->activityTagsNames)){
5563 assert(hashActivityTagIDsTimetable.contains(atn));
5564 int id=hashActivityTagIDsTimetable.value(atn, "0").toInt()-1;
5565 assert(id>=0);
5566 assert(id<gt.rules.nInternalActivityTags);
5567 if(gt.rules.internalActivityTagsList[id]->printable){
5568 switch(htmlLevel){
5569 case 3 : tmp+=protect2(atn); break;
5570 case 4 : tmp+="<span class=\"at_"+hashActivityTagIDsTimetable.value(atn)+"\">"+protect2(atn)+"</span>"; break;
5571 case 5 : ;
5572 case 6 : tmp+="<span class=\"at_"+hashActivityTagIDsTimetable.value(atn)+"\" onmouseover=\"highlight('at_"+hashActivityTagIDsTimetable.value(atn)+"')\">"+protect2(atn)+"</span>"; break;
5573 default: tmp+=protect2(atn); break;
5574 }
5575 tmp+=", ";
5576 }
5577 }
5578 tmp.remove(tmp.size()-2, 2);
5579 if(!activityTagsOnly){
5580 if(htmlLevel>=3){
5581 tmp+="</span>";
5582 }
5583 }
5584 }
5585 }
5586 if(startTag=="div"){
5587 if(htmlLevel>=3)
5588 tmp+="</div>";
5589 else tmp+="<br />";
5590 }
5591 }
5592 return tmp;
5593 }
5594
5595 // by Volker Dirr
writeStudents(int htmlLevel,const Activity * act,const QString & startTag,const QString & startTagAttribute)5596 QString TimetableExport::writeStudents(int htmlLevel, const Activity* act, const QString& startTag, const QString& startTagAttribute){
5597 QString tmp;
5598 if(act->studentsNames.size()>0){
5599 if(startTag=="div" && htmlLevel>=3)
5600 tmp+="<"+startTag+startTagAttribute+">";
5601 for(const QString& st : qAsConst(act->studentsNames)){
5602 switch(htmlLevel){
5603 case 4 : tmp+="<span class=\"ss_"+hashStudentIDsTimetable.value(st)+"\">"+protect2(st)+"</span>"; break;
5604 case 5 : ;
5605 case 6 : tmp+="<span class=\"ss_"+hashStudentIDsTimetable.value(st)+"\" onmouseover=\"highlight('ss_"+hashStudentIDsTimetable.value(st)+"')\">"+protect2(st)+"</span>"; break;
5606 default: tmp+=protect2(st); break;
5607 }
5608 tmp+=", ";
5609 }
5610 tmp.remove(tmp.size()-2, 2);
5611 if(startTag=="div"){
5612 if(htmlLevel>=3)
5613 tmp+="</div>";
5614 else tmp+="<br />";
5615 }
5616 }
5617 return tmp;
5618 }
5619
5620 // by Volker Dirr
writeTeachers(int htmlLevel,const Activity * act,const QString & startTag,const QString & startTagAttribute)5621 QString TimetableExport::writeTeachers(int htmlLevel, const Activity* act, const QString& startTag, const QString& startTagAttribute){
5622 QString tmp;
5623 if(act->teachersNames.size()>0){
5624 if(startTag=="div" && htmlLevel>=3)
5625 tmp+="<"+startTag+startTagAttribute+">";
5626 for(const QString& t : qAsConst(act->teachersNames)){
5627 switch(htmlLevel){
5628 case 4 : tmp+="<span class=\"t_"+hashTeacherIDsTimetable.value(t)+"\">"+protect2(t)+"</span>"; break;
5629 case 5 : ;
5630 case 6 : tmp+="<span class=\"t_"+hashTeacherIDsTimetable.value(t)+"\" onmouseover=\"highlight('t_"+hashTeacherIDsTimetable.value(t)+"')\">"+protect2(t)+"</span>"; break;
5631 default: tmp+=protect2(t); break;
5632 }
5633 tmp+=", ";
5634 }
5635 tmp.remove(tmp.size()-2, 2);
5636 if(startTag=="div"){
5637 if(htmlLevel>=3)
5638 tmp+="</div>";
5639 else tmp+="<br />";
5640 }
5641 }
5642 return tmp;
5643 }
5644
5645 // by Volker Dirr
writeRoom(int htmlLevel,int ai,const QString & startTag,const QString & startTagAttribute)5646 QString TimetableExport::writeRoom(int htmlLevel, int ai, const QString& startTag, const QString& startTagAttribute){
5647 QString tmp;
5648 int r=best_solution.rooms[ai];
5649 if(r!=UNALLOCATED_SPACE && r!=UNSPECIFIED_ROOM){
5650 if(startTag=="div" && htmlLevel>=3)
5651 tmp+="<"+startTag+startTagAttribute+">";
5652
5653 if(gt.rules.internalRoomsList[r]->isVirtual==false){
5654 switch(htmlLevel){
5655 case 4 : tmp+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"\">"+protect2(gt.rules.internalRoomsList[r]->name)+"</span>"; break;
5656 case 5 : ;
5657 case 6 : tmp+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"\" onmouseover=\"highlight('r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"')\">"+protect2(gt.rules.internalRoomsList[r]->name)+"</span>"; break;
5658 default: tmp+=protect2(gt.rules.internalRoomsList[r]->name); break;
5659 }
5660 } else {
5661 QStringList rooms;
5662 if(SHOW_VIRTUAL_ROOMS_IN_TIMETABLES){
5663 switch(htmlLevel){
5664 case 4 : tmp+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"\">"+protect2(gt.rules.internalRoomsList[r]->name)+"</span>"; break;
5665 case 5 : ;
5666 case 6 : tmp+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"\" onmouseover=\"highlight('r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[r]->name)+"')\">"+protect2(gt.rules.internalRoomsList[r]->name)+"</span>"; break;
5667 default: tmp+=protect2(gt.rules.internalRoomsList[r]->name); break;
5668 }
5669 //tmp+="Virtual Room X";
5670 tmp+=" (";
5671 }
5672 for(int rr : qAsConst(best_solution.realRoomsList[ai])){
5673 QString room;
5674 switch(htmlLevel){
5675 case 4 : room+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[rr]->name)+"\">"+protect2(gt.rules.internalRoomsList[rr]->name)+"</span>"; break;
5676 case 5 : ;
5677 case 6 : room+="<span class=\"r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[rr]->name)+"\" onmouseover=\"highlight('r_"+hashRoomIDsTimetable.value(gt.rules.internalRoomsList[rr]->name)+"')\">"+protect2(gt.rules.internalRoomsList[rr]->name)+"</span>"; break;
5678 default: room+=protect2(gt.rules.internalRoomsList[rr]->name); break;
5679 }
5680 rooms.append(room);
5681 }
5682 tmp+=rooms.join(", ");
5683 if(SHOW_VIRTUAL_ROOMS_IN_TIMETABLES){
5684 tmp+=")";
5685 }
5686 }
5687
5688 if(startTag=="div"){
5689 if(htmlLevel>=3)
5690 tmp+="</div>";
5691 else tmp+="<br />";
5692 }
5693 }
5694 return tmp;
5695 }
5696
5697 // by Volker Dirr
writeNotAvailableSlot(int htmlLevel,const QString & weight)5698 QString TimetableExport::writeNotAvailableSlot(int htmlLevel, const QString& weight){
5699 QString tmp;
5700 //weight=" "+weight;
5701 switch(htmlLevel){
5702 case 3 : ;
5703 case 4 : tmp=" <td class=\"notAvailable\"><span class=\"notAvailable\">"+protect2(STRING_NOT_AVAILABLE_TIME_SLOT)+weight+"</span></td>\n"; break;
5704 case 5 : ;
5705 case 6 : tmp=" <td class=\"notAvailable\"><span class=\"notAvailable\" onmouseover=\"highlight('notAvailable')\">"+protect2(STRING_NOT_AVAILABLE_TIME_SLOT)+weight+"</span></td>\n"; break;
5706 case 7 : tmp=" <td class=\"notAvailable\"><span class=\"notAvailable\">"+protect2(STRING_NOT_AVAILABLE_TIME_SLOT)+weight+"</span></td>\n"; break;
5707 default: tmp=" <td>"+protect2(STRING_NOT_AVAILABLE_TIME_SLOT)+weight+"</td>\n";
5708 }
5709 return tmp;
5710 }
5711
5712 // by Volker Dirr
writeBreakSlot(int htmlLevel,const QString & weight)5713 QString TimetableExport::writeBreakSlot(int htmlLevel, const QString& weight){
5714 QString tmp;
5715 //weight=" "+weight;
5716 switch(htmlLevel){
5717 case 3 : ;
5718 case 4 : tmp=" <td class=\"break\"><span class=\"break\">"+protect2(STRING_BREAK_SLOT)+weight+"</span></td>\n"; break;
5719 case 5 : ;
5720 case 6 : tmp=" <td class=\"break\"><span class=\"break\" onmouseover=\"highlight('break')\">"+protect2(STRING_BREAK_SLOT)+weight+"</span></td>\n"; break;
5721 case 7 : tmp=" <td class=\"break\"><span class=\"break\">"+protect2(STRING_BREAK_SLOT)+weight+"</span></td>\n"; break;
5722 default: tmp=" <td>"+protect2(STRING_BREAK_SLOT)+weight+"</td>\n";
5723 }
5724 return tmp;
5725 }
5726
5727 // by Volker Dirr
writeEmpty(int htmlLevel)5728 QString TimetableExport::writeEmpty(int htmlLevel){
5729 QString tmp;
5730 switch(htmlLevel){
5731 case 3 : ;
5732 case 4 : tmp=" <td class=\"empty\"><span class=\"empty\">"+protect2(STRING_EMPTY_SLOT)+"</span></td>\n"; break;
5733 case 5 : ;
5734 case 6 : tmp=" <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"+protect2(STRING_EMPTY_SLOT)+"</span></td>\n"; break;
5735 case 7 : tmp=" <td class=\"empty\"><span class=\"empty\">"+protect2(STRING_EMPTY_SLOT)+"</span></td>\n"; break;
5736 default: tmp=" <td>"+protect2(STRING_EMPTY_SLOT)+"</td>\n";
5737 }
5738 return tmp;
5739 }
5740
5741 //by Volker Dirr
writeActivityStudents(int htmlLevel,int ai,int day,int hour,bool notAvailable,bool colspan,bool rowspan,bool printActivityTags,QString skipStudentsSet)5742 QString TimetableExport::writeActivityStudents(int htmlLevel, int ai, int day, int hour, bool notAvailable, bool colspan, bool rowspan, bool printActivityTags, QString skipStudentsSet){
5743 QString tmp;
5744 int currentTime=day+gt.rules.nDaysPerWeek*hour;
5745 if(ai!=UNALLOCATED_ACTIVITY){
5746 if(best_solution.times[ai]==currentTime){
5747 Activity* act=>.rules.internalActivitiesList[ai];
5748 tmp+=writeStartTagTDofActivities(htmlLevel, act, false, colspan, rowspan, COLOR_BY_SUBJECT);
5749 //TODO line0
5750 bool skipLine0=false;
5751 if(act->studentsNames.size()==1){
5752 if(act->studentsNames.at(0)==skipStudentsSet){
5753 skipLine0=true;
5754 }
5755 }
5756 if(!skipLine0){
5757 tmp+=writeStudents(htmlLevel, act, "div", " class=\"studentsset line0\"");
5758 }
5759 tmp+=writeSubjectAndActivityTags(htmlLevel, act, "div", " class=\"line1\"", false, printActivityTags);
5760 tmp+=writeTeachers(htmlLevel, act, "div", " class=\"teacher line2\"");
5761 tmp+=writeRoom(htmlLevel, ai, "div", " class=\"room line3\"");
5762 tmp+="</td>\n";
5763 } else
5764 tmp+=" <!-- span -->\n";
5765 } else {
5766 if(notAvailable && PRINT_NOT_AVAILABLE_TIME_SLOTS){
5767 tmp+=writeNotAvailableSlot(htmlLevel, "");
5768 }
5769 else if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
5770 tmp+=writeBreakSlot(htmlLevel, "");
5771 }
5772 else{
5773 tmp+=writeEmpty(htmlLevel);
5774 }
5775 }
5776 return tmp;
5777 }
5778
5779 //by Volker Dirr
writeActivitiesStudents(int htmlLevel,const QList<int> & allActivities,bool printActivityTags)5780 QString TimetableExport::writeActivitiesStudents(int htmlLevel, const QList<int>& allActivities, bool printActivityTags){
5781 QString tmp;
5782 if(htmlLevel>=1)
5783 tmp+=" <td><table class=\"detailed\">";
5784 else
5785 tmp+=" <td><table>";
5786 if(htmlLevel>=3)
5787 tmp+="<tr class=\"studentsset line0\">";
5788 else tmp+="<tr>";
5789 for(int a=0; a<allActivities.size(); a++){
5790 int ai=allActivities[a];
5791 if(ai!=UNALLOCATED_ACTIVITY){
5792 Activity* act=>.rules.internalActivitiesList[ai];
5793 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT)+writeStudents(htmlLevel, act, "", "")+"</td>";
5794 }
5795 }
5796 tmp+="</tr>";
5797 if(htmlLevel>=3)
5798 tmp+="<tr class=\"line1\">";
5799 else tmp+="<tr>";
5800 for(int a=0; a<allActivities.size(); a++){
5801 int ai=allActivities[a];
5802 if(ai!=UNALLOCATED_ACTIVITY){
5803 Activity* act=>.rules.internalActivitiesList[ai];
5804 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT)+writeSubjectAndActivityTags(htmlLevel, act, "", "", false, printActivityTags)+"</td>";
5805 }
5806 }
5807 tmp+="</tr>";
5808 if(htmlLevel>=3)
5809 tmp+="<tr class=\"teacher line2\">";
5810 else tmp+="<tr>";
5811 for(int a=0; a<allActivities.size(); a++){
5812 int ai=allActivities[a];
5813 if(ai!=UNALLOCATED_ACTIVITY){
5814 Activity* act=>.rules.internalActivitiesList[ai];
5815 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT)+writeTeachers(htmlLevel, act, "", "")+"</td>";
5816 }
5817 }
5818 tmp+="</tr>";
5819 if(htmlLevel>=3)
5820 tmp+="<tr class=\"room line3\">";
5821 else tmp+="<tr>";
5822 for(int a=0; a<allActivities.size(); a++){
5823 int ai=allActivities[a];
5824 if(ai!=UNALLOCATED_ACTIVITY){
5825 Activity* act=>.rules.internalActivitiesList[ai];
5826 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT)+writeRoom(htmlLevel, ai, "", "")+"</td>";
5827 }
5828 }
5829 tmp+="</tr>";
5830 tmp+="</table></td>\n";
5831 return tmp;
5832 }
5833
5834 //by Volker Dirr
writeActivityTeacher(int htmlLevel,int teacher,int day,int hour,bool colspan,bool rowspan,bool printActivityTags,QString skipTeacher)5835 QString TimetableExport::writeActivityTeacher(int htmlLevel, int teacher, int day, int hour, bool colspan, bool rowspan, bool printActivityTags, QString skipTeacher){
5836 QString tmp;
5837 int ai=teachers_timetable_weekly[teacher][day][hour];
5838 int currentTime=day+gt.rules.nDaysPerWeek*hour;
5839 if(ai!=UNALLOCATED_ACTIVITY){
5840 if(best_solution.times[ai]==currentTime){
5841 Activity* act=>.rules.internalActivitiesList[ai];
5842 tmp+=writeStartTagTDofActivities(htmlLevel, act, false, colspan, rowspan, COLOR_BY_SUBJECT_STUDENTS);
5843 //TODO line0
5844 bool skipLine0=false;
5845 if(act->teachersNames.size()==1){
5846 if(act->teachersNames.at(0)==skipTeacher){
5847 skipLine0=true;
5848 }
5849 }
5850 if(!skipLine0){
5851 tmp+=writeTeachers(htmlLevel, act, "div", " class=\"teacher line0\"");
5852 }
5853 tmp+=writeStudents(htmlLevel, act, "div", " class=\"studentsset line1\"");
5854 tmp+=writeSubjectAndActivityTags(htmlLevel, act, "div", " class=\"line2\"", false, printActivityTags);
5855 tmp+=writeRoom(htmlLevel, ai, "div", " class=\"room line3\"");
5856 tmp+="</td>\n";
5857 } else
5858 tmp+=" <!-- span -->\n";
5859 } else {
5860 if(teacherNotAvailableDayHour[teacher][day][hour] && PRINT_NOT_AVAILABLE_TIME_SLOTS){
5861 tmp+=writeNotAvailableSlot(htmlLevel, "");
5862 }
5863 else if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
5864 tmp+=writeBreakSlot(htmlLevel, "");
5865 }
5866 else{
5867 tmp+=writeEmpty(htmlLevel);
5868 }
5869 }
5870 return tmp;
5871 }
5872
5873 //by Volker Dirr
writeActivitiesTeachers(int htmlLevel,const QList<int> & allActivities,bool printActivityTags)5874 QString TimetableExport::writeActivitiesTeachers(int htmlLevel, const QList<int>& allActivities, bool printActivityTags){
5875 QString tmp;
5876 if(htmlLevel>=1)
5877 tmp+=" <td><table class=\"detailed\">";
5878 else
5879 tmp+=" <td><table>";
5880 if(htmlLevel>=3)
5881 tmp+="<tr class=\"teacher line0\">";
5882 else tmp+="<tr>";
5883 for(int a=0; a<allActivities.size(); a++){
5884 int ai=allActivities[a];
5885 if(ai!=UNALLOCATED_ACTIVITY){
5886 Activity* act=>.rules.internalActivitiesList[ai];
5887 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeTeachers(htmlLevel, act, "", "")+"</td>";
5888 }
5889 }
5890 tmp+="</tr>";
5891 if(htmlLevel>=3)
5892 tmp+="<tr class=\"studentsset line1\">";
5893 else tmp+="<tr>";
5894 for(int a=0; a<allActivities.size(); a++){
5895 int ai=allActivities[a];
5896 if(ai!=UNALLOCATED_ACTIVITY){
5897 Activity* act=>.rules.internalActivitiesList[ai];
5898 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeStudents(htmlLevel, act, "", "")+"</td>";
5899 }
5900 }
5901 tmp+="</tr>";
5902 if(htmlLevel>=3)
5903 tmp+="<tr class=\"line2\">";
5904 else tmp+="<tr>";
5905 for(int a=0; a<allActivities.size(); a++){
5906 int ai=allActivities[a];
5907 if(ai!=UNALLOCATED_ACTIVITY){
5908 Activity* act=>.rules.internalActivitiesList[ai];
5909 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeSubjectAndActivityTags(htmlLevel, act, "", "", false, printActivityTags)+"</td>";
5910 }
5911 }
5912 tmp+="</tr>";
5913
5914 if(htmlLevel>=3)
5915 tmp+="<tr class=\"room line3\">";
5916 else tmp+="<tr>";
5917 for(int a=0; a<allActivities.size(); a++){
5918 int ai=allActivities[a];
5919 if(ai!=UNALLOCATED_ACTIVITY){
5920 Activity* act=>.rules.internalActivitiesList[ai];
5921 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeRoom(htmlLevel, ai, "", "")+"</td>";
5922 }
5923 }
5924 tmp+="</tr>";
5925 tmp+="</table></td>\n";
5926 return tmp;
5927 }
5928
5929 //by Volker Dirr
writeActivityRoom(int htmlLevel,int room,int day,int hour,bool colspan,bool rowspan,bool printActivityTags)5930 QString TimetableExport::writeActivityRoom(int htmlLevel, int room, int day, int hour, bool colspan, bool rowspan, bool printActivityTags){
5931 QString tmp;
5932 int ai=rooms_timetable_weekly[room][day][hour];
5933 int currentTime=day+gt.rules.nDaysPerWeek*hour;
5934 if(ai!=UNALLOCATED_ACTIVITY){
5935 if(best_solution.times[ai]==currentTime){
5936 Activity* act=>.rules.internalActivitiesList[ai];
5937 tmp+=writeStartTagTDofActivities(htmlLevel, act, false, colspan, rowspan, COLOR_BY_SUBJECT_STUDENTS);
5938 //Each activity has only a single room. So there is no need for line0. Modify this as soon as FET supports multiple rooms per activity.
5939 tmp+=writeStudents(htmlLevel, act, "div", " class=\"studentsset line1\"");
5940 tmp+=writeTeachers(htmlLevel, act, "div", " class=\"teacher line2\"");
5941 tmp+=writeSubjectAndActivityTags(htmlLevel, act, "div", " class=\"line3\"", false, printActivityTags);
5942 tmp+="</td>\n";
5943 } else
5944 tmp+=" <!-- span -->\n";
5945 } else {
5946 if(notAllowedRoomTimePercentages[room][day+hour*gt.rules.nDaysPerWeek]>=0 && PRINT_NOT_AVAILABLE_TIME_SLOTS){
5947 tmp+=writeNotAvailableSlot(htmlLevel, "");
5948 }
5949 else if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
5950 tmp+=writeBreakSlot(htmlLevel, "");
5951 }
5952 else{
5953 tmp+=writeEmpty(htmlLevel);
5954 }
5955 }
5956 return tmp;
5957 }
5958
5959 //by Volker Dirr
writeActivitiesRooms(int htmlLevel,const QList<int> & allActivities,bool printActivityTags)5960 QString TimetableExport::writeActivitiesRooms(int htmlLevel, const QList<int>& allActivities, bool printActivityTags){
5961 QString tmp;
5962 if(htmlLevel>=1)
5963 tmp+=" <td><table class=\"detailed\">";
5964 else
5965 tmp+=" <td><table>";
5966 if(htmlLevel>=3)
5967 tmp+="<tr class=\"room line0\">";
5968 else tmp+="<tr>";
5969 for(int a=0; a<allActivities.size(); a++){
5970 int ai=allActivities[a];
5971 if(ai!=UNALLOCATED_ACTIVITY){
5972 Activity* act=>.rules.internalActivitiesList[ai];
5973 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeRoom(htmlLevel, ai, "", "")+"</td>";
5974 }
5975 }
5976 tmp+="</tr>";
5977 if(htmlLevel>=3)
5978 tmp+="<tr class=\"studentsset line1\">";
5979 else tmp+="<tr>";
5980 for(int a=0; a<allActivities.size(); a++){
5981 int ai=allActivities[a];
5982 if(ai!=UNALLOCATED_ACTIVITY){
5983 Activity* act=>.rules.internalActivitiesList[ai];
5984 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeStudents(htmlLevel, act, "", "")+"</td>";
5985 }
5986 }
5987 tmp+="</tr>";
5988 if(htmlLevel>=3)
5989 tmp+="<tr class=\"teacher line2\">";
5990 else tmp+="<tr>";
5991 for(int a=0; a<allActivities.size(); a++){
5992 int ai=allActivities[a];
5993 if(ai!=UNALLOCATED_ACTIVITY){
5994 Activity* act=>.rules.internalActivitiesList[ai];
5995 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeTeachers(htmlLevel, act, "", "")+"</td>";
5996 }
5997 }
5998 tmp+="</tr>";
5999 if(htmlLevel>=3)
6000 tmp+="<tr class=\"line3\">";
6001 else tmp+="<tr>";
6002 for(int a=0; a<allActivities.size(); a++){
6003 int ai=allActivities[a];
6004 if(ai!=UNALLOCATED_ACTIVITY){
6005 Activity* act=>.rules.internalActivitiesList[ai];
6006 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeSubjectAndActivityTags(htmlLevel, act, "", "", false, printActivityTags)+"</td>";
6007 }
6008 }
6009 tmp+="</tr>";
6010
6011 tmp+="</table></td>\n";
6012 return tmp;
6013 }
6014
6015 //by Volker Dirr
writeActivitiesSubjects(int htmlLevel,const QList<int> & allActivities,bool printActivityTags)6016 QString TimetableExport::writeActivitiesSubjects(int htmlLevel, const QList<int>& allActivities, bool printActivityTags){
6017 QString tmp;
6018 if(allActivities.isEmpty()){
6019 tmp+=writeEmpty(htmlLevel);
6020 } else {
6021 if(htmlLevel>=1)
6022 tmp+=" <td><table class=\"detailed\">";
6023 else
6024 tmp+=" <td><table>";
6025 //Each activity has only a single subject. So there is no need for subjects in line0. Modify this as soon as FET supports multiple subjects per activity.
6026 if(printActivityTags){
6027 if(htmlLevel>=3)
6028 tmp+="<tr class=\"line0 activitytag\">";
6029 else tmp+="<tr>";
6030 for(int a=0; a<allActivities.size(); a++){
6031 Activity* act=>.rules.internalActivitiesList[allActivities[a]];
6032 Activity* act0=>.rules.internalActivitiesList[allActivities[0]]; //Because this is always the original subject. We don't need to repeat it, because it is displayed in the tables head
6033 if(act->subjectName==act0->subjectName){
6034 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeSubjectAndActivityTags(htmlLevel, act, "", "", true, printActivityTags)+"</td>";
6035 } else {
6036 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeSubjectAndActivityTags(htmlLevel, act, "", "", false, printActivityTags)+"</td>";
6037 }
6038 }
6039 tmp+="</tr>";
6040 }
6041 if(htmlLevel>=3)
6042 tmp+="<tr class=\"studentsset line1\">";
6043 else tmp+="<tr>";
6044 for(int a=0; a<allActivities.size(); a++){
6045 Activity* act=>.rules.internalActivitiesList[allActivities[a]];
6046 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeStudents(htmlLevel, act, "", "")+"</td>";
6047 }
6048 tmp+="</tr>";
6049 if(htmlLevel>=3)
6050 tmp+="<tr class=\"teacher line2\">";
6051 else tmp+="<tr>";
6052 for(int a=0; a<allActivities.size(); a++){
6053 Activity* act=>.rules.internalActivitiesList[allActivities[a]];
6054 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeTeachers(htmlLevel, act, "", "")+"</td>";
6055 }
6056 tmp+="</tr>";
6057 if(htmlLevel>=3)
6058 tmp+="<tr class=\"room line3\">";
6059 else tmp+="<tr>";
6060 for(int a=0; a<allActivities.size(); a++){
6061 int ai=allActivities[a];
6062 Activity* act=>.rules.internalActivitiesList[ai];
6063 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeRoom(htmlLevel, ai, "", "")+"</td>";
6064 }
6065 tmp+="</tr>";
6066 tmp+="</table></td>\n";
6067 }
6068 return tmp;
6069 }
6070
6071 //by Volker Dirr
writeActivitiesActivityTags(int htmlLevel,const QList<int> & allActivities,bool printActivityTags)6072 QString TimetableExport::writeActivitiesActivityTags(int htmlLevel, const QList<int>& allActivities, bool printActivityTags){
6073 QString tmp;
6074 if(allActivities.isEmpty()){
6075 tmp+=writeEmpty(htmlLevel);
6076 } else {
6077 if(htmlLevel>=1)
6078 tmp+=" <td><table class=\"detailed\">";
6079 else
6080 tmp+=" <td><table>";
6081
6082 if(htmlLevel>=3)
6083 tmp+="<tr class=\"line0\">";
6084 else tmp+="<tr>";
6085 for(int a=0; a<allActivities.size(); a++){
6086 int ai=allActivities[a];
6087 if(ai!=UNALLOCATED_ACTIVITY){
6088 Activity* act=>.rules.internalActivitiesList[ai];
6089 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeSubjectAndActivityTags(htmlLevel, act, "", "", false, printActivityTags)+"</td>";
6090 }
6091 }
6092 tmp+="</tr>";
6093
6094 if(htmlLevel>=3)
6095 tmp+="<tr class=\"studentsset line1\">";
6096 else tmp+="<tr>";
6097 for(int a=0; a<allActivities.size(); a++){
6098 Activity* act=>.rules.internalActivitiesList[allActivities[a]];
6099 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeStudents(htmlLevel, act, "", "")+"</td>";
6100 }
6101 tmp+="</tr>";
6102 if(htmlLevel>=3)
6103 tmp+="<tr class=\"teacher line2\">";
6104 else tmp+="<tr>";
6105 for(int a=0; a<allActivities.size(); a++){
6106 Activity* act=>.rules.internalActivitiesList[allActivities[a]];
6107 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeTeachers(htmlLevel, act, "", "")+"</td>";
6108 }
6109 tmp+="</tr>";
6110 if(htmlLevel>=3)
6111 tmp+="<tr class=\"room line3\">";
6112 else tmp+="<tr>";
6113 for(int a=0; a<allActivities.size(); a++){
6114 int ai=allActivities[a];
6115 Activity* act=>.rules.internalActivitiesList[ai];
6116 tmp+=writeStartTagTDofActivities(htmlLevel, act, true, false, false, COLOR_BY_SUBJECT_STUDENTS)+writeRoom(htmlLevel, ai, "", "")+"</td>";
6117 }
6118 tmp+="</tr>";
6119 tmp+="</table></td>\n";
6120 }
6121 return tmp;
6122 }
6123
6124
6125 //the following functions return a single html table (needed for html file export and printing)
6126
6127 //by Volker Dirr
singleSubgroupsTimetableDaysHorizontalHtml(int htmlLevel,int subgroup,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6128 QString TimetableExport::singleSubgroupsTimetableDaysHorizontalHtml(int htmlLevel, int subgroup, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6129 int realSubgroup;
6130 if(subgroupsSortedOrder!=QList<int>())
6131 realSubgroup=subgroupsSortedOrder.at(subgroup);
6132 else
6133 realSubgroup=subgroup;
6134
6135 assert(realSubgroup>=0);
6136 assert(realSubgroup<gt.rules.nInternalSubgroups);
6137 QString tmpString;
6138 QString subgroup_name = gt.rules.internalSubgroupsList[realSubgroup]->name;
6139 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(subgroup_name)+"\" border=\"1\"";
6140 if(subgroup%2==0) tmpString+=" class=\"odd_table\"";
6141 else tmpString+=" class=\"even_table\"";
6142 tmpString+=">\n";
6143
6144 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6145 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(subgroup_name)+"</th>";
6146 if(repeatNames){
6147 tmpString+="<td rowspan=\"2\"></td>";
6148 }
6149 tmpString+="</tr>\n";
6150 tmpString+=" <tr>\n <!-- span -->\n";
6151 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6152 if(htmlLevel>=2)
6153 tmpString+=" <th class=\"xAxis\">";
6154 else
6155 tmpString+=" <th>";
6156 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6157 }
6158 tmpString+=" </tr>\n";
6159 tmpString+=" </thead>\n";
6160 /*workaround
6161 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6162 */
6163 tmpString+=" <tbody>\n";
6164 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6165 tmpString+=" <tr>\n";
6166 if(htmlLevel>=2)
6167 tmpString+=" <th class=\"yAxis\">";
6168 else
6169 tmpString+=" <th>";
6170 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6171 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6172 QList<int> allActivities;
6173 allActivities.clear();
6174 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6175 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6176 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6177 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], false, true, printActivityTags, subgroup_name);
6178 } else{
6179 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6180 }
6181 }
6182 if(repeatNames){
6183 if(htmlLevel>=2)
6184 tmpString+=" <th class=\"yAxis\">";
6185 else
6186 tmpString+=" <th>";
6187 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6188 }
6189 tmpString+=" </tr>\n";
6190 }
6191 //workaround begin.
6192 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6193 if(repeatNames){
6194 tmpString+="<td></td>";
6195 }
6196 tmpString+="</tr>\n";
6197 //workaround end.
6198 tmpString+=" </tbody>\n";
6199 tmpString+=" </table>\n\n";
6200 return tmpString;
6201 }
6202
6203 //by Volker Dirr
singleSubgroupsTimetableDaysVerticalHtml(int htmlLevel,int subgroup,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6204 QString TimetableExport::singleSubgroupsTimetableDaysVerticalHtml(int htmlLevel, int subgroup, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6205 int realSubgroup;
6206 if(subgroupsSortedOrder!=QList<int>())
6207 realSubgroup=subgroupsSortedOrder.at(subgroup);
6208 else
6209 realSubgroup=subgroup;
6210
6211 assert(realSubgroup>=0);
6212 assert(realSubgroup<gt.rules.nInternalSubgroups);
6213 QString tmpString;
6214 QString subgroup_name = gt.rules.internalSubgroupsList[realSubgroup]->name;
6215 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(subgroup_name)+"\" border=\"1\"";
6216 if(subgroup%2==0) tmpString+=" class=\"odd_table\"";
6217 else tmpString+=" class=\"even_table\"";
6218 tmpString+=">\n";
6219
6220 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6221 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(subgroup_name)+"</th>";
6222 if(repeatNames){
6223 tmpString+="<td rowspan=\"2\"></td>";
6224 }
6225 tmpString+="</tr>\n";
6226 tmpString+=" <tr>\n <!-- span -->\n";
6227 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6228 if(htmlLevel>=2)
6229 tmpString+=" <th class=\"xAxis\">";
6230 else
6231 tmpString+=" <th>";
6232 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6233 }
6234 tmpString+=" </tr>\n";
6235 tmpString+=" </thead>\n";
6236 /*workaround
6237 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6238 */
6239 tmpString+=" <tbody>\n";
6240 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6241 tmpString+=" <tr>\n";
6242 if(htmlLevel>=2)
6243 tmpString+=" <th class=\"yAxis\">";
6244 else
6245 tmpString+=" <th>";
6246 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6247 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6248 QList<int> allActivities;
6249 allActivities.clear();
6250 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6251 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6252 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6253 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], true, false, printActivityTags, subgroup_name);
6254 } else{
6255 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6256 }
6257 }
6258 if(repeatNames){
6259 if(htmlLevel>=2)
6260 tmpString+=" <th class=\"yAxis\">";
6261 else
6262 tmpString+=" <th>";
6263 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6264 }
6265 tmpString+=" </tr>\n";
6266 }
6267 //workaround begin.
6268 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6269 if(repeatNames){
6270 tmpString+="<td></td>";
6271 }
6272 tmpString+="</tr>\n";
6273 //workaround end.
6274 tmpString+=" </tbody>\n";
6275 tmpString+=" </table>\n\n";
6276 return tmpString;
6277 }
6278
6279 //by Volker Dirr
singleSubgroupsTimetableTimeVerticalHtml(int htmlLevel,int maxSubgroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6280 QString TimetableExport::singleSubgroupsTimetableTimeVerticalHtml(int htmlLevel, int maxSubgroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6281 QString tmpString;
6282 tmpString+=" <table border=\"1\">\n";
6283 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6284
6285 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
6286
6287 int currentCount=0;
6288 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6289 int realSubgroup;
6290 if(subgroupsSortedOrder!=QList<int>())
6291 realSubgroup=subgroupsSortedOrder.at(subgroup);
6292 else
6293 realSubgroup=subgroup;
6294
6295 if(!excludedNames.contains(subgroup)){
6296 currentCount++;
6297 if(htmlLevel>=2)
6298 tmpString+=" <th class=\"xAxis\">";
6299 else
6300 tmpString+=" <th>";
6301 tmpString+=gt.rules.internalSubgroupsList[realSubgroup]->name+"</th>";
6302 }
6303 }
6304 if(repeatNames){
6305 tmpString+="<td colspan=\"2\"></td>";
6306 }
6307 tmpString+="</tr>\n </thead>\n";
6308 /*workaround
6309 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6310 */
6311 tmpString+=" <tbody>\n";
6312 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6313 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6314 tmpString+=" <tr>\n";
6315 if(hour==0)
6316 tmpString+=" <th rowspan=\"" +QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6317 else tmpString+=" <!-- span -->\n";
6318
6319 if(htmlLevel>=2)
6320 tmpString+=" <th class=\"yAxis\">";
6321 else
6322 tmpString+=" <th>";
6323 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6324 currentCount=0;
6325 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6326 int realSubgroup;
6327 if(subgroupsSortedOrder!=QList<int>())
6328 realSubgroup=subgroupsSortedOrder.at(subgroup);
6329 else
6330 realSubgroup=subgroup;
6331
6332 if(!excludedNames.contains(subgroup)){
6333 currentCount++;
6334 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
6335 excludedNames<<subgroup;
6336 QList<int> allActivities;
6337 allActivities.clear();
6338 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6339 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6340 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6341 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], false, true, printActivityTags, gt.rules.internalSubgroupsList[realSubgroup]->name);
6342 } else{
6343 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6344 }
6345 }
6346 }
6347 if(repeatNames){
6348 if(htmlLevel>=2)
6349 tmpString+=" <th class=\"yAxis\">";
6350 else
6351 tmpString+=" <th>";
6352 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6353
6354 if(hour==0)
6355 tmpString+=" <th rowspan=\"" +QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6356 else tmpString+=" <!-- span -->\n";
6357 }
6358 tmpString+=" </tr>\n";
6359 }
6360 }
6361 //workaround begin.
6362 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6363 if(repeatNames){
6364 tmpString+="<td colspan=\"2\"></td>";
6365 }
6366 tmpString+="</tr>\n";
6367 //workaround end.
6368 tmpString+=" </tbody>\n </table>\n";
6369 return tmpString;
6370 }
6371
6372 //by Volker Dirr
singleSubgroupsTimetableTimeHorizontalHtml(int htmlLevel,int maxSubgroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6373 QString TimetableExport::singleSubgroupsTimetableTimeHorizontalHtml(int htmlLevel, int maxSubgroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6374 QString tmpString;
6375 tmpString+=" <table border=\"1\">\n";
6376 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6377
6378 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
6379 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6380 tmpString+="<th colspan=\"" +QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
6381 }
6382 if(repeatNames){
6383 tmpString+="<td rowspan=\"2\"></td>";
6384 }
6385 tmpString+=" </tr>\n";
6386 tmpString+=" <tr>\n <!-- span -->\n";
6387 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6388 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6389 if(htmlLevel>=2)
6390 tmpString+=" <th class=\"xAxis\">";
6391 else
6392 tmpString+=" <th>";
6393 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6394 }
6395 }
6396 tmpString+=" </tr>\n";
6397 tmpString+=" </thead>\n";
6398 /*workaround
6399 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6400 */
6401 tmpString+=" <tbody>\n";
6402
6403 int currentCount=0;
6404 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6405 int realSubgroup;
6406 if(subgroupsSortedOrder!=QList<int>())
6407 realSubgroup=subgroupsSortedOrder.at(subgroup);
6408 else
6409 realSubgroup=subgroup;
6410
6411 if(!excludedNames.contains(subgroup)){
6412 currentCount++;
6413 excludedNames<<subgroup;
6414 tmpString+=" <tr>\n";
6415 if(htmlLevel>=2)
6416 tmpString+=" <th class=\"yAxis\">";
6417 else
6418 tmpString+=" <th>";
6419 tmpString+=protect2(gt.rules.internalSubgroupsList[realSubgroup]->name)+"</th>\n";
6420 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6421 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6422 QList<int> allActivities;
6423 allActivities.clear();
6424 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6425 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6426 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6427 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], true, false, printActivityTags, gt.rules.internalSubgroupsList[realSubgroup]->name);
6428 } else{
6429 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6430 }
6431 }
6432 }
6433 if(repeatNames){
6434 if(htmlLevel>=2)
6435 tmpString+=" <th class=\"yAxis\">";
6436 else
6437 tmpString+=" <th>";
6438 tmpString+=protect2(gt.rules.internalSubgroupsList[realSubgroup]->name)+"</th>\n";
6439 }
6440 tmpString+=" </tr>\n";
6441 }
6442 }
6443 //workaround begin.
6444 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6445 if(repeatNames){
6446 tmpString+="<td></td>";
6447 }
6448 tmpString+="</tr>\n";
6449 //workaround end.
6450 tmpString+=" </tbody>\n </table>\n";
6451 return tmpString;
6452 }
6453
6454 //by Volker Dirr
singleSubgroupsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxSubgroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6455 QString TimetableExport::singleSubgroupsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxSubgroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6456 assert(day>=0);
6457 assert(day<gt.rules.nDaysPerWeek);
6458
6459 QString tmpString;
6460 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
6461 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6462
6463 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
6464 int currentCount=0;
6465 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6466 int realSubgroup;
6467 if(subgroupsSortedOrder!=QList<int>())
6468 realSubgroup=subgroupsSortedOrder.at(subgroup);
6469 else
6470 realSubgroup=subgroup;
6471
6472 if(!excludedNames.contains(subgroup)){
6473 currentCount++;
6474 if(htmlLevel>=2)
6475 tmpString+=" <th class=\"xAxis\">";
6476 else
6477 tmpString+=" <th>";
6478 tmpString+=gt.rules.internalSubgroupsList[realSubgroup]->name+"</th>";
6479 }
6480 }
6481 if(repeatNames){
6482 tmpString+="<td colspan=\"2\"></td>";
6483 }
6484 tmpString+="</tr>\n </thead>\n";
6485 /*workaround
6486 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6487 */
6488 tmpString+=" <tbody>\n";
6489 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6490 tmpString+=" <tr>\n";
6491 if(hour==0)
6492 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6493 else tmpString+=" <!-- span -->\n";
6494 if(htmlLevel>=2)
6495 tmpString+=" <th class=\"yAxis\">";
6496 else
6497 tmpString+=" <th>";
6498 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6499 currentCount=0;
6500 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6501 int realSubgroup;
6502 if(subgroupsSortedOrder!=QList<int>())
6503 realSubgroup=subgroupsSortedOrder.at(subgroup);
6504 else
6505 realSubgroup=subgroup;
6506
6507 if(!excludedNames.contains(subgroup)){
6508 currentCount++;
6509 if(hour+1==gt.rules.nHoursPerDay)
6510 excludedNames<<subgroup;
6511 QList<int> allActivities;
6512 allActivities.clear();
6513 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6514 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6515 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6516 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], false, true, printActivityTags, gt.rules.internalSubgroupsList[realSubgroup]->name);
6517 } else{
6518 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6519 }
6520 }
6521 }
6522 if(repeatNames){
6523 if(htmlLevel>=2)
6524 tmpString+=" <th class=\"yAxis\">";
6525 else
6526 tmpString+=" <th>";
6527 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6528
6529 if(hour==0)
6530 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6531 else tmpString+=" <!-- span -->\n";
6532 }
6533 tmpString+=" </tr>\n";
6534 }
6535 //workaround begin.
6536 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6537 if(repeatNames){
6538 tmpString+="<td colspan=\"2\"></td>";
6539 }
6540 tmpString+="</tr>\n";
6541 //workaround end.
6542 tmpString+=" </tbody>\n";
6543 tmpString+=" </table>\n\n";
6544 return tmpString;
6545 }
6546
6547 //by Volker Dirr
singleSubgroupsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxSubgroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames,const QList<int> & subgroupsSortedOrder)6548 QString TimetableExport::singleSubgroupsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxSubgroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames, const QList<int>& subgroupsSortedOrder){
6549 assert(day>=0);
6550 assert(day<gt.rules.nDaysPerWeek);
6551 QString tmpString;
6552 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
6553 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6554
6555 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
6556 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
6557 if(repeatNames){
6558 tmpString+="<td rowspan=\"2\"></td>";
6559 }
6560 tmpString+=" </tr>\n";
6561 tmpString+=" <tr>\n <!-- span -->\n";
6562 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6563 if(htmlLevel>=2)
6564 tmpString+=" <th class=\"xAxis\">";
6565 else
6566 tmpString+=" <th>";
6567 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6568 }
6569 tmpString+=" </tr>\n";
6570 tmpString+=" </thead>\n";
6571 /*workaround
6572 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6573 */
6574 tmpString+=" <tbody>\n";
6575 int currentCount=0;
6576 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups && currentCount<maxSubgroups; subgroup++){
6577 int realSubgroup;
6578 if(subgroupsSortedOrder!=QList<int>())
6579 realSubgroup=subgroupsSortedOrder.at(subgroup);
6580 else
6581 realSubgroup=subgroup;
6582
6583 if(!excludedNames.contains(subgroup)){
6584 currentCount++;
6585 excludedNames<<subgroup;
6586
6587 tmpString+=" <tr>\n";
6588 if(htmlLevel>=2)
6589 tmpString+=" <th class=\"yAxis\">";
6590 else
6591 tmpString+=" <th>";
6592 tmpString+=gt.rules.internalSubgroupsList[realSubgroup]->name+"</th>\n";
6593 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6594 QList<int> allActivities;
6595 allActivities.clear();
6596 allActivities<<students_timetable_weekly[realSubgroup][day][hour];
6597 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6598 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6599 tmpString+=writeActivityStudents(htmlLevel, students_timetable_weekly[realSubgroup][day][hour], day, hour, subgroupNotAvailableDayHour[realSubgroup][day][hour], true, false, printActivityTags, gt.rules.internalSubgroupsList[realSubgroup]->name);
6600 } else{
6601 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6602 }
6603 }
6604 if(repeatNames){
6605 if(htmlLevel>=2)
6606 tmpString+=" <th class=\"yAxis\">";
6607 else
6608 tmpString+=" <th>";
6609 tmpString+=gt.rules.internalSubgroupsList[realSubgroup]->name+"</th>\n";
6610 }
6611 tmpString+=" </tr>\n";
6612 }
6613 }
6614 //workaround begin.
6615 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6616 if(repeatNames){
6617 tmpString+="<td></td>";
6618 }
6619 tmpString+="</tr>\n";
6620 //workaround end.
6621 tmpString+=" </tbody>\n";
6622 tmpString+=" </table>\n\n";
6623 return tmpString;
6624 }
6625
6626 //by Volker Dirr
singleGroupsTimetableDaysHorizontalHtml(int htmlLevel,int group,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)6627 QString TimetableExport::singleGroupsTimetableDaysHorizontalHtml(int htmlLevel, int group, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
6628 assert(group>=0);
6629 assert(group<gt.rules.internalGroupsList.size());
6630 QString tmpString;
6631 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(gt.rules.internalGroupsList[group]->name);
6632 tmpString+="\" border=\"1\"";
6633 if(group%2) tmpString+=" class=\"even_table\"";
6634 else tmpString+=" class=\"odd_table\"";
6635 tmpString+=">\n";
6636
6637 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6638 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(gt.rules.internalGroupsList[group]->name)+"</th>";
6639 if(repeatNames){
6640 tmpString+="<td rowspan=\"2\"></td>";
6641 }
6642 tmpString+="</tr>\n";
6643 tmpString+=" <tr>\n <!-- span -->\n";
6644 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6645 if(htmlLevel>=2)
6646 tmpString+=" <th class=\"xAxis\">";
6647 else
6648 tmpString+=" <th>";
6649 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6650 }
6651 tmpString+=" </tr>\n";
6652 tmpString+=" </thead>\n";
6653 /*workaround
6654 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6655 */
6656 tmpString+=" <tbody>\n";
6657 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6658 tmpString+=" <tr>\n";
6659 if(htmlLevel>=2)
6660 tmpString+=" <th class=\"yAxis\">";
6661 else
6662 tmpString+=" <th>";
6663 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6664 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6665 QList<int> allActivities;
6666 allActivities.clear();
6667 bool isNotAvailable=true;
6668 for(int sg=0; sg<gt.rules.internalGroupsList[group]->subgroupsList.size(); sg++){
6669 StudentsSubgroup* sts=gt.rules.internalGroupsList[group]->subgroupsList[sg];
6670 int subgroup=sts->indexInInternalSubgroupsList;
6671 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
6672 allActivities<<students_timetable_weekly[subgroup][day][hour];
6673 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
6674 isNotAvailable=false;
6675 }
6676 assert(!allActivities.isEmpty());
6677 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6678 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6679 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.internalGroupsList[group]->name);
6680 } else{
6681 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
6682 else{
6683 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6684 }
6685 }
6686 }
6687 if(repeatNames){
6688 if(htmlLevel>=2)
6689 tmpString+=" <th class=\"yAxis\">";
6690 else
6691 tmpString+=" <th>";
6692 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6693 }
6694 tmpString+=" </tr>\n";
6695 }
6696 //workaround begin.
6697 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6698 if(repeatNames){
6699 tmpString+="<td></td>";
6700 }
6701 tmpString+="</tr>\n";
6702 //workaround end.
6703 tmpString+=" </tbody>\n";
6704 tmpString+=" </table>\n\n";
6705 return tmpString;
6706 }
6707
6708 //by Volker Dirr
singleGroupsTimetableDaysVerticalHtml(int htmlLevel,int group,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)6709 QString TimetableExport::singleGroupsTimetableDaysVerticalHtml(int htmlLevel, int group, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
6710 assert(group>=0);
6711 assert(group<gt.rules.internalGroupsList.size());
6712 QString tmpString;
6713 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(gt.rules.internalGroupsList.at(group)->name);
6714 tmpString+="\" border=\"1\"";
6715 if(group%2) tmpString+=" class=\"even_table\"";
6716 else tmpString+=" class=\"odd_table\"";
6717 tmpString+=">\n";
6718
6719 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6720 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>";
6721 if(repeatNames){
6722 tmpString+="<td rowspan=\"2\"></td>";
6723 }
6724 tmpString+="</tr>\n";
6725 tmpString+=" <tr>\n <!-- span -->\n";
6726 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6727 if(htmlLevel>=2)
6728 tmpString+=" <th class=\"xAxis\">";
6729 else
6730 tmpString+=" <th>";
6731 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6732 }
6733 tmpString+=" </tr>\n";
6734 tmpString+=" </thead>\n";
6735 /*workaround
6736 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6737 */
6738 tmpString+=" <tbody>\n";
6739 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6740 tmpString+=" <tr>\n";
6741 if(htmlLevel>=2)
6742 tmpString+=" <th class=\"yAxis\">";
6743 else
6744 tmpString+=" <th>";
6745 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6746 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6747 QList<int> allActivities;
6748 allActivities.clear();
6749 bool isNotAvailable=true;
6750 for(int sg=0; sg<gt.rules.internalGroupsList.at(group)->subgroupsList.size(); sg++){
6751 StudentsSubgroup* sts=gt.rules.internalGroupsList.at(group)->subgroupsList[sg];
6752 int subgroup=sts->indexInInternalSubgroupsList;
6753 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
6754 allActivities<<students_timetable_weekly[subgroup][day][hour];
6755 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
6756 isNotAvailable=false;
6757 }
6758 assert(!allActivities.isEmpty());
6759 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6760 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6761 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.internalGroupsList[group]->name);
6762 } else{
6763 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
6764 else{
6765 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6766 }
6767 }
6768 }
6769 if(repeatNames){
6770 if(htmlLevel>=2)
6771 tmpString+=" <th class=\"yAxis\">";
6772 else
6773 tmpString+=" <th>";
6774 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
6775 }
6776 tmpString+=" </tr>\n";
6777 }
6778 //workaround begin.
6779 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6780 if(repeatNames){
6781 tmpString+="<td></td>";
6782 }
6783 tmpString+="</tr>\n";
6784 //workaround end.
6785 tmpString+=" </tbody>\n";
6786 tmpString+=" </table>\n\n";
6787 return tmpString;
6788 }
6789
6790 //by Volker Dirr
singleGroupsTimetableTimeVerticalHtml(int htmlLevel,int maxGroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)6791 QString TimetableExport::singleGroupsTimetableTimeVerticalHtml(int htmlLevel, int maxGroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
6792 QString tmpString;
6793 tmpString+=" <table id=\"table";
6794 tmpString+="\" border=\"1\">\n";
6795 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6796 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
6797 int currentCount=0;
6798 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
6799 if(!excludedNames.contains(group)){
6800 currentCount++;
6801 if(htmlLevel>=2)
6802 tmpString+=" <th class=\"xAxis\">";
6803 else
6804 tmpString+=" <th>";
6805 tmpString+=protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>";
6806 }
6807 }
6808 if(repeatNames){
6809 tmpString+="<td colspan=\"2\"></td>";
6810 }
6811 tmpString+="</tr>\n </thead>\n";
6812 /*workaround
6813 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6814 */
6815 tmpString+=" <tbody>\n";
6816 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6817 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6818 currentCount=0;
6819 tmpString+=" <tr>\n";
6820 if(hour==0)
6821 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6822 else tmpString+=" <!-- span -->\n";
6823 if(htmlLevel>=2)
6824 tmpString+=" <th class=\"yAxis\">";
6825 else
6826 tmpString+=" <th>";
6827 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6828 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
6829 if(!excludedNames.contains(group)){
6830 currentCount++;
6831 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
6832 excludedNames<<group;
6833 QList<int> allActivities;
6834 allActivities.clear();
6835 bool isNotAvailable=true;
6836 for(int sg=0; sg<gt.rules.internalGroupsList.at(group)->subgroupsList.size(); sg++){
6837 StudentsSubgroup* sts=gt.rules.internalGroupsList.at(group)->subgroupsList[sg];
6838 int subgroup=sts->indexInInternalSubgroupsList;
6839 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
6840 allActivities<<students_timetable_weekly[subgroup][day][hour];
6841 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
6842 isNotAvailable=false;
6843 }
6844 assert(!allActivities.isEmpty());
6845 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6846 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6847 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.internalGroupsList[group]->name);
6848 } else{
6849 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
6850 else{
6851 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6852 }
6853 }
6854 }
6855 }
6856 if(repeatNames){
6857 if(htmlLevel>=2)
6858 tmpString+=" <th class=\"yAxis\">";
6859 else
6860 tmpString+=" <th>";
6861 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6862 if(hour==0)
6863 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
6864 else tmpString+=" <!-- span -->\n";
6865 }
6866 tmpString+=" </tr>\n";
6867 }
6868 }
6869 //workaround begin.
6870 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6871 if(repeatNames){
6872 tmpString+="<td colspan=\"2\"></td>";
6873 }
6874 tmpString+="</tr>\n";
6875 //workaround end.
6876 tmpString+=" </tbody>\n";
6877 tmpString+=" </table>\n\n";
6878 return tmpString;
6879 }
6880
6881 //by Volker Dirr
singleGroupsTimetableTimeHorizontalHtml(int htmlLevel,int maxGroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)6882 QString TimetableExport::singleGroupsTimetableTimeHorizontalHtml(int htmlLevel, int maxGroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
6883 QString tmpString;
6884 tmpString+=" <table id=\"table";
6885 tmpString+="\" border=\"1\">\n";
6886 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6887 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
6888 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
6889 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
6890 if(repeatNames){
6891 tmpString+="<td rowspan=\"2\"></td>";
6892 }
6893 tmpString+="</tr>\n";
6894 tmpString+=" <tr>\n <!-- span -->\n";
6895 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6896 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6897 if(htmlLevel>=2)
6898 tmpString+=" <th class=\"xAxis\">";
6899 else
6900 tmpString+=" <th>";
6901 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
6902 }
6903 }
6904 tmpString+=" </tr>\n";
6905 tmpString+=" </thead>\n";
6906 /*workaround
6907 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6908 */
6909 tmpString+=" <tbody>\n";
6910
6911 int currentCount=0;
6912 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
6913 if(!excludedNames.contains(group)){
6914 currentCount++;
6915 excludedNames<<group;
6916
6917 tmpString+=" <tr>\n";
6918 if(htmlLevel>=2)
6919 tmpString+=" <th class=\"yAxis\">";
6920 else
6921 tmpString+=" <th>";
6922 tmpString+=protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>\n";
6923 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
6924 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6925 QList<int> allActivities;
6926 allActivities.clear();
6927 bool isNotAvailable=true;
6928 for(int sg=0; sg<gt.rules.internalGroupsList.at(group)->subgroupsList.size(); sg++){
6929 StudentsSubgroup* sts=gt.rules.internalGroupsList.at(group)->subgroupsList[sg];
6930 int subgroup=sts->indexInInternalSubgroupsList;
6931 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
6932 allActivities<<students_timetable_weekly[subgroup][day][hour];
6933 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
6934 isNotAvailable=false;
6935 }
6936 assert(!allActivities.isEmpty());
6937 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
6938 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
6939 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.internalGroupsList[group]->name);
6940 } else{
6941 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
6942 else{
6943 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
6944 }
6945 }
6946 }
6947 }
6948 if(repeatNames){
6949 if(htmlLevel>=2)
6950 tmpString+=" <th class=\"yAxis\">";
6951 else
6952 tmpString+=" <th>";
6953 tmpString+=protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>\n";
6954 }
6955 }
6956 tmpString+=" </tr>\n";
6957 }
6958 //workaround begin.
6959 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
6960 if(repeatNames){
6961 tmpString+="<td></td>";
6962 }
6963 tmpString+="</tr>\n";
6964 //workaround end.
6965 tmpString+=" </tbody>\n";
6966 tmpString+=" </table>\n\n";
6967 return tmpString;
6968 }
6969
6970 //by Volker Dirr
singleGroupsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxGroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)6971 QString TimetableExport::singleGroupsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxGroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
6972 assert(day>=0);
6973 assert(day<gt.rules.nDaysPerWeek);
6974 QString tmpString;
6975 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day]);
6976 tmpString+="\" border=\"1\">\n";
6977 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
6978 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
6979 int currentCount=0;
6980 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
6981 if(!excludedNames.contains(group)){
6982 currentCount++;
6983 if(htmlLevel>=2)
6984 tmpString+=" <th class=\"xAxis\">";
6985 else
6986 tmpString+=" <th>";
6987 tmpString+=gt.rules.internalGroupsList.at(group)->name+"</th>";
6988 }
6989 }
6990 if(repeatNames){
6991 tmpString+="<td colspan=\"2\"></td>";
6992 }
6993 tmpString+="</tr>\n </thead>\n";
6994 /*workaround
6995 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
6996 */
6997 tmpString+=" <tbody>\n";
6998 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
6999 currentCount=0;
7000 tmpString+=" <tr>\n";
7001 if(hour==0)
7002 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">" + protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7003 else tmpString+=" <!-- span -->\n";
7004 if(htmlLevel>=2)
7005 tmpString+=" <th class=\"yAxis\">";
7006 else
7007 tmpString+=" <th>";
7008 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7009 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
7010 if(!excludedNames.contains(group)){
7011 currentCount++;
7012 if(hour+1==gt.rules.nHoursPerDay)
7013 excludedNames<<group;
7014 QList<int> allActivities;
7015 allActivities.clear();
7016 bool isNotAvailable=true;
7017 for(int sg=0; sg<gt.rules.internalGroupsList.at(group)->subgroupsList.size(); sg++){
7018 StudentsSubgroup* sts=gt.rules.internalGroupsList.at(group)->subgroupsList[sg];
7019 int subgroup=sts->indexInInternalSubgroupsList;
7020 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7021 allActivities<<students_timetable_weekly[subgroup][day][hour];
7022 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7023 isNotAvailable=false;
7024 }
7025 assert(!allActivities.isEmpty());
7026 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7027 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7028 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.internalGroupsList[group]->name);
7029 } else{
7030 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7031 else{
7032 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7033 }
7034 }
7035 }
7036 }
7037 if(repeatNames){
7038 if(htmlLevel>=2)
7039 tmpString+=" <th class=\"yAxis\">";
7040 else
7041 tmpString+=" <th>";
7042 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7043 if(hour==0)
7044 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">" + protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7045 else tmpString+=" <!-- span -->\n";
7046 }
7047 tmpString+=" </tr>\n";
7048 }
7049 //workaround begin.
7050 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7051 if(repeatNames){
7052 tmpString+="<td colspan=\"2\"></td>";
7053 }
7054 tmpString+="</tr>\n";
7055 //workaround end.
7056 tmpString+=" </tbody>\n";
7057 tmpString+=" </table>\n\n";
7058 return tmpString;
7059 }
7060
7061 //by Volker Dirr
singleGroupsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxGroups,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7062 QString TimetableExport::singleGroupsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxGroups, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7063 assert(day>=0);
7064 assert(day<gt.rules.nDaysPerWeek);
7065 QString tmpString;
7066 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day]);
7067 tmpString+="\" border=\"1\">\n";
7068 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7069 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
7070 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
7071 if(repeatNames){
7072 tmpString+="<td rowspan=\"2\"></td>";
7073 }
7074 tmpString+="</tr>\n";
7075 tmpString+=" <tr>\n <!-- span -->\n";
7076 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7077 if(htmlLevel>=2)
7078 tmpString+=" <th class=\"xAxis\">";
7079 else
7080 tmpString+=" <th>";
7081 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7082 }
7083 tmpString+=" </tr>\n";
7084 tmpString+=" </thead>\n";
7085 /*workaround
7086 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7087 */
7088 tmpString+=" <tbody>\n";
7089
7090 int currentCount=0;
7091 for(int group=0; group<gt.rules.internalGroupsList.size() && currentCount<maxGroups; group++){
7092 if(!excludedNames.contains(group)){
7093 currentCount++;
7094 excludedNames<<group;
7095
7096 tmpString+=" <tr>\n";
7097 if(htmlLevel>=2)
7098 tmpString+=" <th class=\"yAxis\">";
7099 else
7100 tmpString+=" <th>";
7101 tmpString+=protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>\n";
7102 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7103 QList<int> allActivities;
7104 allActivities.clear();
7105 bool isNotAvailable=true;
7106 for(int sg=0; sg<gt.rules.internalGroupsList.at(group)->subgroupsList.size(); sg++){
7107 StudentsSubgroup* sts=gt.rules.internalGroupsList.at(group)->subgroupsList[sg];
7108 int subgroup=sts->indexInInternalSubgroupsList;
7109 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7110 allActivities<<students_timetable_weekly[subgroup][day][hour];
7111 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7112 isNotAvailable=false;
7113 }
7114 assert(!allActivities.isEmpty());
7115 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7116 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7117 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.internalGroupsList[group]->name);
7118 } else{
7119 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7120 else{
7121 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7122 }
7123 }
7124 }
7125 if(repeatNames){
7126 if(htmlLevel>=2)
7127 tmpString+=" <th class=\"yAxis\">";
7128 else
7129 tmpString+=" <th>";
7130 tmpString+=protect2(gt.rules.internalGroupsList.at(group)->name)+"</th>\n";
7131 }
7132 tmpString+=" </tr>\n";
7133 }
7134 }
7135 //workaround begin.
7136 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7137 if(repeatNames){
7138 tmpString+="<td></td>";
7139 }
7140 tmpString+="</tr>\n";
7141 //workaround end.
7142 tmpString+=" </tbody>\n";
7143 tmpString+=" </table>\n\n";
7144 return tmpString;
7145 }
7146
7147 //by Volker Dirr
singleYearsTimetableDaysHorizontalHtml(int htmlLevel,int year,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7148 QString TimetableExport::singleYearsTimetableDaysHorizontalHtml(int htmlLevel, int year, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7149 assert(year>=0);
7150 assert(year<gt.rules.augmentedYearsList.size());
7151 QString tmpString;
7152 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(gt.rules.augmentedYearsList.at(year)->name);
7153 tmpString+="\" border=\"1\"";
7154 if(year%2) tmpString+=" class=\"even_table\"";
7155 else tmpString+=" class=\"odd_table\"";
7156 tmpString+=">\n";
7157
7158 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7159 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(gt.rules.augmentedYearsList.at(year)->name)+"</th>";
7160 if(repeatNames){
7161 tmpString+="<td rowspan=\"2\"></td>";
7162 }
7163 tmpString+="</tr>\n";
7164 tmpString+=" <tr>\n <!-- span -->\n";
7165 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7166 if(htmlLevel>=2)
7167 tmpString+=" <th class=\"xAxis\">";
7168 else
7169 tmpString+=" <th>";
7170 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7171 }
7172 tmpString+=" </tr>\n";
7173 tmpString+=" </thead>\n";
7174 /*workaround
7175 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7176 */
7177 tmpString+=" <tbody>\n";
7178 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7179 tmpString+=" <tr>\n";
7180 if(htmlLevel>=2)
7181 tmpString+=" <th class=\"yAxis\">";
7182 else
7183 tmpString+=" <th>";
7184 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7185 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7186 QList<int> allActivities;
7187 allActivities.clear();
7188 bool isNotAvailable=true;
7189 for(int g=0; g<gt.rules.augmentedYearsList.at(year)->groupsList.size(); g++){
7190 StudentsGroup* stg=gt.rules.augmentedYearsList.at(year)->groupsList[g];
7191 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7192 StudentsSubgroup* sts=stg->subgroupsList[sg];
7193 int subgroup=sts->indexInInternalSubgroupsList;
7194 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7195 allActivities<<students_timetable_weekly[subgroup][day][hour];
7196 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7197 isNotAvailable=false;
7198 }
7199 }
7200 assert(!allActivities.isEmpty());
7201 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7202 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7203 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7204 } else{
7205 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7206 else{
7207 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7208 }
7209 }
7210 }
7211 if(repeatNames){
7212 if(htmlLevel>=2)
7213 tmpString+=" <th class=\"yAxis\">";
7214 else
7215 tmpString+=" <th>";
7216 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7217 }
7218 tmpString+=" </tr>\n";
7219 }
7220 //workaround begin.
7221 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7222 if(repeatNames){
7223 tmpString+="<td></td>";
7224 }
7225 tmpString+="</tr>\n";
7226 //workaround end.
7227 tmpString+=" </tbody>\n";
7228 tmpString+=" </table>\n\n";
7229 return tmpString;
7230 }
7231
7232 //by Volker Dirr
singleYearsTimetableDaysVerticalHtml(int htmlLevel,int year,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7233 QString TimetableExport::singleYearsTimetableDaysVerticalHtml(int htmlLevel, int year, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7234 assert(year>=0);
7235 assert(year<gt.rules.augmentedYearsList.size());
7236 QString tmpString;
7237 tmpString+=" <table id=\"table_"+hashStudentIDsTimetable.value(gt.rules.augmentedYearsList.at(year)->name);
7238 tmpString+="\" border=\"1\"";
7239 if(year%2) tmpString+=" class=\"even_table\"";
7240 else tmpString+=" class=\"odd_table\"";
7241 tmpString+=">\n";
7242
7243 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7244
7245 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.augmentedYearsList.at(year)->name)+"</th>";
7246 if(repeatNames){
7247 tmpString+="<td rowspan=\"2\"></td>";
7248 }
7249 tmpString+="</tr>\n";
7250 tmpString+=" <tr>\n <!-- span -->\n";
7251 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7252 if(htmlLevel>=2)
7253 tmpString+=" <th class=\"xAxis\">";
7254 else
7255 tmpString+=" <th>";
7256 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7257 }
7258 tmpString+=" </tr>\n";
7259 tmpString+=" </thead>\n";
7260 /*workaround
7261 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7262 */
7263 tmpString+=" <tbody>\n";
7264 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7265 tmpString+=" <tr>\n";
7266 if(htmlLevel>=2)
7267 tmpString+=" <th class=\"yAxis\">";
7268 else
7269 tmpString+=" <th>";
7270 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7271
7272 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7273 QList<int> allActivities;
7274 allActivities.clear();
7275 bool isNotAvailable=true;
7276 for(int g=0; g<gt.rules.augmentedYearsList.at(year)->groupsList.size(); g++){
7277 StudentsGroup* stg=gt.rules.augmentedYearsList.at(year)->groupsList[g];
7278 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7279 StudentsSubgroup* sts=stg->subgroupsList[sg];
7280 int subgroup=sts->indexInInternalSubgroupsList;
7281 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7282 allActivities<<students_timetable_weekly[subgroup][day][hour];
7283 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7284 isNotAvailable=false;
7285 }
7286 }
7287 assert(!allActivities.isEmpty());
7288 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7289 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7290 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7291 } else{
7292 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7293 else{
7294 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7295 }
7296 }
7297 }
7298 if(repeatNames){
7299 if(htmlLevel>=2)
7300 tmpString+=" <th class=\"yAxis\">";
7301 else
7302 tmpString+=" <th>";
7303 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7304 }
7305 tmpString+=" </tr>\n";
7306 }
7307 //workaround begin.
7308 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7309 if(repeatNames){
7310 tmpString+="<td></td>";
7311 }
7312 tmpString+="</tr>\n";
7313 //workaround end.
7314 tmpString+=" </tbody>\n";
7315 tmpString+=" </table>\n\n";
7316 return tmpString;
7317 }
7318
7319 //by Volker Dirr
singleYearsTimetableTimeVerticalHtml(int htmlLevel,int maxYears,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7320 QString TimetableExport::singleYearsTimetableTimeVerticalHtml(int htmlLevel, int maxYears, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7321 QString tmpString;
7322 tmpString+=" <table id=\"table";
7323 tmpString+="\" border=\"1\">\n";
7324
7325 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7326
7327 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
7328 int currentCount=0;
7329 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7330 if(!excludedNames.contains(year)){
7331 currentCount++;
7332 if(htmlLevel>=2)
7333 tmpString+=" <th class=\"xAxis\">";
7334 else
7335 tmpString+=" <th>";
7336 tmpString+=protect2(gt.rules.augmentedYearsList.at(year)->name)+"</th>";
7337 }
7338 }
7339 if(repeatNames){
7340 tmpString+="<td colspan=\"2\"></td>";
7341 }
7342 tmpString+="</tr>\n </thead>\n";
7343 /*workaround
7344 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7345 */
7346 tmpString+=" <tbody>\n";
7347 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7348 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7349 tmpString+=" <tr>\n";
7350 if(hour==0)
7351 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7352 else tmpString+=" <!-- span -->\n";
7353 if(htmlLevel>=2)
7354 tmpString+=" <th class=\"yAxis\">";
7355 else
7356 tmpString+=" <th>";
7357 tmpString+=protect2(gt.rules.hoursOfTheDay[hour]) + "</th>\n";
7358 currentCount=0;
7359 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7360 if(!excludedNames.contains(year)){
7361 currentCount++;
7362 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
7363 excludedNames<<year;
7364 QList<int> allActivities;
7365 allActivities.clear();
7366 bool isNotAvailable=true;
7367 StudentsYear* sty=gt.rules.augmentedYearsList[year];
7368 for(int g=0; g<sty->groupsList.size(); g++){
7369 StudentsGroup* stg=sty->groupsList[g];
7370 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7371 StudentsSubgroup* sts=stg->subgroupsList[sg];
7372 int subgroup=sts->indexInInternalSubgroupsList;
7373 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7374 allActivities<<students_timetable_weekly[subgroup][day][hour];
7375 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7376 isNotAvailable=false;
7377 }
7378 }
7379 assert(!allActivities.isEmpty());
7380 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7381 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7382 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7383 } else{
7384 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7385 else{
7386 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7387 }
7388 }
7389 }
7390 }
7391 if(repeatNames){
7392 if(htmlLevel>=2)
7393 tmpString+=" <th class=\"yAxis\">";
7394 else
7395 tmpString+=" <th>";
7396 tmpString+=protect2(gt.rules.hoursOfTheDay[hour]) + "</th>\n";
7397 if(hour==0)
7398 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7399 else tmpString+=" <!-- span -->\n";
7400 }
7401 tmpString+=" </tr>\n";
7402 }
7403 }
7404 //workaround begin.
7405 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7406 if(repeatNames){
7407 tmpString+="<td colspan=\"2\"></td>";
7408 }
7409 tmpString+="</tr>\n";
7410 //workaround end.
7411 tmpString+=" </tbody>\n";
7412 tmpString+=" </table>\n\n";
7413 return tmpString;
7414 }
7415
7416 //by Volker Dirr
singleYearsTimetableTimeHorizontalHtml(int htmlLevel,int maxYears,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7417 QString TimetableExport::singleYearsTimetableTimeHorizontalHtml(int htmlLevel, int maxYears, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7418 QString tmpString;
7419 tmpString+=" <table id=\"table";
7420 tmpString+="\" border=\"1\">\n";
7421
7422 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7423
7424 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
7425 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
7426 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
7427 if(repeatNames){
7428 tmpString+="<td rowspan=\"2\"></td>";
7429 }
7430 tmpString+="</tr>\n";
7431 tmpString+=" <tr>\n <!-- span -->\n";
7432 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7433 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7434 if(htmlLevel>=2)
7435 tmpString+=" <th class=\"xAxis\">";
7436 else
7437 tmpString+=" <th>";
7438 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7439 }
7440 }
7441 tmpString+=" </tr>\n";
7442 tmpString+=" </thead>\n";
7443 /*workaround
7444 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7445 */
7446 tmpString+=" <tbody>\n";
7447
7448 int currentCount=0;
7449 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7450 StudentsYear* sty=gt.rules.augmentedYearsList[year];
7451 if(!excludedNames.contains(year)){
7452 currentCount++;
7453 excludedNames<<year;
7454 tmpString+=" <tr>\n";
7455 if(htmlLevel>=2)
7456 tmpString+=" <th class=\"yAxis\">";
7457 else
7458 tmpString+=" <th>";
7459 tmpString+=protect2(sty->name)+"</th>\n";
7460 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7461 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7462 QList<int> allActivities;
7463 allActivities.clear();
7464 bool isNotAvailable=true;
7465 for(int g=0; g<sty->groupsList.size(); g++){
7466 StudentsGroup* stg=sty->groupsList[g];
7467 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7468 StudentsSubgroup* sts=stg->subgroupsList[sg];
7469 int subgroup=sts->indexInInternalSubgroupsList;
7470 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7471 allActivities<<students_timetable_weekly[subgroup][day][hour];
7472 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7473 isNotAvailable=false;
7474 }
7475 }
7476 assert(!allActivities.isEmpty());
7477 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7478 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7479 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7480 } else{
7481 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7482 else{
7483 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7484 }
7485 }
7486 }
7487 }
7488 if(repeatNames){
7489 if(htmlLevel>=2)
7490 tmpString+=" <th class=\"yAxis\">";
7491 else
7492 tmpString+=" <th>";
7493 tmpString+=protect2(sty->name)+"</th>\n";
7494 }
7495 tmpString+=" </tr>\n";
7496 }
7497 }
7498 //workaround begin.
7499 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7500 if(repeatNames){
7501 tmpString+="<td></td>";
7502 }
7503 tmpString+="</tr>\n";
7504 //workaround end.
7505 tmpString+=" </tbody>\n";
7506 tmpString+=" </table>\n\n";
7507 return tmpString;
7508 }
7509
7510 //by Volker Dirr
singleYearsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxYears,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7511 QString TimetableExport::singleYearsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxYears, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7512 assert(day>=0);
7513 assert(day<gt.rules.nDaysPerWeek);
7514 QString tmpString;
7515 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day]);
7516 tmpString+="\" border=\"1\">\n";
7517
7518 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7519
7520 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
7521 int currentCount=0;
7522 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7523 if(!excludedNames.contains(year)){
7524 currentCount++;
7525
7526 if(htmlLevel>=2)
7527 tmpString+=" <th class=\"xAxis\">";
7528 else
7529 tmpString+=" <th>";
7530 tmpString+=protect2(gt.rules.augmentedYearsList.at(year)->name)+"</th>";
7531 }
7532 }
7533 if(repeatNames){
7534 tmpString+="<td colspan=\"2\"></td>";
7535 }
7536 tmpString+="</tr>\n </thead>\n";
7537 /*workaround
7538 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7539 */
7540 tmpString+=" <tbody>\n";
7541
7542 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7543 tmpString+=" <tr>\n";
7544 if(hour==0)
7545 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7546 else tmpString+=" <!-- span -->\n";
7547 if(htmlLevel>=2)
7548 tmpString+=" <th class=\"yAxis\">";
7549 else
7550 tmpString+=" <th>";
7551 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7552 currentCount=0;
7553 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7554 StudentsYear* sty=gt.rules.augmentedYearsList[year];
7555 if(!excludedNames.contains(year)){
7556 currentCount++;
7557 if(hour+1==gt.rules.nHoursPerDay)
7558 excludedNames<<year;
7559 QList<int> allActivities;
7560 allActivities.clear();
7561 bool isNotAvailable=true;
7562 for(int g=0; g<sty->groupsList.size(); g++){
7563 StudentsGroup* stg=sty->groupsList[g];
7564 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7565 StudentsSubgroup* sts=stg->subgroupsList[sg];
7566 int subgroup=sts->indexInInternalSubgroupsList;
7567 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7568 allActivities<<students_timetable_weekly[subgroup][day][hour];
7569 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7570 isNotAvailable=false;
7571 }
7572 }
7573 assert(!allActivities.isEmpty());
7574 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7575 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7576 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, false, true, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7577 } else{
7578 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7579 else{
7580 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7581 }
7582 }
7583 }
7584 }
7585 if(repeatNames){
7586 if(htmlLevel>=2)
7587 tmpString+=" <th class=\"yAxis\">";
7588 else
7589 tmpString+=" <th>";
7590 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7591 if(hour==0)
7592 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7593 else tmpString+=" <!-- span -->\n";
7594 }
7595 tmpString+=" </tr>\n";
7596 }
7597 //workaround begin.
7598 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7599 if(repeatNames){
7600 tmpString+="<td colspan=\"2\"></td>";
7601 }
7602 tmpString+="</tr>\n";
7603 //workaround end.
7604 tmpString+=" </tbody>\n";
7605 tmpString+=" </table>\n\n";
7606 return tmpString;
7607 }
7608
7609 //by Volker Dirr
singleYearsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxYears,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool detailed,bool repeatNames)7610 QString TimetableExport::singleYearsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxYears, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool detailed, bool repeatNames){
7611 assert(day>=0);
7612 assert(day<gt.rules.nDaysPerWeek);
7613 QString tmpString;
7614 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day]);
7615 tmpString+="\" border=\"1\">\n";
7616
7617 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7618
7619 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
7620
7621 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
7622 if(repeatNames){
7623 tmpString+="<td rowspan=\"2\"></td>";
7624 }
7625 tmpString+="</tr>\n";
7626 tmpString+=" <tr>\n <!-- span -->\n";
7627 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7628 if(htmlLevel>=2)
7629 tmpString+=" <th class=\"xAxis\">";
7630 else
7631 tmpString+=" <th>";
7632 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7633 }
7634 tmpString+=" </tr>\n";
7635 tmpString+=" </thead>\n";
7636 /*workaround
7637 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7638 */
7639 tmpString+=" <tbody>\n";
7640 int currentCount=0;
7641 for(int year=0; year<gt.rules.augmentedYearsList.size() && currentCount<maxYears; year++){
7642 if(!excludedNames.contains(year)){
7643 currentCount++;
7644 excludedNames<<year;
7645 tmpString+=" <tr>\n";
7646 if(htmlLevel>=2)
7647 tmpString+=" <th class=\"yAxis\">";
7648 else
7649 tmpString+=" <th>";
7650 StudentsYear* sty=gt.rules.augmentedYearsList[year];
7651 tmpString+=protect2(sty->name)+"</th>\n";
7652 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7653 QList<int> allActivities;
7654 allActivities.clear();
7655 bool isNotAvailable=true;
7656 for(int g=0; g<sty->groupsList.size(); g++){
7657 StudentsGroup* stg=sty->groupsList[g];
7658 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
7659 StudentsSubgroup* sts=stg->subgroupsList[sg];
7660 int subgroup=sts->indexInInternalSubgroupsList;
7661 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour])))
7662 allActivities<<students_timetable_weekly[subgroup][day][hour];
7663 if(!subgroupNotAvailableDayHour[subgroup][day][hour])
7664 isNotAvailable=false;
7665 }
7666 }
7667 assert(!allActivities.isEmpty());
7668 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
7669 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
7670 tmpString+=writeActivityStudents(htmlLevel, allActivities[0], day, hour, isNotAvailable, true, false, printActivityTags, gt.rules.augmentedYearsList.at(year)->name);
7671 } else{
7672 if(!detailed) tmpString+=" <td>"+protect2(STRING_SEVERAL_ACTIVITIES_IN_LESS_DETAILED_TABLES)+"</td>\n";
7673 else{
7674 tmpString+=writeActivitiesStudents(htmlLevel, allActivities, printActivityTags);
7675 }
7676 }
7677 }
7678 if(repeatNames){
7679 if(htmlLevel>=2)
7680 tmpString+=" <th class=\"yAxis\">";
7681 else
7682 tmpString+=" <th>";
7683 tmpString+=protect2(sty->name)+"</th>\n";
7684 }
7685 tmpString+=" </tr>\n";
7686 }
7687 }
7688 //workaround begin.
7689 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7690 if(repeatNames){
7691 tmpString+="<td></td>";
7692 }
7693 tmpString+="</tr>\n";
7694 //workaround end.
7695 tmpString+=" </tbody>\n";
7696 tmpString+=" </table>\n\n";
7697 return tmpString;
7698 }
7699
7700 //by Volker Dirr
singleAllActivitiesTimetableDaysHorizontalHtml(int htmlLevel,const QString & saveTime,bool printActivityTags,bool repeatNames)7701 QString TimetableExport::singleAllActivitiesTimetableDaysHorizontalHtml(int htmlLevel, const QString& saveTime, bool printActivityTags, bool repeatNames){
7702 QString tmpString;
7703 tmpString+=" <table border=\"1\">\n";
7704 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7705 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+tr("All Activities")+"</th>";
7706 if(repeatNames){
7707 tmpString+="<td rowspan=\"2\"></td>";
7708 }
7709 tmpString+="</tr>\n";
7710 tmpString+=" <tr>\n <!-- span -->\n";
7711 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7712 if(htmlLevel>=2)
7713 tmpString+=" <th class=\"xAxis\">";
7714 else
7715 tmpString+=" <th>";
7716 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7717 }
7718 tmpString+=" </tr>\n";
7719 tmpString+=" </thead>\n";
7720 /*workaround
7721 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7722 */
7723 tmpString+=" <tbody>\n";
7724 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7725 tmpString+=" <tr>\n";
7726 if(htmlLevel>=2)
7727 tmpString+=" <th class=\"yAxis\">";
7728 else
7729 tmpString+=" <th>";
7730 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7731 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7732 if(activitiesAtTime[day][hour].isEmpty()){
7733 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
7734 tmpString+=writeBreakSlot(htmlLevel, "");
7735 } else {
7736 tmpString+=writeEmpty(htmlLevel);
7737 }
7738 } else {
7739 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
7740 }
7741 }
7742 if(repeatNames){
7743 if(htmlLevel>=2)
7744 tmpString+=" <th class=\"yAxis\">";
7745 else
7746 tmpString+=" <th>";
7747 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7748 }
7749 tmpString+=" </tr>\n";
7750 }
7751 //workaround begin.
7752 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7753 if(repeatNames){
7754 tmpString+="<td></td>";
7755 }
7756 tmpString+="</tr>\n";
7757 //workaround end.
7758 tmpString+=" </tbody>\n";
7759 tmpString+=" </table>\n";
7760 return tmpString;
7761 }
7762
7763 //by Volker Dirr
singleAllActivitiesTimetableDaysVerticalHtml(int htmlLevel,const QString & saveTime,bool printActivityTags,bool repeatNames)7764 QString TimetableExport::singleAllActivitiesTimetableDaysVerticalHtml(int htmlLevel, const QString& saveTime, bool printActivityTags, bool repeatNames){
7765 QString tmpString;
7766 tmpString+=" <table border=\"1\">\n";
7767 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7768 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+tr("All Activities")+"</th>";
7769 if(repeatNames){
7770 tmpString+="<td rowspan=\"2\"></td>";
7771 }
7772 tmpString+="</tr>\n";
7773 tmpString+=" <tr>\n <!-- span -->\n";
7774 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7775 if(htmlLevel>=2)
7776 tmpString+=" <th class=\"xAxis\">";
7777 else
7778 tmpString+=" <th>";
7779 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7780 }
7781 tmpString+=" </tr>\n";
7782 tmpString+=" </thead>\n";
7783 /*workaround
7784 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7785 */
7786 tmpString+=" <tbody>\n";
7787 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7788 tmpString+=" <tr>\n";
7789 if(htmlLevel>=2)
7790 tmpString+=" <th class=\"yAxis\">";
7791 else
7792 tmpString+=" <th>";
7793 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7794 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7795 if(activitiesAtTime[day][hour].isEmpty()){
7796 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
7797 tmpString+=writeBreakSlot(htmlLevel, "");
7798 } else {
7799 tmpString+=writeEmpty(htmlLevel);
7800 }
7801 } else {
7802 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
7803 }
7804 }
7805 if(repeatNames){
7806 if(htmlLevel>=2)
7807 tmpString+=" <th class=\"yAxis\">";
7808 else
7809 tmpString+=" <th>";
7810 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
7811 }
7812 tmpString+=" </tr>\n";
7813 }
7814 //workaround begin.
7815 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7816 if(repeatNames){
7817 tmpString+="<td></td>";
7818 }
7819 tmpString+="</tr>\n";
7820 //workaround end.
7821 tmpString+=" </tbody>\n";
7822 tmpString+=" </table>\n";
7823 return tmpString;
7824 }
7825
7826
7827 //by Volker Dirr
singleAllActivitiesTimetableTimeVerticalHtml(int htmlLevel,const QString & saveTime,bool printActivityTags,bool repeatNames)7828 QString TimetableExport::singleAllActivitiesTimetableTimeVerticalHtml(int htmlLevel, const QString& saveTime, bool printActivityTags, bool repeatNames){
7829 QString tmpString;
7830 tmpString+=" <table border=\"1\">\n";
7831 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7832 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
7833 if(htmlLevel>=2)
7834 tmpString+=" <th class=\"xAxis\">";
7835 else
7836 tmpString+=" <th>";
7837 tmpString+=tr("All Activities");
7838 tmpString+="</th>";
7839 if(repeatNames){
7840 tmpString+="<td colspan=\"2\"></td>";
7841 }
7842 tmpString+="</tr>\n </thead>\n";
7843 /*workaround
7844 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td>"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7845 */
7846 tmpString+=" <tbody>\n";
7847 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7848 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7849 tmpString+=" <tr>\n";
7850 if(hour==0)
7851 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7852 else tmpString+=" <!-- span -->\n";
7853 if(htmlLevel>=2)
7854 tmpString+=" <th class=\"yAxis\">";
7855 else
7856 tmpString+=" <th>";
7857 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7858 if(activitiesAtTime[day][hour].isEmpty()){
7859 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
7860 tmpString+=writeBreakSlot(htmlLevel, "");
7861 } else {
7862 tmpString+=writeEmpty(htmlLevel);
7863 }
7864 } else {
7865 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
7866 }
7867 if(repeatNames){
7868 if(htmlLevel>=2)
7869 tmpString+=" <th class=\"yAxis\">";
7870 else
7871 tmpString+=" <th>";
7872 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7873 if(hour==0)
7874 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7875 else tmpString+=" <!-- span -->\n";
7876 }
7877 tmpString+=" </tr>\n";
7878 }
7879 }
7880 //workaround begin.
7881 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td>"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7882 if(repeatNames){
7883 tmpString+="<td colspan=\"2\"></td>";
7884 }
7885 tmpString+="</tr>\n";
7886 //workaround end.
7887 tmpString+=" </tbody>\n";
7888 tmpString+=" </table>\n";
7889 return tmpString;
7890 }
7891
7892 //by Volker Dirr
singleAllActivitiesTimetableTimeHorizontalHtml(int htmlLevel,const QString & saveTime,bool printActivityTags,bool repeatNames)7893 QString TimetableExport::singleAllActivitiesTimetableTimeHorizontalHtml(int htmlLevel, const QString& saveTime, bool printActivityTags, bool repeatNames){
7894
7895 QString tmpString;
7896 tmpString+=" <table border=\"1\">\n";
7897 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7898 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
7899 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7900 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay) +"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
7901 }
7902 if(repeatNames){
7903 tmpString+="<td></td>";
7904 }
7905 tmpString+="</tr>\n";
7906 tmpString+=" <tr>\n <!-- span -->\n";
7907 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
7908 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7909 if(htmlLevel>=2)
7910 tmpString+=" <th class=\"xAxis\">";
7911 else
7912 tmpString+=" <th>";
7913 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7914 }
7915 tmpString+=" </tr>\n";
7916 tmpString+=" </thead>\n";
7917 /*workaround
7918 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7919 */
7920 tmpString+=" <tbody>\n";
7921
7922 tmpString+=" <tr>\n";
7923 if(htmlLevel>=2)
7924 tmpString+=" <th class=\"yAxis\">";
7925 else
7926 tmpString+=" <th>";
7927 tmpString+=tr("All Activities")+"</th>\n";
7928 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
7929 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7930 if(activitiesAtTime[day][hour].isEmpty()){
7931 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
7932 tmpString+=writeBreakSlot(htmlLevel, "");
7933 } else {
7934 tmpString+=writeEmpty(htmlLevel);
7935 }
7936 } else {
7937 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
7938 }
7939 }
7940 }
7941 if(repeatNames){
7942 if(htmlLevel>=2)
7943 tmpString+=" <th class=\"yAxis\">";
7944 else
7945 tmpString+=" <th>";
7946 tmpString+=tr("All Activities")+"</th>\n";
7947 }
7948 tmpString+=" </tr>\n";
7949 //workaround begin.
7950 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
7951 if(repeatNames){
7952 tmpString+="<td></td>";
7953 }
7954 tmpString+="</tr>\n";
7955 //workaround end.
7956 tmpString+=" </tbody>\n";
7957 tmpString+=" </table>\n";
7958 return tmpString;
7959 }
7960
7961 //by Volker Dirr
singleAllActivitiesTimetableTimeVerticalDailyHtml(int htmlLevel,int day,const QString & saveTime,bool printActivityTags,bool repeatNames)7962 QString TimetableExport::singleAllActivitiesTimetableTimeVerticalDailyHtml(int htmlLevel, int day, const QString& saveTime, bool printActivityTags, bool repeatNames){
7963 assert(day>=0);
7964 assert(day<gt.rules.nDaysPerWeek);
7965 QString tmpString;
7966 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
7967 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
7968 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
7969 if(htmlLevel>=2)
7970 tmpString+=" <th class=\"xAxis\">";
7971 else
7972 tmpString+=" <th>";
7973 tmpString+=tr("All Activities");
7974 tmpString+="</th>";
7975 if(repeatNames){
7976 tmpString+="<td colspan=\"2\"></td>";
7977 }
7978 tmpString+="</tr>\n </thead>\n";
7979 /*workaround
7980 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td>"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
7981 */
7982 tmpString+=" <tbody>\n";
7983
7984 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
7985 tmpString+=" <tr>\n";
7986 if(hour==0)
7987 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
7988 else tmpString+=" <!-- span -->\n";
7989 if(htmlLevel>=2)
7990 tmpString+=" <th class=\"yAxis\">";
7991 else
7992 tmpString+=" <th>";
7993 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
7994 if(activitiesAtTime[day][hour].isEmpty()){
7995 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
7996 tmpString+=writeBreakSlot(htmlLevel, "");
7997 } else {
7998 tmpString+=writeEmpty(htmlLevel);
7999 }
8000 } else {
8001 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
8002 }
8003 if(repeatNames){
8004 if(htmlLevel>=2)
8005 tmpString+=" <th class=\"yAxis\">";
8006 else
8007 tmpString+=" <th>";
8008 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8009 if(hour==0)
8010 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8011 else tmpString+=" <!-- span -->\n";
8012 }
8013 tmpString+=" </tr>\n";
8014 }
8015 //workaround begin.
8016 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td>"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8017 if(repeatNames){
8018 tmpString+="<td colspan=\"2\"></td>";
8019 }
8020 tmpString+="</tr>\n";
8021 //workaround end.
8022 tmpString+=" </tbody>\n";
8023 tmpString+=" </table>\n\n";
8024 return tmpString;
8025 }
8026
8027 //by Volker Dirr
singleAllActivitiesTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,const QString & saveTime,bool printActivityTags,bool repeatNames)8028 QString TimetableExport::singleAllActivitiesTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, const QString& saveTime, bool printActivityTags, bool repeatNames){
8029 assert(day>=0);
8030 assert(day<gt.rules.nDaysPerWeek);
8031 QString tmpString;
8032 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
8033 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8034 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
8035 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
8036 if(repeatNames){
8037 tmpString+="<td rowspan=\"2\"></td>";
8038 }
8039 tmpString+="</tr>\n";
8040 tmpString+=" <tr>\n <!-- span -->\n";
8041 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8042 if(htmlLevel>=2)
8043 tmpString+=" <th class=\"xAxis\">";
8044 else
8045 tmpString+=" <th>";
8046 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8047 }
8048 tmpString+=" </tr>\n";
8049 tmpString+=" </thead>\n";
8050 /*workaround
8051 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8052 */
8053 tmpString+=" <tbody>\n";
8054
8055 tmpString+=" <tr>\n";
8056 if(htmlLevel>=2)
8057 tmpString+=" <th class=\"yAxis\">";
8058 else
8059 tmpString+=" <th>";
8060 tmpString+=tr("All Activities")+"</th>\n";
8061 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8062 if(activitiesAtTime[day][hour].isEmpty()){
8063 if(breakDayHour[day][hour] && PRINT_BREAK_TIME_SLOTS){
8064 tmpString+=writeBreakSlot(htmlLevel, "");
8065 } else {
8066 tmpString+=writeEmpty(htmlLevel);
8067 }
8068 } else {
8069 tmpString+=writeActivitiesStudents(htmlLevel, activitiesAtTime[day][hour], printActivityTags);
8070 }
8071 }
8072 if(repeatNames){
8073 if(htmlLevel>=2)
8074 tmpString+=" <th class=\"yAxis\">";
8075 else
8076 tmpString+=" <th>";
8077 tmpString+=tr("All Activities")+"</th>\n";
8078 }
8079 tmpString+=" </tr>\n";
8080 //workaround begin.
8081 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8082 if(repeatNames){
8083 tmpString+="<td></td>";
8084 }
8085 tmpString+="</tr>\n";
8086 //workaround end.
8087 tmpString+=" </tbody>\n";
8088 tmpString+=" </table>\n\n";
8089 return tmpString;
8090 }
8091
8092 //by Volker Dirr
singleTeachersTimetableDaysHorizontalHtml(int htmlLevel,int teacher,const QString & saveTime,bool printActivityTags,bool repeatNames)8093 QString TimetableExport::singleTeachersTimetableDaysHorizontalHtml(int htmlLevel, int teacher, const QString& saveTime, bool printActivityTags, bool repeatNames){
8094 assert(teacher>=0);
8095 assert(teacher<gt.rules.nInternalTeachers);
8096 QString tmpString;
8097 QString teacher_name = gt.rules.internalTeachersList[teacher]->name;
8098 tmpString+=" <table id=\"table_"+hashTeacherIDsTimetable.value(teacher_name)+"\" border=\"1\"";
8099 if(teacher%2==0) tmpString+=" class=\"odd_table\"";
8100 else tmpString+=" class=\"even_table\"";
8101 tmpString+=">\n";
8102
8103 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8104
8105 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(teacher_name)+"</th>";
8106 if(repeatNames){
8107 tmpString+="<td rowspan=\"2\"></td>";
8108 }
8109 tmpString+="</tr>\n";
8110 tmpString+=" <tr>\n <!-- span -->\n";
8111 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8112 if(htmlLevel>=2)
8113 tmpString+=" <th class=\"xAxis\">";
8114 else
8115 tmpString+=" <th>";
8116 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8117 }
8118 tmpString+=" </tr>\n";
8119 tmpString+=" </thead>\n";
8120 /*workaround
8121 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8122 */
8123 tmpString+=" <tbody>\n";
8124 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8125 tmpString+=" <tr>\n";
8126 if(htmlLevel>=2)
8127 tmpString+=" <th class=\"yAxis\">";
8128 else
8129 tmpString+=" <th>";
8130 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8131 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8132 QList<int> allActivities;
8133 allActivities.clear();
8134 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8135 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8136 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8137 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, false, true, printActivityTags, teacher_name);
8138 } else{
8139 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8140 }
8141 }
8142 if(repeatNames){
8143 if(htmlLevel>=2)
8144 tmpString+=" <th class=\"yAxis\">";
8145 else
8146 tmpString+=" <th>";
8147 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8148 }
8149 tmpString+=" </tr>\n";
8150 }
8151 //workaround begin.
8152 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8153 if(repeatNames){
8154 tmpString+="<td></td>";
8155 }
8156 tmpString+="</tr>\n";
8157 //workaround end.
8158 tmpString+=" </tbody>\n";
8159 tmpString+=" </table>\n\n";
8160 return tmpString;
8161 }
8162
8163
8164 //by Volker Dirr
singleTeachersTimetableDaysVerticalHtml(int htmlLevel,int teacher,const QString & saveTime,bool printActivityTags,bool repeatNames)8165 QString TimetableExport::singleTeachersTimetableDaysVerticalHtml(int htmlLevel, int teacher, const QString& saveTime, bool printActivityTags, bool repeatNames){
8166 assert(teacher>=0);
8167 assert(teacher<gt.rules.nInternalTeachers);
8168 QString tmpString;
8169 QString teacher_name = gt.rules.internalTeachersList[teacher]->name;
8170 tmpString+=" <table id=\"table_"+hashTeacherIDsTimetable.value(teacher_name)+"\" border=\"1\"";
8171 if(teacher%2==0) tmpString+=" class=\"odd_table\"";
8172 else tmpString+=" class=\"even_table\"";
8173 tmpString+=">\n";
8174
8175 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8176
8177 tmpString+=" <thead>\n";
8178 tmpString+=" <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(teacher_name)+"</th>";
8179 if(repeatNames){
8180 tmpString+="<td rowspan=\"2\"></td>";
8181 }
8182 tmpString+="</tr>\n";
8183 tmpString+=" <tr>\n <!-- span -->\n";
8184 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8185 if(htmlLevel>=2)
8186 tmpString+=" <th class=\"xAxis\">";
8187 else
8188 tmpString+=" <th>";
8189 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8190 }
8191 tmpString+=" </tr>\n";
8192 tmpString+=" </thead>\n";
8193 /*workaround
8194 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8195 */
8196 tmpString+=" <tbody>\n";
8197 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8198 tmpString+=" <tr>\n";
8199 if(htmlLevel>=2)
8200 tmpString+=" <th class=\"yAxis\">";
8201 else
8202 tmpString+=" <th>";
8203 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8204 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8205 QList<int> allActivities;
8206 allActivities.clear();
8207 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8208 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8209 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8210 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, true, false, printActivityTags, teacher_name);
8211 } else{
8212 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8213 }
8214 }
8215 if(repeatNames){
8216 if(htmlLevel>=2)
8217 tmpString+=" <th class=\"yAxis\">";
8218 else
8219 tmpString+=" <th>";
8220 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8221 }
8222 tmpString+=" </tr>\n";
8223 }
8224 //workaround begin.
8225 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8226 if(repeatNames){
8227 tmpString+="<td></td>";
8228 }
8229 tmpString+="</tr>\n";
8230 //workaround end.
8231 tmpString+=" </tbody>\n";
8232 tmpString+=" </table>\n\n";
8233 return tmpString;
8234 }
8235
8236
8237 //by Volker Dirr
singleTeachersTimetableTimeVerticalHtml(int htmlLevel,int maxTeachers,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8238 QString TimetableExport::singleTeachersTimetableTimeVerticalHtml(int htmlLevel, int maxTeachers, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8239 QString tmpString;
8240 tmpString+=" <table border=\"1\">\n";
8241 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8242
8243 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
8244 int currentCount=0;
8245 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8246 if(!excludedNames.contains(teacher)){
8247 currentCount++;
8248 if(htmlLevel>=2)
8249 tmpString+=" <th class=\"xAxis\">";
8250 else
8251 tmpString+=" <th>";
8252 tmpString+=gt.rules.internalTeachersList[teacher]->name+"</th>";
8253 }
8254 }
8255 if(repeatNames){
8256 tmpString+="<td colspan=\"2\"></td>";
8257 }
8258 tmpString+="</tr>\n </thead>\n";
8259 /*workaround
8260 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8261 */
8262 tmpString+=" <tbody>\n";
8263 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8264 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8265 tmpString+=" <tr>\n";
8266 if(hour==0)
8267 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8268 else tmpString+=" <!-- span -->\n";
8269 if(htmlLevel>=2)
8270 tmpString+=" <th class=\"yAxis\">";
8271 else
8272 tmpString+=" <th>";
8273 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8274 currentCount=0;
8275 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8276 if(!excludedNames.contains(teacher)){
8277 currentCount++;
8278 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
8279 excludedNames<<teacher;
8280 QList<int> allActivities;
8281 allActivities.clear();
8282 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8283 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8284 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8285 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, false, true, printActivityTags, gt.rules.internalTeachersList[teacher]->name);
8286 } else {
8287 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8288 }
8289 }
8290 }
8291 if(repeatNames){
8292 if(htmlLevel>=2)
8293 tmpString+=" <th class=\"yAxis\">";
8294 else
8295 tmpString+=" <th>";
8296 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8297 if(hour==0)
8298 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8299 else tmpString+=" <!-- span -->\n";
8300 }
8301 tmpString+=" </tr>\n";
8302 }
8303 }
8304 //workaround begin.
8305 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8306 if(repeatNames){
8307 tmpString+="<td colspan=\"2\"></td>";
8308 }
8309 tmpString+="</tr>\n";
8310 //workaround end.
8311 tmpString+=" </tbody>\n </table>\n";
8312 return tmpString;
8313 }
8314
8315 //by Volker Dirr
singleTeachersTimetableTimeHorizontalHtml(int htmlLevel,int maxTeachers,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8316 QString TimetableExport::singleTeachersTimetableTimeHorizontalHtml(int htmlLevel, int maxTeachers, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8317 QString tmpString;
8318 tmpString+=" <table border=\"1\">\n";
8319 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8320
8321 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
8322 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
8323 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
8324 if(repeatNames){
8325 tmpString+="<td rowspan=\"2\"></td>";
8326 }
8327 tmpString+="</tr>\n";
8328 tmpString+=" <tr>\n <!-- span -->\n";
8329 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8330 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8331 if(htmlLevel>=2)
8332 tmpString+=" <th class=\"xAxis\">";
8333 else
8334 tmpString+=" <th>";
8335 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8336 }
8337 }
8338 tmpString+=" </tr>\n";
8339 tmpString+=" </thead>\n";
8340 /*workaround
8341 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8342 */
8343 tmpString+=" <tbody>\n";
8344 int currentCount=0;
8345 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8346 if(!excludedNames.contains(teacher)){
8347 currentCount++;
8348 excludedNames<<teacher;
8349 tmpString+=" <tr>\n";
8350 if(htmlLevel>=2)
8351 tmpString+=" <th class=\"yAxis\">";
8352 else
8353 tmpString+=" <th>";
8354 tmpString+=protect2(gt.rules.internalTeachersList[teacher]->name)+"</th>\n";
8355 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8356 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8357 QList<int> allActivities;
8358 allActivities.clear();
8359 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8360 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8361 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8362 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, true, false, printActivityTags, gt.rules.internalTeachersList[teacher]->name);
8363 } else {
8364 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8365 }
8366 }
8367 }
8368 if(repeatNames){
8369 if(htmlLevel>=2)
8370 tmpString+=" <th class=\"yAxis\">";
8371 else
8372 tmpString+=" <th>";
8373 tmpString+=protect2(gt.rules.internalTeachersList[teacher]->name)+"</th>\n";
8374 }
8375 tmpString+=" </tr>\n";
8376 }
8377 }
8378 //workaround begin.
8379 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8380 if(repeatNames){
8381 tmpString+="<td></td>";
8382 }
8383 tmpString+="</tr>\n";
8384 //workaround end.
8385 tmpString+=" </tbody>\n </table>\n";
8386 return tmpString;
8387 }
8388
8389 //by Volker Dirr
singleTeachersTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxTeachers,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8390 QString TimetableExport::singleTeachersTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxTeachers, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8391 assert(day>=0);
8392 assert(day<gt.rules.nDaysPerWeek);
8393 QString tmpString;
8394 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
8395 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8396
8397 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
8398 int currentCount=0;
8399 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8400 if(!excludedNames.contains(teacher)){
8401 currentCount++;
8402 if(htmlLevel>=2)
8403 tmpString+=" <th class=\"xAxis\">";
8404 else
8405 tmpString+=" <th>";
8406 tmpString+=gt.rules.internalTeachersList[teacher]->name+"</th>";
8407 }
8408 }
8409 if(repeatNames){
8410 tmpString+="<td colspan=\"2\"></td>";
8411 }
8412 tmpString+="</tr>\n </thead>\n";
8413 /*workaround
8414 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8415 */
8416 tmpString+=" <tbody>\n";
8417
8418 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8419 tmpString+=" <tr>\n";
8420 if(hour==0)
8421 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8422 else tmpString+=" <!-- span -->\n";
8423 if(htmlLevel>=2)
8424 tmpString+=" <th class=\"yAxis\">";
8425 else
8426 tmpString+=" <th>";
8427 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8428 currentCount=0;
8429 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8430 if(!excludedNames.contains(teacher)){
8431 currentCount++;
8432 if(hour+1==gt.rules.nHoursPerDay)
8433 excludedNames<<teacher;
8434 QList<int> allActivities;
8435 allActivities.clear();
8436 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8437 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8438 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8439 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, false, true, printActivityTags, gt.rules.internalTeachersList[teacher]->name);
8440 } else {
8441 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8442 }
8443 }
8444 }
8445 if(repeatNames){
8446 if(htmlLevel>=2)
8447 tmpString+=" <th class=\"yAxis\">";
8448 else
8449 tmpString+=" <th>";
8450 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8451 if(hour==0)
8452 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8453 else tmpString+=" <!-- span -->\n";
8454 }
8455 tmpString+=" </tr>\n";
8456 }
8457 //workaround begin.
8458 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8459 if(repeatNames){
8460 tmpString+="<td colspan=\"2\"></td>";
8461 }
8462 tmpString+="</tr>\n";
8463 //workaround end.
8464 tmpString+=" </tbody>\n";
8465 tmpString+=" </table>\n\n";
8466 return tmpString;
8467 }
8468
8469 //by Volker Dirr
singleTeachersTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxTeachers,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8470 QString TimetableExport::singleTeachersTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxTeachers, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8471 assert(day>=0);
8472 assert(day<gt.rules.nDaysPerWeek);
8473 QString tmpString;
8474 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
8475 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8476
8477 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
8478 tmpString+="<th colspan=\"" +QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
8479 if(repeatNames){
8480 tmpString+="<td rowspan=\"2\"></td>";
8481 }
8482 tmpString+="</tr>\n";
8483 tmpString+=" <tr>\n <!-- span -->\n";
8484 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8485 if(htmlLevel>=2)
8486 tmpString+=" <th class=\"xAxis\">";
8487 else
8488 tmpString+=" <th>";
8489 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8490 }
8491 tmpString+=" </tr>\n";
8492 tmpString+=" </thead>\n";
8493 /*workaround
8494 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8495 */
8496 tmpString+=" <tbody>\n";
8497 int currentCount=0;
8498 for(int teacher=0; teacher<gt.rules.nInternalTeachers && currentCount<maxTeachers; teacher++){
8499 if(!excludedNames.contains(teacher)){
8500 currentCount++;
8501 excludedNames<<teacher;
8502 tmpString+=" <tr>\n";
8503 if(htmlLevel>=2)
8504 tmpString+=" <th class=\"yAxis\">";
8505 else
8506 tmpString+=" <th>";
8507 tmpString+=protect2(gt.rules.internalTeachersList[teacher]->name)+"</th>\n";
8508
8509 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8510 QList<int> allActivities;
8511 allActivities.clear();
8512 allActivities<<teachers_timetable_weekly[teacher][day][hour];
8513 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8514 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8515 tmpString+=writeActivityTeacher(htmlLevel, teacher, day, hour, true, false, printActivityTags, gt.rules.internalTeachersList[teacher]->name);
8516 } else {
8517 tmpString+=writeActivitiesTeachers(htmlLevel, allActivities, printActivityTags);
8518 }
8519 }
8520 if(repeatNames){
8521 if(htmlLevel>=2)
8522 tmpString+=" <th class=\"yAxis\">";
8523 else
8524 tmpString+=" <th>";
8525 tmpString+=protect2(gt.rules.internalTeachersList[teacher]->name)+"</th>\n";
8526 }
8527 tmpString+=" </tr>\n";
8528 }
8529 }
8530 //workaround begin.
8531 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8532 if(repeatNames){
8533 tmpString+="<td></td>";
8534 }
8535 tmpString+="</tr>\n";
8536 //workaround end.
8537 tmpString+=" </tbody>\n";
8538 tmpString+=" </table>\n\n";
8539 return tmpString;
8540 }
8541
8542 //by Volker Dirr
singleRoomsTimetableDaysHorizontalHtml(int htmlLevel,int room,const QString & saveTime,bool printActivityTags,bool repeatNames)8543 QString TimetableExport::singleRoomsTimetableDaysHorizontalHtml(int htmlLevel, int room, const QString& saveTime, bool printActivityTags, bool repeatNames){
8544 assert(room>=0);
8545 assert(room<gt.rules.nInternalRooms);
8546 QString tmpString;
8547 QString room_name = gt.rules.internalRoomsList[room]->name;
8548 tmpString+=" <table id=\"table_"+hashRoomIDsTimetable.value(room_name)+"\" border=\"1\"";
8549 if(room%2==0) tmpString+=" class=\"odd_table\"";
8550 else tmpString+=" class=\"even_table\"";
8551 tmpString+=">\n";
8552
8553 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8554
8555 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(room_name)+"</th>";
8556 if(repeatNames){
8557 tmpString+="<td rowspan=\"2\"></td>";
8558 }
8559 tmpString+="</tr>\n";
8560 tmpString+=" <tr>\n <!-- span -->\n";
8561 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8562 if(htmlLevel>=2)
8563 tmpString+=" <th class=\"xAxis\">";
8564 else
8565 tmpString+=" <th>";
8566 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8567 }
8568 tmpString+=" </tr>\n";
8569 tmpString+=" </thead>\n";
8570 /*workaround
8571 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8572 */
8573 tmpString+=" <tbody>\n";
8574 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8575 tmpString+=" <tr>\n";
8576 if(htmlLevel>=2)
8577 tmpString+=" <th class=\"yAxis\">";
8578 else
8579 tmpString+=" <th>";
8580 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8581 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8582 QList<int> allActivities;
8583 if(gt.rules.internalRoomsList[room]->isVirtual==false){
8584 allActivities<<rooms_timetable_weekly[room][day][hour];
8585 }
8586 else{
8587 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
8588 if(allActivities.isEmpty())
8589 allActivities<<UNALLOCATED_ACTIVITY;
8590 }
8591 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8592 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8593 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, false, true, printActivityTags);
8594 } else {
8595 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
8596 }
8597 }
8598 if(repeatNames){
8599 if(htmlLevel>=2)
8600 tmpString+=" <th class=\"yAxis\">";
8601 else
8602 tmpString+=" <th>";
8603 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8604 }
8605 tmpString+=" </tr>\n";
8606 }
8607 //workaround begin.
8608 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8609 if(repeatNames){
8610 tmpString+="<td></td>";
8611 }
8612 tmpString+="</tr>\n";
8613 //workaround end.
8614 tmpString+=" </tbody>\n";
8615 tmpString+=" </table>\n\n";
8616 return tmpString;
8617 }
8618
8619 //by Volker Dirr
singleRoomsTimetableDaysVerticalHtml(int htmlLevel,int room,const QString & saveTime,bool printActivityTags,bool repeatNames)8620 QString TimetableExport::singleRoomsTimetableDaysVerticalHtml(int htmlLevel, int room, const QString& saveTime, bool printActivityTags, bool repeatNames){
8621 assert(room>=0);
8622 assert(room<gt.rules.nInternalRooms);
8623 QString tmpString;
8624 QString room_name = gt.rules.internalRoomsList[room]->name;
8625 tmpString+=" <table id=\"table_"+hashRoomIDsTimetable.value(room_name)+"\" border=\"1\"";
8626 if(room%2==0) tmpString+=" class=\"odd_table\"";
8627 else tmpString+=" class=\"even_table\"";
8628 tmpString+=">\n";
8629
8630 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8631
8632 tmpString+=" <thead>\n";
8633 tmpString+=" <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(room_name)+"</th>";
8634 if(repeatNames){
8635 tmpString+="<td rowspan=\"2\"></td>";
8636 }
8637 tmpString+="</tr>\n";
8638 tmpString+=" <tr>\n <!-- span -->\n";
8639 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8640 if(htmlLevel>=2)
8641 tmpString+=" <th class=\"xAxis\">";
8642 else
8643 tmpString+=" <th>";
8644 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8645 }
8646 tmpString+=" </tr>\n";
8647 tmpString+=" </thead>\n";
8648 /*workaround
8649 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8650 */
8651 tmpString+=" <tbody>\n";
8652 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8653 tmpString+=" <tr>\n";
8654 if(htmlLevel>=2)
8655 tmpString+=" <th class=\"yAxis\">";
8656 else
8657 tmpString+=" <th>";
8658 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8659 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8660 QList<int> allActivities;
8661
8662 if(gt.rules.internalRoomsList[room]->isVirtual==false){
8663 allActivities<<rooms_timetable_weekly[room][day][hour];
8664 }
8665 else{
8666 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
8667 if(allActivities.isEmpty())
8668 allActivities<<UNALLOCATED_ACTIVITY;
8669 }
8670
8671 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8672 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8673 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, true, false, printActivityTags);
8674 } else {
8675 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
8676 }
8677 }
8678 if(repeatNames){
8679 if(htmlLevel>=2)
8680 tmpString+=" <th class=\"yAxis\">";
8681 else
8682 tmpString+=" <th>";
8683 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
8684 }
8685 tmpString+=" </tr>\n";
8686 }
8687 //workaround begin.
8688 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8689 if(repeatNames){
8690 tmpString+="<td></td>";
8691 }
8692 tmpString+="</tr>\n";
8693 //workaround end.
8694 tmpString+=" </tbody>\n";
8695 tmpString+=" </table>\n\n";
8696 return tmpString;
8697 }
8698
8699
8700 //by Volker Dirr
singleRoomsTimetableTimeVerticalHtml(int htmlLevel,int maxRooms,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8701 QString TimetableExport::singleRoomsTimetableTimeVerticalHtml(int htmlLevel, int maxRooms, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8702 QString tmpString;
8703 tmpString+=" <table border=\"1\">\n";
8704 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8705
8706 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
8707 int currentCount=0;
8708 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8709 if(!excludedNames.contains(room)){
8710 currentCount++;
8711 if(htmlLevel>=2)
8712 tmpString+=" <th class=\"xAxis\">";
8713 else
8714 tmpString+=" <th>";
8715 tmpString+=gt.rules.internalRoomsList[room]->name+"</th>";
8716 }
8717 }
8718 if(repeatNames){
8719 tmpString+="<td colspan=\"2\"></td>";
8720 }
8721 tmpString+="</tr>\n </thead>\n";
8722 /*workaround
8723 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8724 */
8725 tmpString+=" <tbody>\n";
8726 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8727 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8728 tmpString+=" <tr>\n";
8729 if(hour==0)
8730 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8731 else tmpString+=" <!-- span -->\n";
8732 if(htmlLevel>=2)
8733 tmpString+=" <th class=\"yAxis\">";
8734 else
8735 tmpString+=" <th>";
8736 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8737 currentCount=0;
8738 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8739 if(!excludedNames.contains(room)){
8740 currentCount++;
8741 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
8742 excludedNames<<room;
8743 QList<int> allActivities;
8744
8745 if(gt.rules.internalRoomsList[room]->isVirtual==false){
8746 allActivities<<rooms_timetable_weekly[room][day][hour];
8747 }
8748 else{
8749 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
8750 if(allActivities.isEmpty())
8751 allActivities<<UNALLOCATED_ACTIVITY;
8752 }
8753
8754 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8755 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8756 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, false, true, printActivityTags);
8757 } else {
8758 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
8759 }
8760 }
8761 }
8762 if(repeatNames){
8763 if(htmlLevel>=2)
8764 tmpString+=" <th class=\"yAxis\">";
8765 else
8766 tmpString+=" <th>";
8767 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8768 if(hour==0)
8769 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8770 else tmpString+=" <!-- span -->\n";
8771 }
8772 tmpString+=" </tr>\n";
8773 }
8774 }
8775 //workaround begin.
8776 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8777 if(repeatNames){
8778 tmpString+="<td colspan=\"2\"></td>";
8779 }
8780 tmpString+="</tr>\n";
8781 //workaround end.
8782 tmpString+=" </tbody>\n </table>\n";
8783 return tmpString;
8784 }
8785
8786 //by Volker Dirr
singleRoomsTimetableTimeHorizontalHtml(int htmlLevel,int maxRooms,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8787 QString TimetableExport::singleRoomsTimetableTimeHorizontalHtml(int htmlLevel, int maxRooms, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8788 QString tmpString;
8789 tmpString+=" <table border=\"1\">\n";
8790 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8791
8792 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
8793 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
8794 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
8795 if(repeatNames){
8796 tmpString+="<td rowspan=\"2\"></td>";
8797 }
8798 tmpString+="</tr>\n";
8799 tmpString+=" <tr>\n <!-- span -->\n";
8800 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8801 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8802 if(htmlLevel>=2)
8803 tmpString+=" <th class=\"xAxis\">";
8804 else
8805 tmpString+=" <th>";
8806 tmpString+=protect2(gt.rules.hoursOfTheDay[hour]) + "</th>\n";
8807 }
8808 }
8809 tmpString+=" </tr>\n";
8810 tmpString+=" </thead>\n";
8811 /*workaround
8812 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8813 */
8814 tmpString+=" <tbody>\n";
8815 int currentCount=0;
8816 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8817 if(!excludedNames.contains(room)){
8818 currentCount++;
8819 excludedNames<<room;
8820
8821 tmpString+=" <tr>\n";
8822 if(htmlLevel>=2)
8823 tmpString+=" <th class=\"yAxis\">";
8824 else
8825 tmpString+=" <th>";
8826 tmpString+=protect2(gt.rules.internalRoomsList[room]->name)+"</th>\n";
8827 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
8828 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8829 QList<int> allActivities;
8830
8831 if(gt.rules.internalRoomsList[room]->isVirtual==false){
8832 allActivities<<rooms_timetable_weekly[room][day][hour];
8833 }
8834 else{
8835 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
8836 if(allActivities.isEmpty())
8837 allActivities<<UNALLOCATED_ACTIVITY;
8838 }
8839
8840 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8841 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8842 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, true, false, printActivityTags);
8843 } else {
8844 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
8845 }
8846 }
8847 }
8848 if(repeatNames){
8849 if(htmlLevel>=2)
8850 tmpString+=" <th class=\"yAxis\">";
8851 else
8852 tmpString+=" <th>";
8853 tmpString+=protect2(gt.rules.internalRoomsList[room]->name)+"</th>\n";
8854 }
8855 tmpString+=" </tr>\n";
8856 }
8857 }
8858 //workaround begin.
8859 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8860 if(repeatNames){
8861 tmpString+="<td></td>";
8862 }
8863 tmpString+="</tr>\n";
8864 //workaround end.
8865 tmpString+=" </tbody>\n </table>\n";
8866 return tmpString;
8867 }
8868
8869
8870 //by Volker Dirr
singleRoomsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxRooms,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8871 QString TimetableExport::singleRoomsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxRooms, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8872 assert(day>=0);
8873 assert(day<gt.rules.nDaysPerWeek);
8874 QString tmpString;
8875 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
8876 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8877
8878 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
8879 int currentCount=0;
8880 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8881 if(!excludedNames.contains(room)){
8882 currentCount++;
8883 if(htmlLevel>=2)
8884 tmpString+=" <th class=\"xAxis\">";
8885 else
8886 tmpString+=" <th>";
8887 tmpString+=gt.rules.internalRoomsList[room]->name+"</th>";
8888 }
8889 }
8890 if(repeatNames){
8891 tmpString+="<td colspan=\"2\"></td>";
8892 }
8893 tmpString+="</tr>\n </thead>\n";
8894 /*workaround
8895 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8896 */
8897 tmpString+=" <tbody>\n";
8898
8899 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8900 tmpString+=" <tr>\n";
8901 if(hour==0)
8902 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8903 else tmpString+=" <!-- span -->\n";
8904 if(htmlLevel>=2)
8905 tmpString+=" <th class=\"yAxis\">";
8906 else
8907 tmpString+=" <th>";
8908 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8909 currentCount=0;
8910 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8911 if(!excludedNames.contains(room)){
8912 currentCount++;
8913 if(hour+1==gt.rules.nHoursPerDay)
8914 excludedNames<<room;
8915 QList<int> allActivities;
8916
8917 if(gt.rules.internalRoomsList[room]->isVirtual==false){
8918 allActivities<<rooms_timetable_weekly[room][day][hour];
8919 }
8920 else{
8921 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
8922 if(allActivities.isEmpty())
8923 allActivities<<UNALLOCATED_ACTIVITY;
8924 }
8925
8926 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
8927 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
8928 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, false, true, printActivityTags);
8929 } else {
8930 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
8931 }
8932 }
8933 }
8934 if(repeatNames){
8935 if(htmlLevel>=2)
8936 tmpString+=" <th class=\"yAxis\">";
8937 else
8938 tmpString+=" <th>";
8939 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8940
8941 if(hour==0)
8942 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
8943 else tmpString+=" <!-- span -->\n";
8944 }
8945 tmpString+=" </tr>\n";
8946 }
8947 //workaround begin.
8948 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
8949 if(repeatNames){
8950 tmpString+="<td colspan=\"2\"></td>";
8951 }
8952 tmpString+="</tr>\n";
8953 //workaround end.
8954 tmpString+=" </tbody>\n";
8955 tmpString+=" </table>\n\n";
8956 return tmpString;
8957 }
8958
8959 //by Volker Dirr
singleRoomsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxRooms,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)8960 QString TimetableExport::singleRoomsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxRooms, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
8961 assert(day>=0);
8962 assert(day<gt.rules.nDaysPerWeek);
8963 QString tmpString;
8964 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
8965 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
8966
8967 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
8968 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
8969 if(repeatNames){
8970 tmpString+="<td rowspan=\"2\"></td>";
8971 }
8972 tmpString+="</tr>\n";
8973 tmpString+=" <tr>\n <!-- span -->\n";
8974 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8975 if(htmlLevel>=2)
8976 tmpString+=" <th class=\"xAxis\">";
8977 else
8978 tmpString+=" <th>";
8979 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
8980 }
8981 tmpString+=" </tr>\n";
8982 tmpString+=" </thead>\n";
8983 /*workaround
8984 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
8985 */
8986 tmpString+=" <tbody>\n";
8987 int currentCount=0;
8988 for(int room=0; room<gt.rules.nInternalRooms && currentCount<maxRooms; room++){
8989 if(!excludedNames.contains(room)){
8990 currentCount++;
8991 excludedNames<<room;
8992 tmpString+=" <tr>\n";
8993 if(htmlLevel>=2)
8994 tmpString+=" <th class=\"yAxis\">";
8995 else
8996 tmpString+=" <th>";
8997 tmpString+=protect2(gt.rules.internalRoomsList[room]->name)+"</th>\n";
8998 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
8999 QList<int> allActivities;
9000
9001 if(gt.rules.internalRoomsList[room]->isVirtual==false){
9002 allActivities<<rooms_timetable_weekly[room][day][hour];
9003 }
9004 else{
9005 allActivities<<virtual_rooms_timetable_weekly[room][day][hour];
9006 if(allActivities.isEmpty())
9007 allActivities<<UNALLOCATED_ACTIVITY;
9008 }
9009
9010 bool activitiesWithSameStartingtime=addActivitiesWithSameStartingTime(allActivities, hour);
9011 if(allActivities.size()==1 && !activitiesWithSameStartingtime){ // because i am using colspan or rowspan!!!
9012 tmpString+=writeActivityRoom(htmlLevel, room, day, hour, true, false, printActivityTags);
9013 } else {
9014 tmpString+=writeActivitiesRooms(htmlLevel, allActivities, printActivityTags);
9015 }
9016 }
9017 if(repeatNames){
9018 if(htmlLevel>=2)
9019 tmpString+=" <th class=\"yAxis\">";
9020 else
9021 tmpString+=" <th>";
9022 tmpString+=protect2(gt.rules.internalRoomsList[room]->name)+"</th>\n";
9023 }
9024 tmpString+=" </tr>\n";
9025 }
9026 }
9027 //workaround begin.
9028 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9029 if(repeatNames){
9030 tmpString+="<td></td>";
9031 }
9032 tmpString+="</tr>\n";
9033 //workaround end.
9034 tmpString+=" </tbody>\n";
9035 tmpString+=" </table>\n\n";
9036 return tmpString;
9037 }
9038
9039 //by Volker Dirr
singleSubjectsTimetableDaysHorizontalHtml(int htmlLevel,int subject,const QString & saveTime,bool printActivityTags,bool repeatNames)9040 QString TimetableExport::singleSubjectsTimetableDaysHorizontalHtml(int htmlLevel, int subject, const QString& saveTime, bool printActivityTags, bool repeatNames){
9041 assert(subject>=0);
9042 assert(subject<gt.rules.nInternalSubjects);
9043 QString tmpString;
9044 ///////by Liviu Lalescu
9045 activitiesForCurrentSubject.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9046 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9047 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9048 activitiesForCurrentSubject[d][h].clear();
9049 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9050 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9051 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9052 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9053 Activity* act=>.rules.internalActivitiesList[ai];
9054 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9055 activitiesForCurrentSubject[d][h+dd].append(ai);
9056 }
9057 ///////end Liviu Lalescu
9058 tmpString+=" <table id=\"table_"+hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[subject]->name);
9059 tmpString+="\" border=\"1\"";
9060 if(subject%2==0) tmpString+=" class=\"odd_table\"";
9061 else tmpString+=" class=\"even_table\"";
9062 tmpString+=">\n";
9063
9064 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9065
9066 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>";
9067 if(repeatNames){
9068 tmpString+="<td rowspan=\"2\"></td>";
9069 }
9070 tmpString+="</tr>\n";
9071 tmpString+=" <tr>\n <!-- span -->\n";
9072 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9073 if(htmlLevel>=2)
9074 tmpString+=" <th class=\"xAxis\">";
9075 else
9076 tmpString+=" <th>";
9077 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9078 }
9079 tmpString+=" </tr>\n";
9080 tmpString+=" </thead>\n";
9081 /*workaround
9082 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9083 */
9084 tmpString+=" <tbody>\n";
9085 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9086 tmpString+=" <tr>\n";
9087 if(htmlLevel>=2)
9088 tmpString+=" <th class=\"yAxis\">";
9089 else
9090 tmpString+=" <th>";
9091 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9092 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9093 QList<int> allActivities;
9094
9095 allActivities=activitiesForCurrentSubject[day][hour];
9096
9097 /*
9098 allActivities.clear();
9099 //Now get the activitiy ids. I don't run through the InternalActivitiesList, even that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9100 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9101 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9102 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9103 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9104 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9105 allActivities+students_timetable_weekly[subgroup][day][hour];
9106 }
9107 }
9108 }
9109 //Now run through the teachers timetable, because activities without a students set are still missing.
9110 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9111 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9112 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9113 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9114 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9115 assert(act->studentsNames.isEmpty());
9116 allActivities+teachers_timetable_weekly[teacher][day][hour];
9117 }
9118 }
9119 }*/
9120 addActivitiesWithSameStartingTime(allActivities, hour);
9121 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9122 }
9123 if(repeatNames){
9124 if(htmlLevel>=2)
9125 tmpString+=" <th class=\"yAxis\">";
9126 else
9127 tmpString+=" <th>";
9128 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9129 }
9130 tmpString+=" </tr>\n";
9131 }
9132 //workaround begin.
9133 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9134 if(repeatNames){
9135 tmpString+="<td></td>";
9136 }
9137 tmpString+="</tr>\n";
9138 //workaround end.
9139 tmpString+=" </tbody>\n";
9140 tmpString+=" </table>\n\n";
9141 return tmpString;
9142 }
9143
9144 //by Volker Dirr
singleSubjectsTimetableDaysVerticalHtml(int htmlLevel,int subject,const QString & saveTime,bool printActivityTags,bool repeatNames)9145 QString TimetableExport::singleSubjectsTimetableDaysVerticalHtml(int htmlLevel, int subject, const QString& saveTime, bool printActivityTags, bool repeatNames){
9146 assert(subject>=0);
9147 assert(subject<gt.rules.nInternalSubjects);
9148 QString tmpString;
9149 ///////by Liviu Lalescu
9150 activitiesForCurrentSubject.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9151 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9152 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9153 activitiesForCurrentSubject[d][h].clear();
9154 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9155 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9156 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9157 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9158 Activity* act=>.rules.internalActivitiesList[ai];
9159 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9160 activitiesForCurrentSubject[d][h+dd].append(ai);
9161 }
9162 ///////end Liviu Lalescu
9163 tmpString+=" <table id=\"table_"+hashSubjectIDsTimetable.value(gt.rules.internalSubjectsList[subject]->name);
9164 tmpString+="\" border=\"1\"";
9165 if(subject%2==0) tmpString+=" class=\"odd_table\"";
9166 else tmpString+=" class=\"even_table\"";
9167 tmpString+=">\n";
9168
9169 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9170
9171 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>";
9172 if(repeatNames){
9173 tmpString+="<td rowspan=\"2\"></td>";
9174 }
9175 tmpString+="</tr>\n";
9176 tmpString+=" <tr>\n <!-- span -->\n";
9177 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9178 if(htmlLevel>=2)
9179 tmpString+=" <th class=\"xAxis\">";
9180 else
9181 tmpString+=" <th>";
9182 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9183 }
9184 tmpString+=" </tr>\n";
9185 tmpString+=" </thead>\n";
9186 /*workaround
9187 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9188 */
9189 tmpString+=" <tbody>\n";
9190 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9191 tmpString+=" <tr>\n";
9192 if(htmlLevel>=2)
9193 tmpString+=" <th class=\"yAxis\">";
9194 else
9195 tmpString+=" <th>";
9196 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9197 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9198 QList<int> allActivities;
9199
9200 allActivities=activitiesForCurrentSubject[day][hour];
9201
9202 /*
9203 allActivities.clear();
9204 //Now get the activitiy ids. I don't run through the InternalActivitiesList, even that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9205 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9206 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9207 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9208 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9209 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9210 allActivities+students_timetable_weekly[subgroup][day][hour];
9211 }
9212 }
9213 }
9214 //Now run through the teachers timetable, because activities without a students set are still missing.
9215 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9216 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9217 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9218 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9219 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9220 assert(act->studentsNames.isEmpty());
9221 allActivities+teachers_timetable_weekly[teacher][day][hour];
9222 }
9223 }
9224 }
9225 */
9226 addActivitiesWithSameStartingTime(allActivities, hour);
9227 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9228 }
9229 if(repeatNames){
9230 if(htmlLevel>=2)
9231 tmpString+=" <th class=\"yAxis\">";
9232 else
9233 tmpString+=" <th>";
9234 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9235 }
9236 tmpString+=" </tr>\n";
9237 }
9238 //workaround begin.
9239 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9240 if(repeatNames){
9241 tmpString+="<td></td>";
9242 }
9243 tmpString+="</tr>\n";
9244 //workaround end.
9245 tmpString+=" </tbody>\n";
9246 tmpString+=" </table>\n\n";
9247 return tmpString;
9248 }
9249
9250
9251 //by Volker Dirr
singleSubjectsTimetableTimeVerticalHtml(int htmlLevel,int maxSubjects,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9252 QString TimetableExport::singleSubjectsTimetableTimeVerticalHtml(int htmlLevel, int maxSubjects, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9253 QString tmpString;
9254 tmpString+=" <table id=\"table\" border=\"1\">\n";
9255
9256 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9257
9258 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
9259 int currentCount=0;
9260 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9261 if(!excludedNames.contains(subject)){
9262 currentCount++;
9263 if(htmlLevel>=2)
9264 tmpString+=" <th class=\"xAxis\">";
9265 else
9266 tmpString+=" <th>";
9267 tmpString+=gt.rules.internalSubjectsList[subject]->name+"</th>";
9268 }
9269 }
9270 if(repeatNames){
9271 tmpString+="<td colspan=\"2\"></td>";
9272 }
9273 tmpString+="</tr>\n </thead>\n";
9274 /*workaround
9275 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9276 */
9277 tmpString+=" <tbody>\n";
9278
9279 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9280 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9281 tmpString+=" <tr>\n";
9282 if(hour==0)
9283 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9284 else tmpString+=" <!-- span -->\n";
9285 if(htmlLevel>=2)
9286 tmpString+=" <th class=\"yAxis\">";
9287 else
9288 tmpString+=" <th>";
9289 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9290
9291 currentCount=0;
9292 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9293 if(!excludedNames.contains(subject)){
9294 currentCount++;
9295 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
9296 excludedNames<<subject;
9297 QList<int> allActivities;
9298 allActivities.clear();
9299
9300 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9301 if(activitiesAtTime[day][hour].contains(ai)){
9302 assert(!allActivities.contains(ai));
9303 allActivities.append(ai);
9304 }
9305
9306 /* //Now get the activities ids. I don't run through the InternalActivitiesList, even if that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9307 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9308 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9309 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9310 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9311 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9312 allActivities+students_timetable_weekly[subgroup][day][hour];
9313 }
9314 }
9315 }
9316 //Now run through the teachers timetable, because activities without a students set are still missing.
9317 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9318 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9319 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9320 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9321 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9322 assert(act->studentsNames.isEmpty());
9323 allActivities+teachers_timetable_weekly[teacher][day][hour];
9324 }
9325 }
9326 }*/
9327 addActivitiesWithSameStartingTime(allActivities, hour);
9328 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9329 }
9330 }
9331 if(repeatNames){
9332 if(htmlLevel>=2)
9333 tmpString+=" <th class=\"yAxis\">";
9334 else
9335 tmpString+=" <th>";
9336 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9337 if(hour==0)
9338 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9339 else tmpString+=" <!-- span -->\n";
9340 }
9341 tmpString+=" </tr>\n";
9342 }
9343 }
9344 //workaround begin.
9345 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9346 if(repeatNames){
9347 tmpString+="<td colspan=\"2\"></td>";
9348 }
9349 tmpString+="</tr>\n";
9350 //workaround end.
9351 tmpString+=" </tbody>\n </table>\n";
9352 return tmpString;
9353 }
9354
9355 //by Volker Dirr
singleSubjectsTimetableTimeHorizontalHtml(int htmlLevel,int maxSubjects,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9356 QString TimetableExport::singleSubjectsTimetableTimeHorizontalHtml(int htmlLevel, int maxSubjects, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9357 QString tmpString;
9358 tmpString+=" <table id=\"table\" border=\"1\">\n";
9359
9360 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9361
9362 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
9363
9364 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
9365 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
9366 if(repeatNames){
9367 tmpString+="<td rowspan=\"2\"></td>";
9368 }
9369 tmpString+="</tr>\n";
9370 tmpString+=" <tr>\n <!-- span -->\n";
9371 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9372 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9373 if(htmlLevel>=2)
9374 tmpString+=" <th class=\"xAxis\">";
9375 else
9376 tmpString+=" <th>";
9377 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9378 }
9379 }
9380 tmpString+=" </tr>\n";
9381 tmpString+=" </thead>\n";
9382 /*workaround
9383 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9384 */
9385 tmpString+=" <tbody>\n";
9386 int currentCount=0;
9387 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9388 if(!excludedNames.contains(subject)){
9389 currentCount++;
9390 excludedNames<<subject;
9391 tmpString+=" <tr>\n";
9392 if(htmlLevel>=2)
9393 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9394 else
9395 tmpString+=" <th>"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9396
9397 ///////by Liviu Lalescu
9398 activitiesForCurrentSubject.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9399 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9400 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9401 activitiesForCurrentSubject[d][h].clear();
9402 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9403 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9404 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9405 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9406 Activity* act=>.rules.internalActivitiesList[ai];
9407 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9408 activitiesForCurrentSubject[d][h+dd].append(ai);
9409 }
9410 ///////end Liviu Lalescu
9411
9412 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9413 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9414 QList<int> allActivities;
9415
9416 allActivities=activitiesForCurrentSubject[day][hour];
9417
9418 /*allActivities.clear();
9419 //Now get the activitiy ids. I don't run through the InternalActivitiesList, even that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9420 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9421 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9422 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9423 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9424 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9425 allActivities+students_timetable_weekly[subgroup][day][hour];
9426 }
9427 }
9428 }
9429 //Now run through the teachers timetable, because activities without a students set are still missing.
9430 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9431 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9432 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9433 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9434 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9435 assert(act->studentsNames.isEmpty());
9436 allActivities+teachers_timetable_weekly[teacher][day][hour];
9437 }
9438 }
9439 }*/
9440 addActivitiesWithSameStartingTime(allActivities, hour);
9441 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9442 }
9443 }
9444 if(repeatNames){
9445 if(htmlLevel>=2)
9446 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9447 else
9448 tmpString+=" <th>"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9449 }
9450 tmpString+=" </tr>\n";
9451 }
9452 }
9453 //workaround begin.
9454 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9455 if(repeatNames){
9456 tmpString+="<td></td>";
9457 }
9458 tmpString+="</tr>\n";
9459 //workaround end.
9460 tmpString+=" </tbody>\n </table>\n";
9461 return tmpString;
9462 }
9463
9464 //by Volker Dirr
singleSubjectsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxSubjects,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9465 QString TimetableExport::singleSubjectsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxSubjects, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9466 assert(day>=0);
9467 assert(day<gt.rules.nDaysPerWeek);
9468 QString tmpString;
9469 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
9470 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9471 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
9472 int currentCount=0;
9473 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9474 if(!excludedNames.contains(subject)){
9475 currentCount++;
9476
9477 if(htmlLevel>=2)
9478 tmpString+=" <th class=\"xAxis\">";
9479 else
9480 tmpString+=" <th>";
9481 tmpString+=gt.rules.internalSubjectsList[subject]->name+"</th>";
9482 }
9483 }
9484 if(repeatNames){
9485 tmpString+="<td colspan=\"2\"></td>";
9486 }
9487 tmpString+="</tr>\n </thead>\n";
9488 /*workaround
9489 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9490 */
9491 tmpString+=" <tbody>\n";
9492 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9493 tmpString+=" <tr>\n";
9494 if(hour==0)
9495 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9496 else tmpString+=" <!-- span -->\n";
9497 if(htmlLevel>=2)
9498 tmpString+=" <th class=\"yAxis\">";
9499 else
9500 tmpString+=" <th>";
9501 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9502
9503 currentCount=0;
9504 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9505 if(!excludedNames.contains(subject)){
9506 currentCount++;
9507 if(hour+1==gt.rules.nHoursPerDay)
9508 excludedNames<<subject;
9509 QList<int> allActivities;
9510 allActivities.clear();
9511
9512 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9513 if(activitiesAtTime[day][hour].contains(ai)){
9514 assert(!allActivities.contains(ai));
9515 allActivities.append(ai);
9516 }
9517
9518 /*//Now get the activitiy ids. I don't run through the InternalActivitiesList, even that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9519 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9520 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9521 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9522 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9523 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9524 allActivities+students_timetable_weekly[subgroup][day][hour];
9525 }
9526 }
9527 }
9528 //Now run through the teachers timetable, because activities without a students set are still missing.
9529 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9530 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9531 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9532 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9533 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9534 assert(act->studentsNames.isEmpty());
9535 allActivities+teachers_timetable_weekly[teacher][day][hour];
9536 }
9537 }
9538 }*/
9539 addActivitiesWithSameStartingTime(allActivities, hour);
9540 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9541 }
9542 }
9543 if(repeatNames){
9544 if(htmlLevel>=2)
9545 tmpString+=" <th class=\"yAxis\">";
9546 else
9547 tmpString+=" <th>";
9548 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9549 if(hour==0)
9550 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9551 else tmpString+=" <!-- span -->\n";
9552 }
9553 tmpString+=" </tr>\n";
9554 }
9555 //workaround begin.
9556 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9557 if(repeatNames){
9558 tmpString+="<td colspan=\"2\"></td>";
9559 }
9560 tmpString+="</tr>\n";
9561 //workaround end.
9562 tmpString+=" </tbody>\n";
9563 tmpString+=" </table>\n\n";
9564 return tmpString;
9565 }
9566
9567 //by Volker Dirr
singleSubjectsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxSubjects,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9568 QString TimetableExport::singleSubjectsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxSubjects, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9569 assert(day>=0);
9570 assert(day<gt.rules.nDaysPerWeek);
9571 QString tmpString;
9572 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
9573 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9574 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
9575
9576 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
9577 if(repeatNames){
9578 tmpString+="<td rowspan=\"2\"></td>";
9579 }
9580 tmpString+="</tr>\n";
9581 tmpString+=" <tr>\n <!-- span -->\n";
9582 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9583 if(htmlLevel>=2)
9584 tmpString+=" <th class=\"xAxis\">";
9585 else
9586 tmpString+=" <th>";
9587 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9588 }
9589 tmpString+=" </tr>\n";
9590 tmpString+=" </thead>\n";
9591 /*workaround
9592 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9593 */
9594 tmpString+=" <tbody>\n";
9595 int currentCount=0;
9596 for(int subject=0; subject<gt.rules.nInternalSubjects && currentCount<maxSubjects; subject++){
9597 if(!excludedNames.contains(subject)){
9598 currentCount++;
9599 excludedNames<<subject;
9600 tmpString+=" <tr>\n";
9601 if(htmlLevel>=2)
9602 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9603 else
9604 tmpString+=" <th>"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9605
9606 ///////by Liviu Lalescu
9607 activitiesForCurrentSubject.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9608 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9609 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9610 activitiesForCurrentSubject[d][h].clear();
9611 for(int ai : qAsConst(gt.rules.activitiesForSubjectList[subject]))
9612 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9613 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9614 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9615 Activity* act=>.rules.internalActivitiesList[ai];
9616 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9617 activitiesForCurrentSubject[d][h+dd].append(ai);
9618 }
9619 ///////end Liviu Lalescu
9620
9621 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9622 QList<int> allActivities;
9623
9624 allActivities=activitiesForCurrentSubject[day][hour];
9625
9626 /*allActivities.clear();
9627 //Now get the activitiy ids. I don't run through the InternalActivitiesList, even that is faster. I run through subgroupsList, because by that the activites are sorted by that in the html-table.
9628 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
9629 if(students_timetable_weekly[subgroup][day][hour]!=UNALLOCATED_ACTIVITY){
9630 Activity* act=>.rules.internalActivitiesList[students_timetable_weekly[subgroup][day][hour]];
9631 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9632 if(!(allActivities.contains(students_timetable_weekly[subgroup][day][hour]))){
9633 allActivities+students_timetable_weekly[subgroup][day][hour];
9634 }
9635 }
9636 }
9637 //Now run through the teachers timetable, because activities without a students set are still missing.
9638 for(int teacher=0; teacher<gt.rules.nInternalTeachers; teacher++){
9639 if(teachers_timetable_weekly[teacher][day][hour]!=UNALLOCATED_ACTIVITY){
9640 Activity* act=>.rules.internalActivitiesList[teachers_timetable_weekly[teacher][day][hour]];
9641 if(act->subjectName==gt.rules.internalSubjectsList[subject]->name)
9642 if(!(allActivities.contains(teachers_timetable_weekly[teacher][day][hour]))){
9643 assert(act->studentsNames.isEmpty());
9644 allActivities+teachers_timetable_weekly[teacher][day][hour];
9645 }
9646 }
9647 }*/
9648 addActivitiesWithSameStartingTime(allActivities, hour);
9649 tmpString+=writeActivitiesSubjects(htmlLevel, allActivities, printActivityTags);
9650 }
9651 if(repeatNames){
9652 if(htmlLevel>=2)
9653 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9654 else
9655 tmpString+=" <th>"+protect2(gt.rules.internalSubjectsList[subject]->name)+"</th>\n";
9656 }
9657 tmpString+=" </tr>\n";
9658 }
9659 }
9660 //workaround begin.
9661 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9662 if(repeatNames){
9663 tmpString+="<td></td>";
9664 }
9665 tmpString+="</tr>\n";
9666 //workaround end.
9667 tmpString+=" </tbody>\n";
9668 tmpString+=" </table>\n\n";
9669 return tmpString;
9670 }
9671
9672
9673 //by Volker Dirr
singleActivityTagsTimetableDaysHorizontalHtml(int htmlLevel,int activityTag,const QString & saveTime,bool printActivityTags,bool repeatNames)9674 QString TimetableExport::singleActivityTagsTimetableDaysHorizontalHtml(int htmlLevel, int activityTag, const QString& saveTime, bool printActivityTags, bool repeatNames){
9675 assert(activityTag>=0);
9676 assert(activityTag<gt.rules.nInternalActivityTags);
9677 QString tmpString;
9678 ///////by Liviu Lalescu
9679 activitiesForCurrentActivityTag.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9680 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9681 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9682 activitiesForCurrentActivityTag[d][h].clear();
9683 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
9684 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9685 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9686 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9687 Activity* act=>.rules.internalActivitiesList[ai];
9688 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9689 activitiesForCurrentActivityTag[d][h+dd].append(ai);
9690 }
9691 ///////end Liviu Lalescu
9692 tmpString+=" <table id=\"table_"+hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[activityTag]->name);
9693 tmpString+="\" border=\"1\"";
9694 if(activityTag%2==0) tmpString+=" class=\"odd_table\"";
9695 else tmpString+=" class=\"even_table\"";
9696 tmpString+=">\n";
9697
9698 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9699
9700 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>";
9701 if(repeatNames){
9702 tmpString+="<td rowspan=\"2\"></td>";
9703 }
9704 tmpString+="</tr>\n";
9705 tmpString+=" <tr>\n <!-- span -->\n";
9706 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9707 if(htmlLevel>=2)
9708 tmpString+=" <th class=\"xAxis\">";
9709 else
9710 tmpString+=" <th>";
9711 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9712 }
9713 tmpString+=" </tr>\n";
9714 tmpString+=" </thead>\n";
9715 /*workaround
9716 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9717 */
9718 tmpString+=" <tbody>\n";
9719 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9720 tmpString+=" <tr>\n";
9721 if(htmlLevel>=2)
9722 tmpString+=" <th class=\"yAxis\">";
9723 else
9724 tmpString+=" <th>";
9725 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9726 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9727 QList<int> allActivities;
9728
9729 allActivities=activitiesForCurrentActivityTag[day][hour];
9730
9731 addActivitiesWithSameStartingTime(allActivities, hour);
9732 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
9733 }
9734 if(repeatNames){
9735 if(htmlLevel>=2)
9736 tmpString+=" <th class=\"yAxis\">";
9737 else
9738 tmpString+=" <th>";
9739 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9740 }
9741 tmpString+=" </tr>\n";
9742 }
9743 //workaround begin.
9744 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9745 if(repeatNames){
9746 tmpString+="<td></td>";
9747 }
9748 tmpString+="</tr>\n";
9749 //workaround end.
9750 tmpString+=" </tbody>\n";
9751 tmpString+=" </table>\n\n";
9752 return tmpString;
9753 }
9754
9755 //by Volker Dirr
singleActivityTagsTimetableDaysVerticalHtml(int htmlLevel,int activityTag,const QString & saveTime,bool printActivityTags,bool repeatNames)9756 QString TimetableExport::singleActivityTagsTimetableDaysVerticalHtml(int htmlLevel, int activityTag, const QString& saveTime, bool printActivityTags, bool repeatNames){
9757 assert(activityTag>=0);
9758 assert(activityTag<gt.rules.nInternalActivityTags);
9759 QString tmpString;
9760 ///////by Liviu Lalescu
9761 activitiesForCurrentActivityTag.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9762 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9763 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9764 activitiesForCurrentActivityTag[d][h].clear();
9765 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
9766 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9767 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9768 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9769 Activity* act=>.rules.internalActivitiesList[ai];
9770 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9771 activitiesForCurrentActivityTag[d][h+dd].append(ai);
9772 }
9773 ///////end Liviu Lalescu
9774 tmpString+=" <table id=\"table_"+hashActivityTagIDsTimetable.value(gt.rules.internalActivityTagsList[activityTag]->name);
9775 tmpString+="\" border=\"1\"";
9776 if(activityTag%2==0) tmpString+=" class=\"odd_table\"";
9777 else tmpString+=" class=\"even_table\"";
9778 tmpString+=">\n";
9779
9780 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9781
9782 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>";
9783 if(repeatNames){
9784 tmpString+="<td rowspan=\"2\"></td>";
9785 }
9786 tmpString+="</tr>\n";
9787 tmpString+=" <tr>\n <!-- span -->\n";
9788 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9789 if(htmlLevel>=2)
9790 tmpString+=" <th class=\"xAxis\">";
9791 else
9792 tmpString+=" <th>";
9793 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9794 }
9795 tmpString+=" </tr>\n";
9796 tmpString+=" </thead>\n";
9797 /*workaround
9798 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9799 */
9800 tmpString+=" <tbody>\n";
9801 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9802 tmpString+=" <tr>\n";
9803 if(htmlLevel>=2)
9804 tmpString+=" <th class=\"yAxis\">";
9805 else
9806 tmpString+=" <th>";
9807 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9808 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9809 QList<int> allActivities;
9810
9811 allActivities=activitiesForCurrentActivityTag[day][hour];
9812
9813 addActivitiesWithSameStartingTime(allActivities, hour);
9814 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
9815 }
9816 if(repeatNames){
9817 if(htmlLevel>=2)
9818 tmpString+=" <th class=\"yAxis\">";
9819 else
9820 tmpString+=" <th>";
9821 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
9822 }
9823 tmpString+=" </tr>\n";
9824 }
9825 //workaround begin.
9826 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9827 if(repeatNames){
9828 tmpString+="<td></td>";
9829 }
9830 tmpString+="</tr>\n";
9831 //workaround end.
9832 tmpString+=" </tbody>\n";
9833 tmpString+=" </table>\n\n";
9834 return tmpString;
9835 }
9836
9837
9838 //by Volker Dirr
singleActivityTagsTimetableTimeVerticalHtml(int htmlLevel,int maxActivityTag,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9839 QString TimetableExport::singleActivityTagsTimetableTimeVerticalHtml(int htmlLevel, int maxActivityTag, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9840 QString tmpString;
9841 tmpString+=" <table id=\"table\" border=\"1\">\n";
9842
9843 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9844
9845 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
9846 int currentCount=0;
9847 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
9848 if(gt.rules.internalActivityTagsList[activityTag]->printable){
9849 if(!excludedNames.contains(activityTag)){
9850 currentCount++;
9851 if(htmlLevel>=2)
9852 tmpString+=" <th class=\"xAxis\">";
9853 else
9854 tmpString+=" <th>";
9855 tmpString+=gt.rules.internalActivityTagsList[activityTag]->name+"</th>";
9856 }
9857 }
9858 }
9859 if(repeatNames){
9860 tmpString+="<td colspan=\"2\"></td>";
9861 }
9862 tmpString+="</tr>\n </thead>\n";
9863 /*workaround
9864 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9865 */
9866 tmpString+=" <tbody>\n";
9867
9868 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9869 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9870 tmpString+=" <tr>\n";
9871 if(hour==0)
9872 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9873 else tmpString+=" <!-- span -->\n";
9874 if(htmlLevel>=2)
9875 tmpString+=" <th class=\"yAxis\">";
9876 else
9877 tmpString+=" <th>";
9878 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9879
9880 currentCount=0;
9881 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
9882 if(gt.rules.internalActivityTagsList[activityTag]->printable){
9883 if(!excludedNames.contains(activityTag)){
9884 currentCount++;
9885 if(day+1==gt.rules.nDaysPerWeek && hour+1==gt.rules.nHoursPerDay)
9886 excludedNames<<activityTag;
9887 QList<int> allActivities;
9888 allActivities.clear();
9889
9890 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
9891 if(activitiesAtTime[day][hour].contains(ai)){
9892 assert(!allActivities.contains(ai));
9893 allActivities.append(ai);
9894 }
9895
9896 addActivitiesWithSameStartingTime(allActivities, hour);
9897 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
9898 }
9899 }
9900 }
9901 if(repeatNames){
9902 if(htmlLevel>=2)
9903 tmpString+=" <th class=\"yAxis\">";
9904 else
9905 tmpString+=" <th>";
9906 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9907 if(hour==0)
9908 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
9909 else tmpString+=" <!-- span -->\n";
9910 }
9911 tmpString+=" </tr>\n";
9912 }
9913 }
9914 //workaround begin.
9915 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
9916 if(repeatNames){
9917 tmpString+="<td colspan=\"2\"></td>";
9918 }
9919 tmpString+="</tr>\n";
9920 //workaround end.
9921 tmpString+=" </tbody>\n </table>\n";
9922 return tmpString;
9923 }
9924
9925 //by Volker Dirr
singleActivityTagsTimetableTimeHorizontalHtml(int htmlLevel,int maxActivityTag,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)9926 QString TimetableExport::singleActivityTagsTimetableTimeHorizontalHtml(int htmlLevel, int maxActivityTag, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
9927 QString tmpString;
9928 tmpString+=" <table id=\"table\" border=\"1\">\n";
9929
9930 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
9931
9932 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
9933
9934 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9935 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
9936 }
9937 if(repeatNames){
9938 tmpString+="<td rowspan=\"2\"></td>";
9939 }
9940 tmpString+="</tr>\n";
9941 tmpString+=" <tr>\n <!-- span -->\n";
9942 for(int day=0; day<gt.rules.nDaysPerWeek; day++)
9943 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9944 if(htmlLevel>=2)
9945 tmpString+=" <th class=\"xAxis\">";
9946 else
9947 tmpString+=" <th>";
9948 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
9949 }
9950 tmpString+=" </tr>\n";
9951 tmpString+=" </thead>\n";
9952 /*workaround
9953 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
9954 */
9955 tmpString+=" <tbody>\n";
9956 int currentCount=0;
9957 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
9958 if(gt.rules.internalActivityTagsList[activityTag]->printable){
9959 if(!excludedNames.contains(activityTag)){
9960 currentCount++;
9961 excludedNames<<activityTag;
9962 tmpString+=" <tr>\n";
9963 if(htmlLevel>=2)
9964 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
9965 else
9966 tmpString+=" <th>"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
9967
9968 ///////by Liviu Lalescu
9969 activitiesForCurrentActivityTag.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
9970 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9971 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9972 activitiesForCurrentActivityTag[d][h].clear();
9973 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
9974 if(best_solution.times[ai]!=UNALLOCATED_TIME){
9975 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
9976 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
9977 Activity* act=>.rules.internalActivitiesList[ai];
9978 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
9979 activitiesForCurrentActivityTag[d][h+dd].append(ai);
9980 }
9981 ///////end Liviu Lalescu
9982
9983 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
9984 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
9985 QList<int> allActivities;
9986
9987 allActivities=activitiesForCurrentActivityTag[day][hour];
9988
9989 addActivitiesWithSameStartingTime(allActivities, hour);
9990 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
9991 }
9992 }
9993 if(repeatNames){
9994 if(htmlLevel>=2)
9995 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
9996 else
9997 tmpString+=" <th>"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
9998 }
9999 tmpString+=" </tr>\n";
10000 }
10001 }
10002 }
10003 //workaround begin.
10004 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10005 if(repeatNames){
10006 tmpString+="<td></td>";
10007 }
10008 tmpString+="</tr>\n";
10009 //workaround end.
10010 tmpString+=" </tbody>\n </table>\n";
10011 return tmpString;
10012 }
10013
10014 //by Volker Dirr
singleActivityTagsTimetableTimeVerticalDailyHtml(int htmlLevel,int day,int maxActivityTag,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)10015 QString TimetableExport::singleActivityTagsTimetableTimeVerticalDailyHtml(int htmlLevel, int day, int maxActivityTag, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
10016 assert(day>=0);
10017 assert(day<gt.rules.nDaysPerWeek);
10018 QString tmpString;
10019 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
10020 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10021 tmpString+=" <thead>\n <tr><td colspan=\"2\"></td>";
10022 int currentCount=0;
10023 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
10024 if(gt.rules.internalActivityTagsList[activityTag]->printable){
10025 if(!excludedNames.contains(activityTag)){
10026 currentCount++;
10027
10028 if(htmlLevel>=2)
10029 tmpString+=" <th class=\"xAxis\">";
10030 else
10031 tmpString+=" <th>";
10032 tmpString+=gt.rules.internalActivityTagsList[activityTag]->name+"</th>";
10033 }
10034 }
10035 }
10036 if(repeatNames){
10037 tmpString+="<td colspan=\"2\"></td>";
10038 }
10039 tmpString+="</tr>\n </thead>\n";
10040 /*workaround
10041 tmpString+=" <tfoot><tr><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
10042 */
10043 tmpString+=" <tbody>\n";
10044 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10045 tmpString+=" <tr>\n";
10046 if(hour==0)
10047 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
10048 else tmpString+=" <!-- span -->\n";
10049 if(htmlLevel>=2)
10050 tmpString+=" <th class=\"yAxis\">";
10051 else
10052 tmpString+=" <th>";
10053 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10054
10055 currentCount=0;
10056 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
10057 if(gt.rules.internalActivityTagsList[activityTag]->printable){
10058 if(!excludedNames.contains(activityTag)){
10059 currentCount++;
10060 if(hour+1==gt.rules.nHoursPerDay)
10061 excludedNames<<activityTag;
10062 QList<int> allActivities;
10063 allActivities.clear();
10064
10065 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
10066 if(activitiesAtTime[day][hour].contains(ai)){
10067 assert(!allActivities.contains(ai));
10068 allActivities.append(ai);
10069 }
10070
10071 addActivitiesWithSameStartingTime(allActivities, hour);
10072 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
10073 }
10074 }
10075 }
10076 if(repeatNames){
10077 if(htmlLevel>=2)
10078 tmpString+=" <th class=\"yAxis\">";
10079 else
10080 tmpString+=" <th>";
10081 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10082 if(hour==0)
10083 tmpString+=" <th rowspan=\""+QString::number(gt.rules.nHoursPerDay)+ "\">"+protect2vert(gt.rules.daysOfTheWeek[day])+"</th>\n";
10084 else tmpString+=" <!-- span -->\n";
10085 }
10086 tmpString+=" </tr>\n";
10087 }
10088 //workaround begin.
10089 tmpString+=" <tr class=\"foot\"><td colspan=\"2\"></td><td colspan=\""+QString::number(currentCount)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10090 if(repeatNames){
10091 tmpString+="<td colspan=\"2\"></td>";
10092 }
10093 tmpString+="</tr>\n";
10094 //workaround end.
10095 tmpString+=" </tbody>\n";
10096 tmpString+=" </table>\n\n";
10097 return tmpString;
10098 }
10099
10100 //by Volker Dirr
singleActivityTagsTimetableTimeHorizontalDailyHtml(int htmlLevel,int day,int maxActivityTag,QSet<int> & excludedNames,const QString & saveTime,bool printActivityTags,bool repeatNames)10101 QString TimetableExport::singleActivityTagsTimetableTimeHorizontalDailyHtml(int htmlLevel, int day, int maxActivityTag, QSet<int>& excludedNames, const QString& saveTime, bool printActivityTags, bool repeatNames){
10102 assert(day>=0);
10103 assert(day<gt.rules.nDaysPerWeek);
10104 QString tmpString;
10105 tmpString+=" <table id=\"table_"+hashDayIDsTimetable.value(gt.rules.daysOfTheWeek[day])+"\" border=\"1\">\n";
10106 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10107 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td>";
10108
10109 tmpString+="<th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+protect2(gt.rules.daysOfTheWeek[day])+"</th>";
10110 if(repeatNames){
10111 tmpString+="<td rowspan=\"2\"></td>";
10112 }
10113 tmpString+="</tr>\n";
10114 tmpString+=" <tr>\n <!-- span -->\n";
10115 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10116 if(htmlLevel>=2)
10117 tmpString+=" <th class=\"xAxis\">";
10118 else
10119 tmpString+=" <th>";
10120 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10121 }
10122 tmpString+=" </tr>\n";
10123 tmpString+=" </thead>\n";
10124 /*workaround
10125 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
10126 */
10127 tmpString+=" <tbody>\n";
10128 int currentCount=0;
10129 for(int activityTag=0; activityTag<gt.rules.nInternalActivityTags && currentCount<maxActivityTag; activityTag++){
10130 if(gt.rules.internalActivityTagsList[activityTag]->printable){
10131 if(!excludedNames.contains(activityTag)){
10132 currentCount++;
10133 excludedNames<<activityTag;
10134 tmpString+=" <tr>\n";
10135 if(htmlLevel>=2)
10136 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
10137 else
10138 tmpString+=" <th>"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
10139
10140 ///////by Liviu Lalescu
10141 activitiesForCurrentActivityTag.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
10142 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
10143 for(int h=0; h<gt.rules.nHoursPerDay; h++)
10144 activitiesForCurrentActivityTag[d][h].clear();
10145 for(int ai : qAsConst(gt.rules.activitiesForActivityTagList[activityTag]))
10146 if(best_solution.times[ai]!=UNALLOCATED_TIME){
10147 int d=best_solution.times[ai]%gt.rules.nDaysPerWeek;
10148 int h=best_solution.times[ai]/gt.rules.nDaysPerWeek;
10149 Activity* act=>.rules.internalActivitiesList[ai];
10150 for(int dd=0; dd < act->duration && h+dd < gt.rules.nHoursPerDay; dd++)
10151 activitiesForCurrentActivityTag[d][h+dd].append(ai);
10152 }
10153 ///////end Liviu Lalescu
10154
10155 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10156 QList<int> allActivities;
10157
10158 allActivities=activitiesForCurrentActivityTag[day][hour];
10159
10160 addActivitiesWithSameStartingTime(allActivities, hour);
10161 tmpString+=writeActivitiesActivityTags(htmlLevel, allActivities, printActivityTags);
10162 }
10163 if(repeatNames){
10164 if(htmlLevel>=2)
10165 tmpString+=" <th class=\"yAxis\">"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
10166 else
10167 tmpString+=" <th>"+protect2(gt.rules.internalActivityTagsList[activityTag]->name)+"</th>\n";
10168 }
10169 tmpString+=" </tr>\n";
10170 }
10171 }
10172 }
10173 //workaround begin.
10174 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10175 if(repeatNames){
10176 tmpString+="<td></td>";
10177 }
10178 tmpString+="</tr>\n";
10179 //workaround end.
10180 tmpString+=" </tbody>\n";
10181 tmpString+=" </table>\n\n";
10182 return tmpString;
10183 }
10184
10185 //by Volker Dirr
singleTeachersFreePeriodsTimetableDaysHorizontalHtml(int htmlLevel,const QString & saveTime,bool detailed,bool repeatNames)10186 QString TimetableExport::singleTeachersFreePeriodsTimetableDaysHorizontalHtml(int htmlLevel, const QString& saveTime, bool detailed, bool repeatNames){
10187 QString tmpString;
10188 tmpString+=" <table id=\"table\" border=\"1\">\n";
10189
10190 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10191
10192 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Teachers' Free Periods")+"</th>";
10193 if(repeatNames){
10194 tmpString+="<td rowspan=\"2\"></td>";
10195 }
10196 tmpString+="</tr>\n";
10197 tmpString+=" <tr>\n <!-- span -->\n";
10198 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
10199 if(htmlLevel>=2)
10200 tmpString+=" <th class=\"xAxis\">";
10201 else
10202 tmpString+=" <th>";
10203 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
10204 }
10205 tmpString+=" </tr>\n";
10206 tmpString+=" </thead>\n";
10207 /*workaround
10208 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nDaysPerWeek+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
10209 */
10210 tmpString+=" <tbody>\n";
10211 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10212 tmpString+=" <tr>\n";
10213 if(htmlLevel>=2)
10214 tmpString+=" <th class=\"yAxis\">";
10215 else
10216 tmpString+=" <th>";
10217 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10218 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
10219 bool empty_slot;
10220 empty_slot=true;
10221 for(int tfp=0; tfp<TEACHERS_FREE_PERIODS_N_CATEGORIES; tfp++){
10222 if(teachers_free_periods_timetable_weekly[tfp][day][hour].size()>0){
10223 empty_slot=false;
10224 }
10225 if(!detailed&&tfp>=TEACHER_MUST_COME_EARLIER) break;
10226 }
10227 if(!empty_slot) tmpString+=" <td>";
10228 for(int tfp=0; tfp<TEACHERS_FREE_PERIODS_N_CATEGORIES; tfp++){
10229 if(teachers_free_periods_timetable_weekly[tfp][day][hour].size()>0){
10230 if(htmlLevel>=2)
10231 tmpString+="<div class=\"DESCRIPTION\">";
10232 switch(tfp){
10233 case TEACHER_HAS_SINGLE_GAP : tmpString+=TimetableExport::tr("Single gap"); break;
10234 case TEACHER_HAS_BORDER_GAP : tmpString+=TimetableExport::tr("Border gap"); break;
10235 case TEACHER_HAS_BIG_GAP : tmpString+=TimetableExport::tr("Big gap"); break;
10236 case TEACHER_MUST_COME_EARLIER : tmpString+=TimetableExport::tr("Must come earlier"); break;
10237 case TEACHER_MUST_STAY_LONGER : tmpString+=TimetableExport::tr("Must stay longer"); break;
10238 case TEACHER_MUST_COME_MUCH_EARLIER : tmpString+=TimetableExport::tr("Must come much earlier"); break;
10239 case TEACHER_MUST_STAY_MUCH_LONGER : tmpString+=TimetableExport::tr("Must stay much longer"); break;
10240 case TEACHER_HAS_A_FREE_DAY : tmpString+=TimetableExport::tr("Free day"); break;
10241 case TEACHER_IS_NOT_AVAILABLE : tmpString+=TimetableExport::tr("Not available", "It refers to a teacher"); break;
10242 default: assert(0==1); break;
10243 }
10244 if(htmlLevel>=2)
10245 tmpString+=":</div>";
10246 else tmpString+=":<br />";
10247 if(htmlLevel>=3)
10248 switch(tfp){
10249 case TEACHER_HAS_SINGLE_GAP : tmpString+="<div class=\"TEACHER_HAS_SINGLE_GAP\">"; break;
10250 case TEACHER_HAS_BORDER_GAP : tmpString+="<div class=\"TEACHER_HAS_BORDER_GAP\">"; break;
10251 case TEACHER_HAS_BIG_GAP : tmpString+="<div class=\"TEACHER_HAS_BIG_GAP\">"; break;
10252 case TEACHER_MUST_COME_EARLIER : tmpString+="<div class=\"TEACHER_MUST_COME_EARLIER\">"; break;
10253 case TEACHER_MUST_STAY_LONGER : tmpString+="<div class=\"TEACHER_MUST_STAY_LONGER\">"; break;
10254 case TEACHER_MUST_COME_MUCH_EARLIER : tmpString+="<div class=\"TEACHER_MUST_COME_MUCH_EARLIER\">"; break;
10255 case TEACHER_MUST_STAY_MUCH_LONGER : tmpString+="<div class=\"TEACHER_MUST_STAY_MUCH_LONGER\">"; break;
10256 case TEACHER_HAS_A_FREE_DAY : tmpString+="<div class=\"TEACHER_HAS_A_FREE_DAY\">"; break;
10257 case TEACHER_IS_NOT_AVAILABLE : tmpString+="<div class=\"TEACHER_IS_NOT_AVAILABLE\">"; break;
10258 default: assert(0==1); break;
10259 }
10260 for(int t=0; t<teachers_free_periods_timetable_weekly[tfp][day][hour].size(); t++){
10261 QString teacher_name = gt.rules.internalTeachersList[teachers_free_periods_timetable_weekly[tfp][day][hour].at(t)]->name;
10262 switch(htmlLevel){
10263 case 4 : tmpString+="<span class=\"t_"+hashTeacherIDsTimetable.value(teacher_name)+"\">"+protect2(teacher_name)+"</span>"; break;
10264 case 5 : ;
10265 case 6 : tmpString+="<span class=\"t_"+hashTeacherIDsTimetable.value(teacher_name)+"\" onmouseover=\"highlight('t_"+hashTeacherIDsTimetable.value(teacher_name)+"')\">"+protect2(teacher_name)+"</span>"; break;
10266 default: tmpString+=protect2(teacher_name); break;
10267 }
10268 tmpString+="<br />";
10269 }
10270 if(htmlLevel>=3)
10271 tmpString+="</div>";
10272 }
10273 if(!detailed&&tfp>=TEACHER_MUST_COME_EARLIER) break;
10274 }
10275 if(!empty_slot){
10276 tmpString+="</td>\n";
10277 } else {
10278 tmpString+=writeEmpty(htmlLevel);
10279 }
10280 }
10281 if(repeatNames){
10282 if(htmlLevel>=2)
10283 tmpString+=" <th class=\"yAxis\">";
10284 else
10285 tmpString+=" <th>";
10286 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10287 }
10288 tmpString+=" </tr>\n";
10289 }
10290 //workaround begin.
10291 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nDaysPerWeek)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10292 if(repeatNames){
10293 tmpString+="<td></td>";
10294 }
10295 tmpString+="</tr>\n";
10296 //workaround end.
10297 tmpString+=" </tbody>\n";
10298 tmpString+=" </table>\n\n";
10299 return tmpString;
10300 }
10301
10302 //by Volker Dirr
singleTeachersFreePeriodsTimetableDaysVerticalHtml(int htmlLevel,const QString & saveTime,bool detailed,bool repeatNames)10303 QString TimetableExport::singleTeachersFreePeriodsTimetableDaysVerticalHtml(int htmlLevel, const QString& saveTime, bool detailed, bool repeatNames){
10304 QString tmpString;
10305
10306 tmpString+=" <table id=\"table\" border=\"1\">\n";
10307
10308 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10309
10310 tmpString+=" <thead>\n <tr><td rowspan=\"2\"></td><th colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Teachers' Free Periods")+"</th>";
10311 if(repeatNames){
10312 tmpString+="<td rowspan=\"2\"></td>";
10313 }
10314 tmpString+="</tr>\n";
10315
10316 tmpString+=" <tr>\n <!-- span -->\n";
10317 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10318 if(htmlLevel>=2)
10319 tmpString+=" <th class=\"xAxis\">";
10320 else
10321 tmpString+=" <th>";
10322 tmpString+=protect2(gt.rules.hoursOfTheDay[hour])+"</th>\n";
10323 }
10324 tmpString+=" </tr>\n";
10325 tmpString+=" </thead>\n";
10326 /*workaround
10327 tmpString+=" <tfoot><tr><td></td><td colspan=\""+gt.rules.nHoursPerDay+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr></tfoot>\n";
10328 */
10329 tmpString+=" <tbody>\n";
10330 for(int day=0; day<gt.rules.nDaysPerWeek; day++){
10331 tmpString+=" <tr>\n";
10332 if(htmlLevel>=2)
10333 tmpString+=" <th class=\"yAxis\">";
10334 else
10335 tmpString+=" <th>";
10336 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
10337 for(int hour=0; hour<gt.rules.nHoursPerDay; hour++){
10338 bool empty_slot;
10339 empty_slot=true;
10340 for(int tfp=0; tfp<TEACHERS_FREE_PERIODS_N_CATEGORIES; tfp++){
10341 if(teachers_free_periods_timetable_weekly[tfp][day][hour].size()>0){
10342 empty_slot=false;
10343 }
10344 if(!detailed&&tfp>=TEACHER_MUST_COME_EARLIER) break;
10345 }
10346 if(!empty_slot) tmpString+=" <td>";
10347 for(int tfp=0; tfp<TEACHERS_FREE_PERIODS_N_CATEGORIES; tfp++){
10348 if(teachers_free_periods_timetable_weekly[tfp][day][hour].size()>0){
10349 if(htmlLevel>=2)
10350 tmpString+="<div class=\"DESCRIPTION\">";
10351 switch(tfp){
10352 case TEACHER_HAS_SINGLE_GAP : tmpString+=TimetableExport::tr("Single gap"); break;
10353 case TEACHER_HAS_BORDER_GAP : tmpString+=TimetableExport::tr("Border gap"); break;
10354 case TEACHER_HAS_BIG_GAP : tmpString+=TimetableExport::tr("Big gap"); break;
10355 case TEACHER_MUST_COME_EARLIER : tmpString+=TimetableExport::tr("Must come earlier"); break;
10356 case TEACHER_MUST_STAY_LONGER : tmpString+=TimetableExport::tr("Must stay longer"); break;
10357 case TEACHER_MUST_COME_MUCH_EARLIER : tmpString+=TimetableExport::tr("Must come much earlier"); break;
10358 case TEACHER_MUST_STAY_MUCH_LONGER : tmpString+=TimetableExport::tr("Must stay much longer"); break;
10359 case TEACHER_HAS_A_FREE_DAY : tmpString+=TimetableExport::tr("Free day"); break;
10360 case TEACHER_IS_NOT_AVAILABLE : tmpString+=TimetableExport::tr("Not available"); break;
10361 default: assert(0==1); break;
10362 }
10363 if(htmlLevel>=2)
10364 tmpString+=":</div>";
10365 else tmpString+=":<br />";
10366 if(htmlLevel>=3)
10367 switch(tfp){
10368 case TEACHER_HAS_SINGLE_GAP : tmpString+="<div class=\"TEACHER_HAS_SINGLE_GAP\">"; break;
10369 case TEACHER_HAS_BORDER_GAP : tmpString+="<div class=\"TEACHER_HAS_BORDER_GAP\">"; break;
10370 case TEACHER_HAS_BIG_GAP : tmpString+="<div class=\"TEACHER_HAS_BIG_GAP\">"; break;
10371 case TEACHER_MUST_COME_EARLIER : tmpString+="<div class=\"TEACHER_MUST_COME_EARLIER\">"; break;
10372 case TEACHER_MUST_STAY_LONGER : tmpString+="<div class=\"TEACHER_MUST_STAY_LONGER\">"; break;
10373 case TEACHER_MUST_COME_MUCH_EARLIER : tmpString+="<div class=\"TEACHER_MUST_COME_MUCH_EARLIER\">"; break;
10374 case TEACHER_MUST_STAY_MUCH_LONGER : tmpString+="<div class=\"TEACHER_MUST_STAY_MUCH_LONGER\">"; break;
10375 case TEACHER_HAS_A_FREE_DAY : tmpString+="<div class=\"TEACHER_HAS_A_FREE_DAY\">"; break;
10376 case TEACHER_IS_NOT_AVAILABLE : tmpString+="<div class=\"TEACHER_IS_NOT_AVAILABLE\">"; break;
10377 default: assert(0==1); break;
10378 }
10379 for(int t=0; t<teachers_free_periods_timetable_weekly[tfp][day][hour].size(); t++){
10380 QString teacher_name = gt.rules.internalTeachersList[teachers_free_periods_timetable_weekly[tfp][day][hour].at(t)]->name;
10381 switch(htmlLevel){
10382 case 4 : tmpString+="<span class=\"t_"+hashTeacherIDsTimetable.value(teacher_name)+"\">"+protect2(teacher_name)+"</span>"; break;
10383 case 5 : ;
10384 case 6 : tmpString+="<span class=\"t_"+hashTeacherIDsTimetable.value(teacher_name)+"\" onmouseover=\"highlight('t_"+hashTeacherIDsTimetable.value(teacher_name)+"')\">"+protect2(teacher_name)+"</span>"; break;
10385 default: tmpString+=protect2(teacher_name); break;
10386 }
10387 tmpString+="<br />";
10388 }
10389 if(htmlLevel>=3)
10390 tmpString+="</div>";
10391 }
10392 if(!detailed&&tfp>=TEACHER_MUST_COME_EARLIER) break;
10393 }
10394 if(!empty_slot){
10395 tmpString+="</td>\n";
10396 } else
10397 tmpString+=writeEmpty(htmlLevel);
10398 }
10399 if(repeatNames){
10400 if(htmlLevel>=2)
10401 tmpString+=" <th class=\"yAxis\">";
10402 else
10403 tmpString+=" <th>";
10404 tmpString+=protect2(gt.rules.daysOfTheWeek[day])+"</th>\n";
10405 }
10406 tmpString+=" </tr>\n";
10407 }
10408 //workaround begin.
10409 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(gt.rules.nHoursPerDay)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10410 if(repeatNames){
10411 tmpString+="<td></td>";
10412 }
10413 tmpString+="</tr>\n";
10414 //workaround end.
10415 tmpString+=" </tbody>\n";
10416 tmpString+=" </table>\n\n";
10417 return tmpString;
10418 }
10419
10420 //by Volker Dirr
singleTeachersStatisticsHtml(int htmlLevel,const QString & saveTime,bool detailed,bool repeatNames,bool printAll)10421 QString TimetableExport::singleTeachersStatisticsHtml(int htmlLevel, const QString& saveTime, bool detailed, bool repeatNames, bool printAll){
10422 Q_UNUSED(htmlLevel);
10423 QString tmpString;
10424 if(!printAll){
10425 tmpString+=" <p>\n";
10426 tmpString+=" <strong>"+tr("This is a teaser only. Values are not correct!")+"</strong>\n";
10427 tmpString+=" </p>\n";
10428 }
10429 tmpString+=" <p>\n";
10430 tmpString+=" "+tr("This file doesn't list limits that are set by constraints. It contains statistics about the min and max values of the currently calculated solution.")+"\n";
10431 tmpString+=" </p>\n";
10432
10433 QString teachersString="";
10434 int freeDaysAllTeachers=0;
10435 int minFreeDaysAllTeachers=gt.rules.nDaysPerWeek;
10436 int maxFreeDaysAllTeachers=0;
10437 int gapsAllTeachers=0;
10438 int minGapsPerDayAllTeachers=gt.rules.nHoursPerDay;
10439 int maxGapsPerDayAllTeachers=0;
10440 int minGapsPerWeekAllTeachers=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10441 int maxGapsPerWeekAllTeachers=0;
10442 int minHoursPerDayAllTeachers=gt.rules.nHoursPerDay;
10443 int maxHoursPerDayAllTeachers=0;
10444 int minHoursPerWeekAllTeachers=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10445 int maxHoursPerWeekAllTeachers=0;
10446 int totalNumberOfHours=0;
10447 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
10448 int freeDaysSingleTeacher=0;
10449 int gapsSingleTeacher=0;
10450 int minGapsPerDaySingleTeacher=gt.rules.nHoursPerDay;
10451 int maxGapsPerDaySingleTeacher=0;
10452 int minHoursPerDaySingleTeacher=gt.rules.nHoursPerDay;
10453 int maxHoursPerDaySingleTeacher=0;
10454 int hoursPerWeekSingleTeacher=0;
10455 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
10456 int firstPeriod=-1;
10457 int lastPeriod=-1;
10458 int gapsPerDaySingleTeacher=0;
10459 int hoursPerDaySingleTeacher=0;
10460 for(int h=0; h<gt.rules.nHoursPerDay; h++){
10461 if(teachers_timetable_weekly[tch][d][h]!=UNALLOCATED_ACTIVITY){
10462 if(firstPeriod==-1)
10463 firstPeriod=h;
10464 lastPeriod=h;
10465 hoursPerDaySingleTeacher++;
10466 }
10467 }
10468 if(firstPeriod==-1){
10469 freeDaysSingleTeacher++;
10470 } else {
10471 for(int h=firstPeriod; h<lastPeriod; h++){
10472 if(teachers_timetable_weekly[tch][d][h]==UNALLOCATED_ACTIVITY && teacherNotAvailableDayHour[tch][d][h]==false && breakDayHour[d][h]==false){
10473 gapsPerDaySingleTeacher++;
10474 }
10475 }
10476 }
10477 gapsSingleTeacher+=gapsPerDaySingleTeacher;
10478 if(minGapsPerDaySingleTeacher>gapsPerDaySingleTeacher)
10479 minGapsPerDaySingleTeacher=gapsPerDaySingleTeacher;
10480 if(maxGapsPerDaySingleTeacher<gapsPerDaySingleTeacher)
10481 maxGapsPerDaySingleTeacher=gapsPerDaySingleTeacher;
10482 if(hoursPerDaySingleTeacher>0){
10483 if(minHoursPerDaySingleTeacher>hoursPerDaySingleTeacher)
10484 minHoursPerDaySingleTeacher=hoursPerDaySingleTeacher;
10485 if(maxHoursPerDaySingleTeacher<hoursPerDaySingleTeacher)
10486 maxHoursPerDaySingleTeacher=hoursPerDaySingleTeacher;
10487 }
10488 hoursPerWeekSingleTeacher+=hoursPerDaySingleTeacher;
10489 }
10490 totalNumberOfHours+=hoursPerWeekSingleTeacher;
10491 if(minHoursPerWeekAllTeachers>hoursPerWeekSingleTeacher)
10492 minHoursPerWeekAllTeachers=hoursPerWeekSingleTeacher;
10493 if(maxHoursPerWeekAllTeachers<hoursPerWeekSingleTeacher)
10494 maxHoursPerWeekAllTeachers=hoursPerWeekSingleTeacher;
10495
10496 if(minFreeDaysAllTeachers>freeDaysSingleTeacher)
10497 minFreeDaysAllTeachers=freeDaysSingleTeacher;
10498 if(maxFreeDaysAllTeachers<freeDaysSingleTeacher)
10499 maxFreeDaysAllTeachers=freeDaysSingleTeacher;
10500
10501 if(minGapsPerDayAllTeachers>minGapsPerDaySingleTeacher)
10502 minGapsPerDayAllTeachers=minGapsPerDaySingleTeacher;
10503 if(maxGapsPerDayAllTeachers<maxGapsPerDaySingleTeacher)
10504 maxGapsPerDayAllTeachers=maxGapsPerDaySingleTeacher;
10505
10506 if(minGapsPerWeekAllTeachers>gapsSingleTeacher)
10507 minGapsPerWeekAllTeachers=gapsSingleTeacher;
10508 if(maxGapsPerWeekAllTeachers<gapsSingleTeacher)
10509 maxGapsPerWeekAllTeachers=gapsSingleTeacher;
10510
10511 if(minHoursPerDayAllTeachers>minHoursPerDaySingleTeacher)
10512 minHoursPerDayAllTeachers=minHoursPerDaySingleTeacher;
10513 if(maxHoursPerDayAllTeachers<maxHoursPerDaySingleTeacher)
10514 maxHoursPerDayAllTeachers=maxHoursPerDaySingleTeacher;
10515
10516 gapsAllTeachers+=gapsSingleTeacher;
10517 freeDaysAllTeachers+=freeDaysSingleTeacher;
10518
10519 if(detailed){
10520 if(freeDaysSingleTeacher==gt.rules.nDaysPerWeek)
10521 minHoursPerDaySingleTeacher=0;
10522 teachersString+=" <tr><th>"+protect2(gt.rules.internalTeachersList[tch]->name)
10523 +"</th><td>"+QString::number(hoursPerWeekSingleTeacher)
10524 +"</td><td>"+QString::number(freeDaysSingleTeacher)
10525 +"</td><td>"+QString::number(gapsSingleTeacher)
10526 +"</td><td>"+QString::number(minGapsPerDaySingleTeacher)
10527 +"</td><td>"+QString::number(maxGapsPerDaySingleTeacher)
10528 +"</td><td>"+QString::number(minHoursPerDaySingleTeacher)
10529 +"</td><td>"+QString::number(maxHoursPerDaySingleTeacher)
10530 +"</td>";
10531
10532 if(repeatNames){
10533 teachersString+="<th>"+protect2(gt.rules.internalTeachersList[tch]->name)+"</th>";
10534 }
10535 teachersString+="</tr>\n";
10536 }
10537 if(!printAll && tch>10){
10538 break;
10539 }
10540 }
10541
10542 tmpString+=" <table border=\"1\">\n";
10543 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10544 tmpString+=" <thead>\n";
10545 tmpString+=" <tr><th>"+tr("All teachers")
10546 +"</th><th>"+tr("Hours per week")
10547 +"</th><th>"+tr("Free days")
10548 +"</th><th>"+tr("Gaps")
10549 +"</th><th>"+tr("Gaps per day")
10550 +"</th><th>"+tr("Hours per day")
10551 +"</th></tr>\n";
10552 tmpString+=" </thead>\n";
10553 tmpString+=" <tr><th>"+tr("Sum")+"</th>";
10554 tmpString+="<td>"+QString::number(totalNumberOfHours)+"</td>";
10555 tmpString+="<td>"+QString::number(freeDaysAllTeachers)+"</td>";
10556 tmpString+="<td>"+QString::number(gapsAllTeachers)+"</td>";
10557 tmpString+="<td>---</td>";
10558 tmpString+="<td>---</td>";
10559 tmpString+="</tr>\n";
10560 tmpString+=" <tr><th>"+tr("Average")+"</th>";
10561 tmpString+="<td>"+QString::number(double(totalNumberOfHours)/gt.rules.nInternalTeachers,'f',2)+"</td>";
10562 tmpString+="<td>"+QString::number(double(freeDaysAllTeachers)/gt.rules.nInternalTeachers,'f',2)+"</td>";
10563 tmpString+="<td>"+QString::number(double(gapsAllTeachers)/gt.rules.nInternalTeachers,'f',2)+"</td>";
10564 tmpString+="<td>---</td>";
10565 tmpString+="<td>---</td>";
10566 tmpString+="</tr>\n";
10567 tmpString+=" <tr><th>"+tr("Min")+"</th>";
10568 tmpString+="<td>"+QString::number(minHoursPerWeekAllTeachers)+"</td>";
10569 tmpString+="<td>"+QString::number(minFreeDaysAllTeachers)+"</td>";
10570 tmpString+="<td>"+QString::number(minGapsPerWeekAllTeachers)+"</td>";
10571 tmpString+="<td>"+QString::number(minGapsPerDayAllTeachers)+"</td>";
10572 tmpString+="<td>"+QString::number(minHoursPerDayAllTeachers)+"</td>";
10573 tmpString+="</tr>\n";
10574 tmpString+=" <tr><th>"+tr("Max")+"</th>";
10575 tmpString+="<td>"+QString::number(maxHoursPerWeekAllTeachers)+"</td>";
10576 tmpString+="<td>"+QString::number(maxFreeDaysAllTeachers)+"</td>";
10577 tmpString+="<td>"+QString::number(maxGapsPerWeekAllTeachers)+"</td>";
10578 tmpString+="<td>"+QString::number(maxGapsPerDayAllTeachers)+"</td>";
10579 tmpString+="<td>"+QString::number(maxHoursPerDayAllTeachers)+"</td>";
10580 tmpString+="</tr>\n";
10581 //workaround begin.
10582 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(5)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr>\n";
10583 //workaround end.
10584 tmpString+=" </table>\n";
10585
10586 if(detailed){
10587 tmpString+=" <p class=\"back0\"><br /></p>\n\n";
10588
10589 tmpString+=" <table border=\"1\">\n";
10590 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10591 tmpString+=" <thead>\n";
10592 tmpString+=" <tr><th>"+tr("Teacher")
10593 +"</th><th>"+tr("Hours per week")
10594 +"</th><th>"+tr("Free days")
10595 +"</th><th>"+tr("Total gaps")
10596 +"</th><th>"+tr("Min gaps per day")
10597 +"</th><th>"+tr("Max gaps per day")
10598 +"</th><th>"+tr("Min hours per day")
10599 +"</th><th>"+tr("Max hours per day")
10600 +"</th>";
10601 if(repeatNames){
10602 tmpString+="<th>"+tr("Teacher")+"</th>";
10603 }
10604 tmpString+="</tr>\n";
10605 tmpString+=" </thead>\n";
10606 tmpString+=teachersString;
10607 //workaround begin.
10608 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(7)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10609 if(repeatNames){
10610 tmpString+="<td></td>";
10611 }
10612 tmpString+="</tr>\n";
10613 //workaround end.
10614 tmpString+=" </table>\n";
10615 }
10616 return tmpString;
10617 }
10618
10619 //by Volker Dirr
singleStudentsStatisticsHtml(int htmlLevel,const QString & saveTime,bool detailed,bool repeatNames,bool printAll)10620 QString TimetableExport::singleStudentsStatisticsHtml(int htmlLevel, const QString& saveTime, bool detailed, bool repeatNames, bool printAll){
10621 Q_UNUSED(htmlLevel);
10622 QString tmpString;
10623 if(!printAll){
10624 tmpString+=" <p>\n";
10625 tmpString+=" <strong>"+tr("This is a teaser only. Values are not correct!")+"</strong>\n";
10626 tmpString+=" </p>\n";
10627 }
10628 tmpString+=" <p>\n";
10629 tmpString+=" "+tr("This file doesn't list limits that are set by constraints. It contains statistics about the min and max values of the currently calculated solution.")+"\n";
10630 tmpString+=" </p>\n";
10631
10632 //subgroups statistics (start)
10633 QString subgroupsString="";
10634 int freeDaysAllSubgroups=0;
10635 int minFreeDaysAllSubgroups=gt.rules.nDaysPerWeek;
10636 int maxFreeDaysAllSubgroups=0;
10637 int gapsAllSubgroups=0;
10638 int minGapsPerDayAllSubgroups=gt.rules.nHoursPerDay;
10639 int maxGapsPerDayAllSubgroups=0;
10640 int minGapsPerWeekAllSubgroups=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10641 int maxGapsPerWeekAllSubgroups=0;
10642 int minHoursPerDayAllSubgroups=gt.rules.nHoursPerDay;
10643 int maxHoursPerDayAllSubgroups=0;
10644 int minHoursPerWeekAllSubgroups=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10645 int maxHoursPerWeekAllSubgroups=0;
10646 int totalNumberOfHours=0;
10647 QList<int> freeDaysPerWeekSubgroupList;
10648 QList<int> gapsPerWeekSubgroupList;
10649 QList<int> minGapsPerDaySubgroupList;
10650 QList<int> maxGapsPerDaySubgroupList;
10651 QList<int> minHoursPerDaySubgroupList;
10652 QList<int> maxHoursPerDaySubgroupList;
10653 QList<int> hoursPerWeekSubgroupList;
10654 for(int subgroup=0; subgroup<gt.rules.nInternalSubgroups; subgroup++){
10655 int freeDaysSingleSubgroup=0;
10656 int gapsSingleSubgroup=0;
10657 int minGapsPerDaySingleSubgroup=gt.rules.nHoursPerDay;
10658 int maxGapsPerDaySingleSubgroup=0;
10659 int minHoursPerDaySingleSubgroup=gt.rules.nHoursPerDay;
10660 int maxHoursPerDaySingleSubgroup=0;
10661 int hoursPerWeekSingleSubgroup=0;
10662 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
10663 int firstPeriod=-1;
10664 int lastPeriod=-1;
10665 int gapsPerDaySingleSubgroup=0;
10666 int hoursPerDaySingleSubgroup=0;
10667 for(int h=0; h<gt.rules.nHoursPerDay; h++){
10668 if(students_timetable_weekly[subgroup][d][h]!=UNALLOCATED_ACTIVITY){
10669 if(firstPeriod==-1)
10670 firstPeriod=h;
10671 lastPeriod=h;
10672 hoursPerDaySingleSubgroup++;
10673 }
10674 }
10675 if(firstPeriod==-1){
10676 freeDaysSingleSubgroup++;
10677 } else {
10678 for(int h=firstPeriod; h<lastPeriod; h++){
10679 if(students_timetable_weekly[subgroup][d][h]==UNALLOCATED_ACTIVITY && subgroupNotAvailableDayHour[subgroup][d][h]==false && breakDayHour[d][h]==false){
10680 gapsPerDaySingleSubgroup++;
10681 }
10682 }
10683 }
10684 gapsSingleSubgroup+=gapsPerDaySingleSubgroup;
10685 if(minGapsPerDaySingleSubgroup>gapsPerDaySingleSubgroup)
10686 minGapsPerDaySingleSubgroup=gapsPerDaySingleSubgroup;
10687 if(maxGapsPerDaySingleSubgroup<gapsPerDaySingleSubgroup)
10688 maxGapsPerDaySingleSubgroup=gapsPerDaySingleSubgroup;
10689 if(hoursPerDaySingleSubgroup>0){
10690 if(minHoursPerDaySingleSubgroup>hoursPerDaySingleSubgroup)
10691 minHoursPerDaySingleSubgroup=hoursPerDaySingleSubgroup;
10692 if(maxHoursPerDaySingleSubgroup<hoursPerDaySingleSubgroup)
10693 maxHoursPerDaySingleSubgroup=hoursPerDaySingleSubgroup;
10694 }
10695 hoursPerWeekSingleSubgroup+=hoursPerDaySingleSubgroup;
10696 }
10697 totalNumberOfHours+=hoursPerWeekSingleSubgroup;
10698 if(minHoursPerWeekAllSubgroups>hoursPerWeekSingleSubgroup)
10699 minHoursPerWeekAllSubgroups=hoursPerWeekSingleSubgroup;
10700 if(maxHoursPerWeekAllSubgroups<hoursPerWeekSingleSubgroup)
10701 maxHoursPerWeekAllSubgroups=hoursPerWeekSingleSubgroup;
10702
10703 if(minFreeDaysAllSubgroups>freeDaysSingleSubgroup)
10704 minFreeDaysAllSubgroups=freeDaysSingleSubgroup;
10705 if(maxFreeDaysAllSubgroups<freeDaysSingleSubgroup)
10706 maxFreeDaysAllSubgroups=freeDaysSingleSubgroup;
10707
10708 if(minGapsPerDayAllSubgroups>minGapsPerDaySingleSubgroup)
10709 minGapsPerDayAllSubgroups=minGapsPerDaySingleSubgroup;
10710 if(maxGapsPerDayAllSubgroups<maxGapsPerDaySingleSubgroup)
10711 maxGapsPerDayAllSubgroups=maxGapsPerDaySingleSubgroup;
10712
10713 if(minGapsPerWeekAllSubgroups>gapsSingleSubgroup)
10714 minGapsPerWeekAllSubgroups=gapsSingleSubgroup;
10715 if(maxGapsPerWeekAllSubgroups<gapsSingleSubgroup)
10716 maxGapsPerWeekAllSubgroups=gapsSingleSubgroup;
10717
10718 if(minHoursPerDayAllSubgroups>minHoursPerDaySingleSubgroup)
10719 minHoursPerDayAllSubgroups=minHoursPerDaySingleSubgroup;
10720 if(maxHoursPerDayAllSubgroups<maxHoursPerDaySingleSubgroup)
10721 maxHoursPerDayAllSubgroups=maxHoursPerDaySingleSubgroup;
10722
10723 gapsAllSubgroups+=gapsSingleSubgroup;
10724 freeDaysAllSubgroups+=freeDaysSingleSubgroup;
10725
10726 if(freeDaysSingleSubgroup==gt.rules.nDaysPerWeek)
10727 minHoursPerDaySingleSubgroup=0;
10728 if(detailed){
10729 subgroupsString+=" <tr><th>"+protect2(gt.rules.internalSubgroupsList[subgroup]->name)
10730 +"</th><td>"+QString::number(hoursPerWeekSingleSubgroup)
10731 +"</td><td>"+QString::number(freeDaysSingleSubgroup)
10732 +"</td><td>"+QString::number(gapsSingleSubgroup)
10733 +"</td><td>"+QString::number(minGapsPerDaySingleSubgroup)
10734 +"</td><td>"+QString::number(maxGapsPerDaySingleSubgroup)
10735 +"</td><td>"+QString::number(minHoursPerDaySingleSubgroup)
10736 +"</td><td>"+QString::number(maxHoursPerDaySingleSubgroup)
10737 +"</td>";
10738 if(repeatNames){
10739 subgroupsString+="<th>"+protect2(gt.rules.internalSubgroupsList[subgroup]->name)+"</th>";
10740 }
10741 subgroupsString+="</tr>\n";
10742 hoursPerWeekSubgroupList<<hoursPerWeekSingleSubgroup;
10743 freeDaysPerWeekSubgroupList<<freeDaysSingleSubgroup;
10744 gapsPerWeekSubgroupList<<gapsSingleSubgroup;
10745 minGapsPerDaySubgroupList<<minGapsPerDaySingleSubgroup;
10746 maxGapsPerDaySubgroupList<<maxGapsPerDaySingleSubgroup;
10747 minHoursPerDaySubgroupList<<minHoursPerDaySingleSubgroup;
10748 maxHoursPerDaySubgroupList<<maxHoursPerDaySingleSubgroup;
10749 }
10750 if(!printAll && subgroup>10){
10751 break;
10752 }
10753 }
10754
10755 tmpString+=" <table border=\"1\">\n";
10756 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10757 tmpString+=" <thead>\n";
10758 tmpString+=" <tr><th>"+tr("All students")
10759 +"</th><th>"+tr("Hours per week")
10760 +"</th><th>"+tr("Free days")
10761 +"</th><th>"+tr("Gaps")
10762 +"</th><th>"+tr("Gaps per day")
10763 +"</th><th>"+tr("Hours per day")
10764 +"</th></tr>\n";
10765 tmpString+=" </thead>\n";
10766 tmpString+=" <tr><th>"+tr("Sum")+"</th>";
10767 tmpString+="<td>"+QString::number(totalNumberOfHours)+"</td>";
10768 tmpString+="<td>"+QString::number(freeDaysAllSubgroups)+"</td>";
10769 tmpString+="<td>"+QString::number(gapsAllSubgroups)+"</td>";
10770 tmpString+="<td>---</td>";
10771 tmpString+="<td>---</td>";
10772 tmpString+="</tr>\n";
10773 tmpString+=" <tr><th>"+tr("Average")+"</th>";
10774 tmpString+="<td>"+QString::number(double(totalNumberOfHours)/gt.rules.nInternalSubgroups,'f',2)+"</td>";
10775 tmpString+="<td>"+QString::number(double(freeDaysAllSubgroups)/gt.rules.nInternalSubgroups,'f',2)+"</td>";
10776 tmpString+="<td>"+QString::number(double(gapsAllSubgroups)/gt.rules.nInternalSubgroups,'f',2)+"</td>";
10777 tmpString+="<td>---</td>";
10778 tmpString+="<td>---</td>";
10779 tmpString+="</tr>\n";
10780 tmpString+=" <tr><th>"+tr("Min")+"</th>";
10781 tmpString+="<td>"+QString::number(minHoursPerWeekAllSubgroups)+"</td>";
10782 tmpString+="<td>"+QString::number(minFreeDaysAllSubgroups)+"</td>";
10783 tmpString+="<td>"+QString::number(minGapsPerWeekAllSubgroups)+"</td>";
10784 tmpString+="<td>"+QString::number(minGapsPerDayAllSubgroups)+"</td>";
10785 tmpString+="<td>"+QString::number(minHoursPerDayAllSubgroups)+"</td>";
10786 tmpString+="</tr>\n";
10787 tmpString+=" <tr><th>"+tr("Max")+"</th>";
10788 tmpString+="<td>"+QString::number(maxHoursPerWeekAllSubgroups)+"</td>";
10789 tmpString+="<td>"+QString::number(maxFreeDaysAllSubgroups)+"</td>";
10790 tmpString+="<td>"+QString::number(maxGapsPerWeekAllSubgroups)+"</td>";
10791 tmpString+="<td>"+QString::number(maxGapsPerDayAllSubgroups)+"</td>";
10792 tmpString+="<td>"+QString::number(maxHoursPerDayAllSubgroups)+"</td>";
10793 tmpString+="</tr>\n";
10794 //workaround begin.
10795 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(5)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td></tr>\n";
10796 //workaround end.
10797 tmpString+=" </table>\n";
10798
10799 tmpString+=" <p class=\"back0\"><br /></p>\n\n";
10800
10801 //subgroups statistics (end)
10802
10803 if(detailed){
10804 if(!printAll){
10805 //similar to source in else part (start)
10806 tmpString+=" <p></p>\n";
10807 tmpString+=" <table border=\"1\">\n";
10808 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10809 tmpString+=" <thead>\n";
10810 tmpString+=" <tr><th>"+tr("Subgroup")
10811 +"</th><th>"+tr("Hours per week")
10812 +"</th><th>"+tr("Free days")
10813 +"</th><th>"+tr("Total gaps")
10814 +"</th><th>"+tr("Min gaps per day")
10815 +"</th><th>"+tr("Max gaps per day")
10816 +"</th><th>"+tr("Min hours per day")
10817 +"</th><th>"+tr("Max hours per day")
10818 +"</th>";
10819 if(repeatNames){
10820 tmpString+="<td>"+tr("Subgroup")+"</td>";
10821 }
10822 tmpString+="</tr>\n";
10823 tmpString+=" </thead>\n";
10824 tmpString+=subgroupsString;
10825 //workaround begin.
10826 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(6)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10827 if(repeatNames){
10828 tmpString+="<td></td>";
10829 }
10830 tmpString+="</tr>\n";
10831 //workaround end.
10832 tmpString+=" </table>\n";
10833 //similar to source in else part (end)
10834 } else {
10835 //groups and years statistics (start)
10836 QString yearsString=" <table border=\"1\">\n";
10837 yearsString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10838 yearsString+=" <thead>\n";
10839 yearsString+=" <tr><th>"+tr("Year")
10840 +"</th><th>"+tr("Min hours per week")
10841 +"</th><th>"+tr("Max hours per week")
10842 +"</th><th>"+tr("Min free days")
10843 +"</th><th>"+tr("Max free days")
10844 +"</th><th>"+tr("Min hours per day")
10845 +"</th><th>"+tr("Max hours per day")
10846 +"</th><th>"+tr("Min gaps per week")
10847 +"</th><th>"+tr("Max gaps per week")
10848 +"</th><th>"+tr("Min gaps per day")
10849 +"</th><th>"+tr("Max gaps per day")
10850 +"</th>";
10851 if(repeatNames){
10852 yearsString+="<th>"+tr("Year")+"</th>";
10853 }
10854 yearsString+="</tr>\n";
10855 yearsString+=" </thead>\n";
10856 QString groupsString=" <table border=\"1\">\n";
10857 groupsString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
10858 groupsString+=" <thead>\n";
10859 groupsString+=" <tr><th>"+tr("Group")
10860 +"</th><th>"+tr("Min hours per week")
10861 +"</th><th>"+tr("Max hours per week")
10862 +"</th><th>"+tr("Min free days")
10863 +"</th><th>"+tr("Max free days")
10864 +"</th><th>"+tr("Min hours per day")
10865 +"</th><th>"+tr("Max hours per day")
10866 +"</th><th>"+tr("Min gaps per week")
10867 +"</th><th>"+tr("Max gaps per week")
10868 +"</th><th>"+tr("Min gaps per day")
10869 +"</th><th>"+tr("Max gaps per day")
10870 +"</th>";
10871 if(repeatNames){
10872 groupsString+="<th>"+tr("Group")+"</th>";
10873 }
10874 groupsString+="</tr>\n";
10875 groupsString+=" </thead>\n";
10876 for(int i=0; i<gt.rules.augmentedYearsList.size(); i++){
10877 StudentsYear* sty=gt.rules.augmentedYearsList[i];
10878 int minNumberOfHoursYear=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10879 int maxNumberOfHoursYear=0;
10880 int minFreeDaysPerWeekYear=gt.rules.nDaysPerWeek;
10881 int maxFreeDaysPerWeekYear=0;
10882 int minGapsPerDayYear=gt.rules.nHoursPerDay;
10883 int maxGapsPerDayYear=0;
10884 int minGapsPerWeekYear=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10885 int maxGapsPerWeekYear=0;
10886 int minHoursPerDayYear=gt.rules.nHoursPerDay;
10887 int maxHoursPerDayYear=0;
10888 for(int g=0; g<sty->groupsList.size(); g++){
10889 StudentsGroup* stg=sty->groupsList[g];
10890 int minNumberOfHoursGroup=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10891 int maxNumberOfHoursGroup=0;
10892 int minFreeDaysPerWeekGroup=gt.rules.nDaysPerWeek;
10893 int maxFreeDaysPerWeekGroup=0;
10894 int minGapsPerDayGroup=gt.rules.nHoursPerDay;
10895 int maxGapsPerDayGroup=0;
10896 int minGapsPerWeekGroup=gt.rules.nHoursPerDay*gt.rules.nDaysPerWeek;
10897 int maxGapsPerWeekGroup=0;
10898 int minHoursPerDayGroup=gt.rules.nHoursPerDay;
10899 int maxHoursPerDayGroup=0;
10900 for(int sg=0; sg<stg->subgroupsList.size(); sg++){
10901 StudentsSubgroup* sts=stg->subgroupsList[sg];
10902 int subgroup=sts->indexInInternalSubgroupsList;
10903
10904 if(minNumberOfHoursGroup>hoursPerWeekSubgroupList.at(subgroup))
10905 minNumberOfHoursGroup=hoursPerWeekSubgroupList.at(subgroup);
10906 if(maxNumberOfHoursGroup<hoursPerWeekSubgroupList.at(subgroup))
10907 maxNumberOfHoursGroup=hoursPerWeekSubgroupList.at(subgroup);
10908
10909 if(minFreeDaysPerWeekGroup>freeDaysPerWeekSubgroupList.at(subgroup))
10910 minFreeDaysPerWeekGroup=freeDaysPerWeekSubgroupList.at(subgroup);
10911 if(maxFreeDaysPerWeekGroup<freeDaysPerWeekSubgroupList.at(subgroup))
10912 maxFreeDaysPerWeekGroup=freeDaysPerWeekSubgroupList.at(subgroup);
10913
10914 if(minHoursPerDayGroup>minHoursPerDaySubgroupList.at(subgroup))
10915 minHoursPerDayGroup=minHoursPerDaySubgroupList.at(subgroup);
10916 if(maxHoursPerDayGroup<maxHoursPerDaySubgroupList.at(subgroup))
10917 maxHoursPerDayGroup=maxHoursPerDaySubgroupList.at(subgroup);
10918
10919 if(minGapsPerWeekGroup>gapsPerWeekSubgroupList.at(subgroup))
10920 minGapsPerWeekGroup=gapsPerWeekSubgroupList.at(subgroup);
10921 if(maxGapsPerWeekGroup<gapsPerWeekSubgroupList.at(subgroup))
10922 maxGapsPerWeekGroup=gapsPerWeekSubgroupList.at(subgroup);
10923
10924 if(minGapsPerDayGroup>minGapsPerDaySubgroupList.at(subgroup))
10925 minGapsPerDayGroup=minGapsPerDaySubgroupList.at(subgroup);
10926 if(maxGapsPerDayGroup<maxGapsPerDaySubgroupList.at(subgroup))
10927 maxGapsPerDayGroup=maxGapsPerDaySubgroupList.at(subgroup);
10928 }
10929 //print groups
10930 groupsString+=" <tr><th>"+protect2(stg->name)+"</th><td>"
10931 +QString::number(minNumberOfHoursGroup)+"</td><td>"+QString::number(maxNumberOfHoursGroup)+"</td><td>"
10932 +QString::number(minFreeDaysPerWeekGroup)+"</td><td>"+QString::number(maxFreeDaysPerWeekGroup)+"</td><td>"
10933 +QString::number(minHoursPerDayGroup)+"</td><td>"+QString::number(maxHoursPerDayGroup)+"</td><td>"
10934 +QString::number(minGapsPerWeekGroup)+"</td><td>"+QString::number(maxGapsPerWeekGroup)+"</td><td>"
10935 +QString::number(minGapsPerDayGroup)+"</td><td>"+QString::number(maxGapsPerDayGroup)+"</td>";
10936 if(repeatNames){
10937 groupsString+="<th>"+protect2(stg->name)+"</th>";
10938 }
10939 groupsString+="</tr>\n";
10940
10941 //check years
10942 if(minNumberOfHoursYear>minNumberOfHoursGroup)
10943 minNumberOfHoursYear=minNumberOfHoursGroup;
10944 if(maxNumberOfHoursYear<maxNumberOfHoursGroup)
10945 maxNumberOfHoursYear=maxNumberOfHoursGroup;
10946
10947 if(minFreeDaysPerWeekYear>minFreeDaysPerWeekGroup)
10948 minFreeDaysPerWeekYear=minFreeDaysPerWeekGroup;
10949 if(maxFreeDaysPerWeekYear<maxFreeDaysPerWeekGroup)
10950 maxFreeDaysPerWeekYear=maxFreeDaysPerWeekGroup;
10951
10952 if(minHoursPerDayYear>minHoursPerDayGroup)
10953 minHoursPerDayYear=minHoursPerDayGroup;
10954 if(maxHoursPerDayYear<maxHoursPerDayGroup)
10955 maxHoursPerDayYear=maxHoursPerDayGroup;
10956
10957 if(minGapsPerWeekYear>minGapsPerWeekGroup)
10958 minGapsPerWeekYear=minGapsPerWeekGroup;
10959 if(maxGapsPerWeekYear<maxGapsPerWeekGroup)
10960 maxGapsPerWeekYear=maxGapsPerWeekGroup;
10961
10962 if(minGapsPerDayYear>minGapsPerDayGroup)
10963 minGapsPerDayYear=minGapsPerDayGroup;
10964 if(maxGapsPerDayYear<maxGapsPerDayGroup)
10965 maxGapsPerDayYear=maxGapsPerDayGroup;
10966 }
10967 //print years
10968 yearsString+=" <tr><th>"+protect2(sty->name)+"</th><td>"
10969 +QString::number(minNumberOfHoursYear)+"</td><td>"+QString::number(maxNumberOfHoursYear)+"</td><td>"
10970 +QString::number(minFreeDaysPerWeekYear)+"</td><td>"+QString::number(maxFreeDaysPerWeekYear)+"</td><td>"
10971 +QString::number(minHoursPerDayYear)+"</td><td>"+QString::number(maxHoursPerDayYear)+"</td><td>"
10972 +QString::number(minGapsPerWeekYear)+"</td><td>"+QString::number(maxGapsPerWeekYear)+"</td><td>"
10973 +QString::number(minGapsPerDayYear)+"</td><td>"+QString::number(maxGapsPerDayYear)+"</td>";
10974 if(repeatNames){
10975 yearsString+="<th>"+protect2(sty->name)+"</th>";
10976 }
10977 yearsString+="</tr>\n";
10978 }
10979 //workaround begin.
10980 groupsString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(10)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10981 if(repeatNames){
10982 groupsString+="<td></td>";
10983 }
10984 groupsString+="</tr>\n";
10985 //workaround end.
10986 groupsString+=" </table>\n";
10987 groupsString+=" <p class=\"back0\"><br /></p>\n\n";
10988 //workaround begin.
10989 yearsString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(10)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
10990 if(repeatNames){
10991 yearsString+="<td></td>";
10992 }
10993 yearsString+="</tr>\n";
10994 //workaround end.
10995 yearsString+=" </table>\n";
10996 yearsString+=" <p class=\"back0\"><br /></p>\n\n";
10997 tmpString+=yearsString;
10998 tmpString+=groupsString;
10999 //similar to source in if part (start)
11000 tmpString+=" <p></p>\n";
11001 tmpString+=" <table border=\"1\">\n";
11002 tmpString+=" <caption>"+protect2(gt.rules.institutionName)+"</caption>\n";
11003 tmpString+=" <thead>\n";
11004 tmpString+=" <tr><th>"+tr("Subgroup")
11005 +"</th><th>"+tr("Hours per week")
11006 +"</th><th>"+tr("Free days")
11007 +"</th><th>"+tr("Total gaps")
11008 +"</th><th>"+tr("Min gaps per day")
11009 +"</th><th>"+tr("Max gaps per day")
11010 +"</th><th>"+tr("Min hours per day")
11011 +"</th><th>"+tr("Max hours per day")
11012 +"</th>";
11013 if(repeatNames){
11014 tmpString+="<td>"+tr("Subgroup")+"</td>";
11015 }
11016 tmpString+="</tr>\n";
11017 tmpString+=" </thead>\n";
11018 tmpString+=subgroupsString;
11019 //workaround begin.
11020 tmpString+=" <tr class=\"foot\"><td></td><td colspan=\""+QString::number(7)+"\">"+TimetableExport::tr("Timetable generated with FET %1 on %2", "%1 is FET version, %2 is the date and time of generation").arg(FET_VERSION).arg(saveTime)+"</td>";
11021 if(repeatNames){
11022 tmpString+="<td></td>";
11023 }
11024 tmpString+="</tr>\n";
11025 //workaround end.
11026 tmpString+=" </table>\n";
11027 //similar to source in if part (end)
11028 }
11029 }
11030 //groups and years statistics (end)
11031 return tmpString;
11032 }
11033