Back to index

fet  5.18.0
statisticsexport.cpp
Go to the documentation of this file.
00001 /*
00002 File statisticsexport.cpp
00003 */
00004 
00005 /***************************************************************************
00006                                 FET
00007                           -------------------
00008    copyright            : (C) by Lalescu Liviu
00009     email                : Please see http://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
00010  ***************************************************************************
00011                       statisticsexport.cpp  -  description
00012                              -------------------
00013     begin                : Sep 2008
00014     copyright            : (C) by Volker Dirr
00015                          : http://www.timetabling.de/
00016  ***************************************************************************
00017  *                                                                         *
00018  *   This program is free software; you can redistribute it and/or modify  *
00019  *   it under the terms of the GNU General Public License as published by  *
00020  *   the Free Software Foundation; either version 2 of the License, or     *
00021  *   (at your option) any later version.                                   *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
00025 // Code contributed by Volker Dirr ( http://www.timetabling.de/ )
00026 // Many thanks to Liviu Lalescu. He told me some speed optimizations.
00027 
00028 #include "timetable_defs.h"
00029 #include "statisticsexport.h"
00030 
00031 // BE CAREFUL: DON'T USE INTERNAL VARIABLES HERE, because maybe computeInternalStructure() is not done!
00032 
00033 #include <QString>
00034 #include <QStringList>
00035 #include <QHash>
00036 #include <QMultiHash>
00037 #include <QMap>
00038 
00039 #include <QMessageBox>
00040 
00041 #include <QLocale>
00042 #include <QTime>
00043 #include <QDate>
00044 
00045 #include <QDir>
00046 
00047 #include <QFile>
00048 #include <QTextStream>
00049 
00050 //#include <QApplication>
00051 #include <QProgressDialog>
00052 //extern QApplication* pqapplication;
00053 
00054 extern Timetable gt;
00055 
00056 static QHash<QString, QString> hashSubjectIDsStatistics;
00057 static QHash<QString, QString> hashActivityTagIDsStatistics;
00058 static QHash<QString, QString> hashStudentIDsStatistics;
00059 static QHash<QString, QString> hashTeacherIDsStatistics;
00060 static QHash<QString, QString> hashRoomIDsStatistics;
00061 static QHash<QString, QString> hashDayIDsStatistics;
00062 
00063 //extern bool simulation_running;  //needed?
00064 
00065 QHash <QString, int> teachersTotalNumberOfHours;
00066 QHash <QString, int> teachersTotalNumberOfHours2;
00067 QHash <QString, int> studentsTotalNumberOfHours;
00068 QHash <QString, int> studentsTotalNumberOfHours2;
00069 QHash <QString, int> subjectsTotalNumberOfHours;
00070 QHash <QString, int> subjectsTotalNumberOfHours4;
00071 QStringList allStudentsNames;                           //NOT QSet <QString>!!! Because that do an incorrect order of the lists!
00072 QStringList allTeachersNames;                           //NOT QSet <QString>!!! Because that do an incorrect order of the lists!
00073 QStringList allSubjectsNames;                           //NOT QSet <QString>!!! Because that do an incorrect order of the lists!
00074 static QMultiHash <QString, int> studentsActivities;
00075 static QMultiHash <QString, int> teachersActivities;
00076 static QMultiHash <QString, int> subjectsActivities;
00077 
00078 //TODO: use the external string!!!
00079 //extern const QString STRING_EMPTY_SLOT;
00080 const QString STRING_EMPTY_SLOT_STATISTICS="---";
00081 
00082 const char TEACHERS_STUDENTS_STATISTICS[]="teachers_students.html";
00083 const char TEACHERS_SUBJECTS_STATISTICS[]="teachers_subjects.html";
00084 const char STUDENTS_TEACHERS_STATISTICS[]="students_teachers.html";
00085 const char STUDENTS_SUBJECTS_STATISTICS[]="students_subjects.html";
00086 const char SUBJECTS_TEACHERS_STATISTICS[]="subjects_teachers.html";
00087 const char SUBJECTS_STUDENTS_STATISTICS[]="subjects_students.html";
00088 const char STYLESHEET_STATISTICS[]="stylesheet.css";
00089 const char INDEX_STATISTICS[]="index.html";
00090 
00091 QString DIRECTORY_STATISTICS;
00092 QString PREFIX_STATISTICS;
00093 
00094 StatisticsExport::StatisticsExport()
00095 {
00096 }
00097 
00098 StatisticsExport::~StatisticsExport()
00099 {
00100 }
00101 
00102 void StatisticsExport::exportStatistics(QWidget* parent){
00103        assert(gt.rules.initialized);
00104        assert(TIMETABLE_HTML_LEVEL>=0);
00105        assert(TIMETABLE_HTML_LEVEL<=6);
00106 
00107        computeHashForIDsStatistics();
00108 
00109        DIRECTORY_STATISTICS=OUTPUT_DIR+FILE_SEP+"statistics";
00110        
00111        if(INPUT_FILENAME_XML=="")
00112               DIRECTORY_STATISTICS.append(FILE_SEP+"unnamed");
00113        else{
00114               DIRECTORY_STATISTICS.append(FILE_SEP+INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1));
00115 
00116               if(DIRECTORY_STATISTICS.right(4)==".fet")
00117                      DIRECTORY_STATISTICS=DIRECTORY_STATISTICS.left(DIRECTORY_STATISTICS.length()-4);
00118               //else if(INPUT_FILENAME_XML!="")
00119               //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00120        }
00121        
00122        PREFIX_STATISTICS=DIRECTORY_STATISTICS+FILE_SEP;
00123        
00124        int ok=QMessageBox::question(parent, tr("FET Question"),
00125                StatisticsExport::tr("Do you want to export detailed statistic files into directory %1 as html files?").arg(QDir::toNativeSeparators(DIRECTORY_STATISTICS)), QMessageBox::Yes | QMessageBox::No);
00126        if(ok==QMessageBox::No)
00127               return;
00128 
00129        /* need if i use iTeachersList. Currently unneeded. please remove commented asserts in other functions if this is needed again!
00130        bool tmp=gt.rules.computeInternalStructure();
00131        if(!tmp){
00132               QMessageBox::critical(parent, tr("FET critical"),
00133               StatisticsExport::tr("Incorrect data")+"\n");
00134               return;
00135               assert(0==1);
00136        }*/
00137 
00138        QDir dir;
00139        if(!dir.exists(OUTPUT_DIR))
00140               dir.mkpath(OUTPUT_DIR);
00141        if(!dir.exists(DIRECTORY_STATISTICS))
00142               dir.mkpath(DIRECTORY_STATISTICS);
00143 
00144        QSet<QString> allStudentsNamesSet;
00145        allStudentsNames.clear();
00146        foreach(StudentsYear* sty, gt.rules.yearsList){
00147               if(!allStudentsNamesSet.contains(sty->name)){
00148                      allStudentsNames<<sty->name;
00149                      allStudentsNamesSet.insert(sty->name);
00150               }
00151               foreach(StudentsGroup* stg, sty->groupsList){
00152                      if(!allStudentsNamesSet.contains(stg->name)){
00153                             allStudentsNames<<stg->name;
00154                             allStudentsNamesSet.insert(stg->name);
00155                      }
00156                      foreach(StudentsSubgroup* sts, stg->subgroupsList){
00157                             if(!allStudentsNamesSet.contains(sts->name)){
00158                                    allStudentsNames<<sts->name;
00159                                    allStudentsNamesSet.insert(sts->name);
00160                             }
00161                      }
00162               }
00163        }
00164 
00165        allTeachersNames.clear();                        // just needed, because i don't need to care about correct iTeacherList if i do it this way.
00166        foreach(Teacher* t, gt.rules.teachersList){             //  So i don't need gt.rules.computeInternalStructure();
00167               allTeachersNames<<t->name;
00168        }
00169 
00170        allSubjectsNames.clear();                        // just done, because i always want to do it the same way + it is faster
00171        foreach(Subject* s, gt.rules.subjectsList){             // Also don't display empty subjects is easier
00172               allSubjectsNames<<s->name;
00173        }
00174 
00175        studentsTotalNumberOfHours.clear();
00176        studentsTotalNumberOfHours2.clear();
00177 
00178        subjectsTotalNumberOfHours.clear();
00179        subjectsTotalNumberOfHours4.clear();
00180 
00181        teachersTotalNumberOfHours.clear();
00182        teachersTotalNumberOfHours2.clear();
00183 
00184        studentsActivities.clear();
00185        subjectsActivities.clear();
00186        teachersActivities.clear();
00187 
00188        Activity* act;
00189        
00190        //QProgressDialog progress(parent);
00191        //progress.setLabelText(tr("Processing activities...please wait"));
00192        //progress.setRange(0,gt.rules.activitiesList.count());
00193        //progress.setModal(true);
00194        
00195        for(int ai=0; ai<gt.rules.activitiesList.size(); ai++){
00196               //progress.setValue(ai);
00197               //pqapplication->processEvents();
00198               
00199               act=gt.rules.activitiesList[ai];
00200               if(act->active){
00201                             subjectsActivities.insert(act->subjectName, ai);
00202                             int tmp=subjectsTotalNumberOfHours.value(act->subjectName)+act->duration;
00203                             subjectsTotalNumberOfHours.insert(act->subjectName, tmp);                                         // (1) so teamlearning-teaching is not counted twice!
00204                             foreach(QString t, act->teachersNames){
00205                                    teachersActivities.insert(t, ai);
00206                                    tmp=teachersTotalNumberOfHours.value(t)+act->duration;
00207                                    teachersTotalNumberOfHours.insert(t, tmp);                                                 // (3)
00208                                    //subjectstTotalNumberOfHours2[act->subjectIndex]+=duration;                        // (1) so teamteaching is counted twice!
00209                             }
00210                             foreach(QString st, act->studentsNames){
00211                                    studentsActivities.insert(st, ai);
00212                                    tmp=studentsTotalNumberOfHours.value(st)+act->duration;
00213                                    studentsTotalNumberOfHours.insert(st, tmp);                                                // (2)
00214                                    //subjectstTotalNumberOfHours3[act->subjectIndex]+=duration;                        // (1) so teamlearning is counted twice!
00215                             }
00216                             foreach(QString t, act->teachersNames){
00217                                    tmp=teachersTotalNumberOfHours2.value(t);
00218                                    tmp += act->duration * act->studentsNames.count();
00219                                    teachersTotalNumberOfHours2.insert(t, tmp);                                         // (3)
00220                             }
00221                             foreach(QString st, act->studentsNames){
00222                                    tmp=studentsTotalNumberOfHours2.value(st);
00223                                    tmp += act->duration * act->teachersNames.count();
00224                                    studentsTotalNumberOfHours2.insert(st, tmp);                                 // (2)
00225                             }
00226                             tmp=subjectsTotalNumberOfHours4.value(act->subjectName);
00227                             tmp += act->duration * act->studentsNames.count() * act->teachersNames.count();
00228                             subjectsTotalNumberOfHours4.insert(act->subjectName, tmp);                   // (1) so teamlearning-teaching is counted twice!
00229                      }
00230        }
00231        //progress.setValue(gt.rules.activitiesList.count());
00232        QStringList tmp;
00233        tmp.clear();
00234        foreach(QString students, allStudentsNames){
00235               if(studentsTotalNumberOfHours.value(students)==0 && studentsTotalNumberOfHours2.value(students)==0){
00236                      studentsTotalNumberOfHours.remove(students);
00237                      studentsTotalNumberOfHours2.remove(students);
00238               } else
00239                      tmp<<students;
00240        }
00241        allStudentsNames=tmp;
00242        tmp.clear();
00243        foreach(QString teachers, allTeachersNames){
00244               if(teachersTotalNumberOfHours.value(teachers)==0 && teachersTotalNumberOfHours2.value(teachers)==0){
00245                             teachersTotalNumberOfHours.remove(teachers);
00246                             teachersTotalNumberOfHours2.remove(teachers);
00247               } else
00248                      tmp<<teachers;
00249        }
00250        allTeachersNames=tmp;
00251        tmp.clear();
00252        foreach(QString subjects, allSubjectsNames){
00253               if(subjectsTotalNumberOfHours.value(subjects)==0 && subjectsTotalNumberOfHours4.value(subjects)==0){
00254                      subjectsTotalNumberOfHours.remove(subjects);
00255                      subjectsTotalNumberOfHours4.remove(subjects);
00256               } else
00257                      tmp<<subjects;
00258        }
00259        allSubjectsNames=tmp;
00260        tmp.clear();
00261 
00262        QDate dat=QDate::currentDate();
00263        QTime tim=QTime::currentTime();
00264        QLocale loc(FET_LANGUAGE);
00265        QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
00266 
00267        ok=true;
00268        ok=exportStatisticsStylesheetCss(parent, sTime);
00269        if(ok)
00270               ok=exportStatisticsIndex(parent, sTime);
00271        if(ok)
00272               ok=exportStatisticsTeachersSubjects(parent, sTime);
00273        if(ok)
00274               ok=exportStatisticsSubjectsTeachers(parent, sTime);
00275        if(ok)
00276               ok=exportStatisticsTeachersStudents(parent, sTime);
00277        if(ok)
00278               ok=exportStatisticsStudentsTeachers(parent, sTime);
00279        if(ok)
00280               ok=exportStatisticsSubjectsStudents(parent, sTime);
00281        if(ok)
00282               ok=exportStatisticsStudentsSubjects(parent, sTime);
00283 
00284        if(ok){
00285               QMessageBox::information(parent, tr("FET Information"),
00286                StatisticsExport::tr("Statistic files were exported to directory %1 as html files.").arg(QDir::toNativeSeparators(DIRECTORY_STATISTICS)));
00287        } else {
00288               QMessageBox::warning(parent, tr("FET warning"),
00289                StatisticsExport::tr("Statistic export incomplete")+"\n");
00290        }
00291        teachersTotalNumberOfHours.clear();
00292        teachersTotalNumberOfHours2.clear();
00293        studentsTotalNumberOfHours.clear();
00294        studentsTotalNumberOfHours2.clear();
00295        subjectsTotalNumberOfHours.clear();
00296        subjectsTotalNumberOfHours4.clear();
00297        allStudentsNames.clear();
00298        allTeachersNames.clear();
00299        allSubjectsNames.clear();
00300        studentsActivities.clear();
00301        teachersActivities.clear();
00302        subjectsActivities.clear();
00303 
00304        hashSubjectIDsStatistics.clear();
00305        hashActivityTagIDsStatistics.clear();
00306        hashStudentIDsStatistics.clear();
00307        hashTeacherIDsStatistics.clear();
00308        hashRoomIDsStatistics.clear();
00309        hashDayIDsStatistics.clear();
00310 }
00311 
00312 void StatisticsExport::computeHashForIDsStatistics(){          // by Volker Dirr
00313        //TODO if an use a relational data base this is unneded, because we can use the primary key id of the database 
00314        //This is very similar to timetable compute hash. so always check it if you change something here!
00315 
00316        hashStudentIDsStatistics.clear();
00317        int cnt=1;
00318        for(int i=0; i<gt.rules.yearsList.size(); i++){
00319               StudentsYear* sty=gt.rules.yearsList[i];
00320               if(!hashStudentIDsStatistics.contains(sty->name)){
00321                      hashStudentIDsStatistics.insert(sty->name, CustomFETString::number(cnt));
00322                      cnt++;
00323               }
00324               for(int j=0; j<sty->groupsList.size(); j++){
00325                      StudentsGroup* stg=sty->groupsList[j];
00326                      if(!hashStudentIDsStatistics.contains(stg->name)){
00327                             hashStudentIDsStatistics.insert(stg->name, CustomFETString::number(cnt));
00328                             cnt++;
00329                      }
00330                      for(int k=0; k<stg->subgroupsList.size(); k++){
00331                             StudentsSubgroup* sts=stg->subgroupsList[k];
00332                             if(!hashStudentIDsStatistics.contains(sts->name)){
00333                                    hashStudentIDsStatistics.insert(sts->name, CustomFETString::number(cnt));
00334                                    cnt++;
00335                             }
00336                      }
00337               }
00338        }
00339 
00340        hashSubjectIDsStatistics.clear();
00341        for(int i=0; i<gt.rules.subjectsList.size(); i++){
00342               hashSubjectIDsStatistics.insert(gt.rules.subjectsList[i]->name, CustomFETString::number(i+1));
00343        }
00344        hashActivityTagIDsStatistics.clear();
00345        for(int i=0; i<gt.rules.activityTagsList.size(); i++){
00346               hashActivityTagIDsStatistics.insert(gt.rules.activityTagsList[i]->name, CustomFETString::number(i+1));
00347        }
00348        hashTeacherIDsStatistics.clear();
00349        for(int i=0; i<gt.rules.teachersList.size(); i++){
00350               hashTeacherIDsStatistics.insert(gt.rules.teachersList[i]->name, CustomFETString::number(i+1));
00351        }
00352        hashRoomIDsStatistics.clear();
00353        for(int room=0; room<gt.rules.roomsList.size(); room++){
00354               hashRoomIDsStatistics.insert(gt.rules.roomsList[room]->name, CustomFETString::number(room+1));
00355        }
00356        hashDayIDsStatistics.clear();
00357        for(int k=0; k<gt.rules.nDaysPerWeek; k++){
00358               hashDayIDsStatistics.insert(gt.rules.daysOfTheWeek[k], CustomFETString::number(k+1));
00359        }
00360 }
00361 
00362 bool StatisticsExport::exportStatisticsStylesheetCss(QWidget* parent, QString saveTime){
00363        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
00364        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00365 
00366        if(s2.right(4)==".fet")
00367               s2=s2.left(s2.length()-4);
00368        //else if(INPUT_FILENAME_XML!="")
00369        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00370 
00371        QString bar;
00372        if(INPUT_FILENAME_XML=="")
00373               bar="";
00374        else
00375               bar="_";
00376        
00377        QString htmlfilename=PREFIX_STATISTICS+s2+bar+STYLESHEET_STATISTICS;
00378 
00379        QFile file(htmlfilename);
00380        if(!file.open(QIODevice::WriteOnly)){
00381               QMessageBox::critical(parent, tr("FET critical"),
00382                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
00383               return false;
00384               assert(0);
00385        }
00386        QTextStream tos(&file);
00387        tos.setCodec("UTF-8");
00388        tos.setGenerateByteOrderMark(true);
00389 
00390        //get used students  //similar to timetableexport.cpp, so maybe use a function?
00391        QSet<QString> usedStudents;
00392        for(int i=0; i<gt.rules.activitiesList.size(); i++){
00393               foreach(QString st, gt.rules.activitiesList[i]->studentsNames){
00394                      if(gt.rules.activitiesList[i]->active){
00395                             if(!usedStudents.contains(st))
00396                                    usedStudents<<st;
00397                      }
00398               }
00399        }
00400 
00401        tos<<"@charset \"UTF-8\";"<<"\n\n";
00402 
00403        QString tt=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00404        if(INPUT_FILENAME_XML=="")
00405               tt=tr("unnamed");
00406        tos<<"/* "<<StatisticsExport::tr("CSS Stylesheet of %1", "%1 is the file name").arg(tt);
00407        tos<<"\n";
00408        tos<<"   "<<StatisticsExport::tr("Stylesheet generated with FET %1 on %2", "%1 is FET version, %2 is date and time").arg(FET_VERSION).arg(saveTime)<<" */\n\n";
00409 
00410        tos<<"/* "<<StatisticsExport::tr("To hide an element just write the following phrase into the element: %1 (without quotes).",
00411               "%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";
00412        tos<<"table {\n  text-align: center;\n}\n\n";
00413        tos<<"caption {\n\n}\n\n";
00414        tos<<"thead {\n\n}\n\n";
00415 
00416        //workaround begin.
00417        tos<<"/* "<<StatisticsExport::tr("Some programs import \"tfoot\" incorrectly. So we use \"tr.foot\" instead of \"tfoot\".",
00418         "Please keep tfoot and tr.foot untranslated, as they are in the original English phrase")<<" */\n\n";
00419        //tos<<"tfoot {\n\n}\n\n";
00420        tos<<"tr.foot {\n\n}\n\n";
00421        //workaround end
00422        
00423        tos<<"tbody {\n\n}\n\n";
00424        tos<<"th {\n\n}\n\n";
00425        tos<<"td {\n\n}\n\n";
00426        tos<<"td.detailed {\n  border: 1px dashed silver;\n  border-bottom: 0;\n  border-top: 0;\n}\n\n";
00427        if(TIMETABLE_HTML_LEVEL>=2){
00428               tos<<"th.xAxis {\n/*width: 8em; */\n}\n\n";
00429               tos<<"th.yAxis {\n  height: 8ex;\n}\n\n";
00430        }
00431        if(TIMETABLE_HTML_LEVEL>=4){ // must be written before LEVEL 3, because LEVEL 3 should have higher priority
00432               for(int i=0; i<gt.rules.subjectsList.size(); i++){
00433                      tos << "span.s_"<<hashSubjectIDsStatistics.value(gt.rules.subjectsList[i]->name)<<" { /* subject "<<gt.rules.subjectsList[i]->name<<" */\n\n}\n\n";
00434               }
00435               for(int i=0; i<gt.rules.activityTagsList.size(); i++){
00436                      tos << "span.at_"<<hashActivityTagIDsStatistics.value(gt.rules.activityTagsList[i]->name)<<" { /* activity tag "<<gt.rules.activityTagsList[i]->name<<" */\n\n}\n\n";
00437               }
00438               for(int i=0; i<gt.rules.yearsList.size(); i++){
00439                      StudentsYear* sty=gt.rules.yearsList[i];
00440                      if(usedStudents.contains(sty->name))
00441                             tos << "span.ss_"<<hashStudentIDsStatistics.value(sty->name)<<" { /* students set "<<sty->name<<" */\n\n}\n\n";
00442                      for(int j=0; j<sty->groupsList.size(); j++){
00443                             StudentsGroup* stg=sty->groupsList[j];
00444                             if(usedStudents.contains(stg->name))
00445                                    tos << "span.ss_"<<hashStudentIDsStatistics.value(stg->name)<<" { /* students set "<<stg->name<<" */\n\n}\n\n";
00446                             for(int k=0; k<stg->subgroupsList.size(); k++){
00447                                    StudentsSubgroup* sts=stg->subgroupsList[k];
00448                                    if(usedStudents.contains(sts->name))
00449                                           tos << "span.ss_"<<hashStudentIDsStatistics.value(sts->name)<<" { /* students set "<<sts->name<<" */\n\n}\n\n";
00450                             }
00451                      }
00452               }
00453               for(int i=0; i<gt.rules.teachersList.size(); i++){
00454                      tos << "span.t_"<<hashTeacherIDsStatistics.value(gt.rules.teachersList[i]->name)<<" { /* teacher "<<gt.rules.teachersList[i]->name<<" */\n\n}\n\n";
00455               }
00456               for(int room=0; room<gt.rules.roomsList.size(); room++){
00457                      tos << "span.r_"<<hashRoomIDsStatistics.value(gt.rules.roomsList[room]->name)<<" { /* room "<<gt.rules.roomsList[room]->name<<" */\n\n}\n\n";
00458               }
00459        }
00460        if(TIMETABLE_HTML_LEVEL>=3){
00461               tos<<"span.subject {\n\n}\n\n";
00462               tos<<"span.activitytag {\n\n}\n\n";
00463               tos<<"span.empty {\n  color: gray;\n}\n\n";
00464               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";
00465               tos<<"span.notAvailable {\n  color: gray;\n}\n\n";
00466               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";
00467               tos<<"td.student, div.student {\n\n}\n\n";
00468               tos<<"td.teacher, div.teacher {\n\n}\n\n";
00469               tos<<"td.room, div.room {\n\n}\n\n";
00470               tos<<"tr.line0 {\n  font-size: smaller;\n}\n\n";
00471               tos<<"tr.line1, div.line1 {\n\n}\n\n";
00472               tos<<"tr.line2, div.line2 {\n  font-size: smaller;\n  color: gray;\n}\n\n";
00473               tos<<"tr.line3, div.line3 {\n  font-size: smaller;\n  color: silver;\n}\n\n";
00474        }
00475        
00476        tos<<"/* "<<StatisticsExport::tr("End of file.")<<" */\n";
00477 
00478        if(file.error()>0){
00479               QMessageBox::critical(parent, tr("FET critical"),
00480                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
00481               return false;
00482        }
00483        file.close();
00484        return true;
00485 }
00486 
00487 bool StatisticsExport::exportStatisticsIndex(QWidget* parent, QString saveTime){
00488        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
00489        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00490        
00491        if(s2.right(4)==".fet")
00492               s2=s2.left(s2.length()-4);
00493        //else if(INPUT_FILENAME_XML!="")
00494        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00495 
00496        QString bar;
00497        if(INPUT_FILENAME_XML=="")
00498               bar="";
00499        else
00500               bar="_";
00501        
00502        QString htmlfilename=PREFIX_STATISTICS+s2+bar+INDEX_STATISTICS;
00503        QFile file(htmlfilename);
00504        if(!file.open(QIODevice::WriteOnly)){
00505               QMessageBox::critical(parent, tr("FET critical"),
00506                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
00507               return false;
00508               assert(0);
00509        }
00510        QTextStream tos(&file);
00511        tos.setCodec("UTF-8");
00512        tos.setGenerateByteOrderMark(true);
00513 
00514        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
00515        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
00516 
00517        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
00518               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
00519        else
00520               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
00521        tos<<"  <head>\n";
00522        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
00523        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
00524 
00525        if(TIMETABLE_HTML_LEVEL>=1){
00526               QString bar;
00527               if(INPUT_FILENAME_XML=="")
00528                      bar="";
00529               else
00530                      bar="_";
00531 
00532               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
00533               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
00534        }
00535        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
00536               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
00537               tos<<"    <script type=\"text/javascript\">\n";
00538               tos<<"      function highlight(classval) {\n";
00539               tos<<"        var spans = document.getElementsByTagName('span');\n";
00540               tos<<"        for(var i=0; spans.length>i; i++) {\n";
00541               tos<<"          if (spans[i].className == classval) {\n";
00542               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
00543               tos<<"          } else {\n";
00544               tos<<"            spans[i].style.backgroundColor = 'white';\n";
00545               tos<<"          }\n";
00546               tos<<"        }\n";
00547               tos<<"      }\n";
00548               tos<<"    </script>\n";
00549        }
00550        tos<<"  </head>\n\n";
00551 
00552        tos<<"  <body>\n";
00553 
00554        tos<<"    <table>\n      <tr align=\"left\" valign=\"top\">\n        <th>"+tr("Institution name")+":</th>\n        <td>"+protect2(gt.rules.institutionName)+"</td>\n      </tr>\n    </table>\n";
00555        tos<<"    <table>\n      <tr align=\"left\" valign=\"top\">\n        <th>"+tr("Comments")+":</th>\n        <td>"+protect2(gt.rules.comments).replace(QString("\n"), QString("<br />\n"))+"</td>\n      </tr>\n    </table>\n";
00556        tos<<"    <p>\n";
00557        tos<<"    </p>\n";
00558 
00559        tos<<"    <table border=\"1\">\n";
00560        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
00561        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\"3\">"+tr("Statistics")+"</th></tr>\n";
00562        tos<<"        <tr>\n          <!-- span -->\n";
00563        tos<<"          <th>"+tr("Teachers")+"</th><th>"+tr("Students")+"</th><th>"+tr("Subjects")+"</th>\n";
00564        tos<<"        </tr>\n";
00565        tos<<"      </thead>\n";
00566        tos<<"      <tbody>\n";
00567        tos<<"        <tr>\n";
00568        tos<<"          <th>"+tr("Teachers")+"</th>\n";
00569        tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
00570        tos<<"          <td><a href=\""<<s2+bar+TEACHERS_STUDENTS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00571        tos<<"          <td><a href=\""<<s2+bar+TEACHERS_SUBJECTS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00572        tos<<"        </tr>\n";
00573        tos<<"        <tr>\n";
00574        tos<<"          <th>"+tr("Students")+"</th>\n";
00575        tos<<"          <td><a href=\""<<s2+bar+STUDENTS_TEACHERS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00576        tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
00577        tos<<"          <td><a href=\""<<s2+bar+STUDENTS_SUBJECTS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00578        tos<<"        </tr>\n";
00579        tos<<"        <tr>\n";
00580        tos<<"          <th>"+tr("Subjects")+"</th>\n";
00581        tos<<"          <td><a href=\""<<s2+bar+SUBJECTS_TEACHERS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00582        tos<<"          <td><a href=\""<<s2+bar+SUBJECTS_STUDENTS_STATISTICS<<"\">"+tr("view")+"</a></td>\n";
00583        tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
00584        tos<<"        </tr>\n";
00585        //workaround begin.
00586        tos<<"      <tr class=\"foot\"><td></td><td colspan=\"3\">"<<StatisticsExport::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";
00587        //workaround end.
00588        tos<<"      </tbody>\n";
00589        tos<<"    </table>\n";
00590        tos<<"  </body>\n</html>\n";
00591 
00592        if(file.error()>0){
00593               QMessageBox::critical(parent, tr("FET critical"),
00594                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
00595               return false;
00596        }
00597        file.close();
00598        return true;
00599 }
00600 
00601 bool StatisticsExport::exportStatisticsTeachersSubjects(QWidget* parent, QString saveTime){
00602        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
00603        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00604 
00605        if(s2.right(4)==".fet")
00606               s2=s2.left(s2.length()-4);
00607        //else if(INPUT_FILENAME_XML!="")
00608        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00609 
00610        QString bar;
00611        if(INPUT_FILENAME_XML=="")
00612               bar="";
00613        else
00614               bar="_";
00615 
00616        QString htmlfilename=PREFIX_STATISTICS+s2+bar+TEACHERS_SUBJECTS_STATISTICS;
00617        QFile file(htmlfilename);
00618        if(!file.open(QIODevice::WriteOnly)){
00619               QMessageBox::critical(parent, tr("FET critical"),
00620                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
00621               return false;
00622               assert(0);
00623        }
00624        QTextStream tos(&file);
00625        tos.setCodec("UTF-8");
00626        tos.setGenerateByteOrderMark(true);
00627 
00628        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
00629        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
00630 
00631        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
00632               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
00633        else
00634               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
00635        tos<<"  <head>\n";
00636        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
00637        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
00638        if(TIMETABLE_HTML_LEVEL>=1){
00639               QString bar;
00640               if(INPUT_FILENAME_XML=="")
00641                      bar="";
00642               else
00643                      bar="_";
00644        
00645               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
00646               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
00647        }
00648        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
00649               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
00650               tos<<"    <script type=\"text/javascript\">\n";
00651               tos<<"      function highlight(classval) {\n";
00652               tos<<"        var spans = document.getElementsByTagName('span');\n";
00653               tos<<"        for(var i=0;spans.length>i;i++) {\n";
00654               tos<<"          if (spans[i].className == classval) {\n";
00655               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
00656               tos<<"          } else {\n";
00657               tos<<"            spans[i].style.backgroundColor = 'white';\n";
00658               tos<<"          }\n";
00659               tos<<"        }\n";
00660               tos<<"      }\n";
00661               tos<<"    </script>\n";
00662        }
00663        tos<<"  </head>\n\n";
00664 
00665        tos<<"  <body>\n";
00666        tos<<"    <table border=\"1\">\n"; 
00667        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
00668        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allTeachersNames.size()+1<<"\">"<<tr("Teachers - Subjects Matrix")<<"</th></tr>\n";
00669        tos<<"        <tr>\n          <!-- span -->\n";
00670        foreach(QString teachers, allTeachersNames){
00671               if(TIMETABLE_HTML_LEVEL>=2)
00672                      tos<<"          <th class=\"xAxis\">";
00673               else
00674                      tos<<"          <th>";
00675               tos<<protect2(teachers)<<"</th>\n";
00676        }
00677        if(TIMETABLE_HTML_LEVEL>=2)
00678               tos<<"          <th class=\"xAxis\">";
00679        else
00680               tos<<"          <th>";
00681        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
00682        tos<<"        </tr>\n";
00683        tos<<"      </thead>\n";
00684        tos<<"      <tbody>\n";
00685        
00686        QProgressDialog progress(parent);
00687        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
00688        progress.setLabelText(tr("Processing teachers with subjects...please wait"));
00689        progress.setRange(0, allSubjectsNames.count());
00690        progress.setModal(true);
00691        
00692        int ttt=0;
00693        
00694        foreach(QString subjects, allSubjectsNames){
00695               progress.setValue(ttt);
00696               //pqapplication->processEvents();
00697               if(progress.wasCanceled()){
00698                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
00699                      return false;
00700               }
00701               ttt++;
00702        
00703               QList<int> tmpSubjects;
00704               QMultiHash<QString, int> tmpTeachers;
00705               tmpSubjects.clear();
00706               tmpTeachers.clear();
00707               tmpSubjects=subjectsActivities.values(subjects);
00708               foreach(int aidx, tmpSubjects){
00709                      Activity* act=gt.rules.activitiesList.at(aidx);
00710                      foreach(QString teacher, act->teachersNames){
00711                             tmpTeachers.insert(teacher, aidx);
00712                      }
00713               }
00714               tos<<"        <tr>\n";
00715               if(TIMETABLE_HTML_LEVEL>=2)
00716                      tos<<"          <th class=\"yAxis\">";
00717               else
00718                      tos<<"          <th>";
00719               tos<<protect2(subjects)<<"</th>\n";
00720               foreach(QString teachers, allTeachersNames){
00721                      QList<int> tmpActivities;
00722                      tmpActivities.clear();
00723                      tmpActivities=tmpTeachers.values(teachers);
00724                      if(tmpActivities.isEmpty()){
00725                             switch(TIMETABLE_HTML_LEVEL){
00726                                    case 3 : ;
00727                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
00728                                    case 5 : ;
00729                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
00730                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
00731                             }
00732                      } else {
00733                             QMap<QString, int> tmpStudentDuration;    //not QHash, because i need the correct order of the activities
00734                             foreach(int tmpAct, tmpActivities){
00735                                    Activity* act=gt.rules.activitiesList[tmpAct];
00736                                    int tmpD=act->duration;
00737                                    QString tmpSt;
00738                                    if(act->studentsNames.size()>0){
00739                                           for(QStringList::Iterator st=act->studentsNames.begin(); st!=act->studentsNames.end(); st++){
00740                                                  switch(TIMETABLE_HTML_LEVEL){
00741                                                         case 4 : tmpSt+="<span class=\"ss_"+hashStudentIDsStatistics.value(*st)+"\">"+protect2(*st)+"</span>"; break;
00742                                                         case 5 : ;
00743                                                         case 6 : tmpSt+="<span class=\"ss_"+hashStudentIDsStatistics.value(*st)+"\" onmouseover=\"highlight('ss_"+hashStudentIDsStatistics.value(*st)+"')\">"+protect2(*st)+"</span>"; break;
00744                                                         default: tmpSt+=protect2(*st); break;
00745                                                         }
00746                                                  if(st!=act->studentsNames.end()-1)
00747                                                         tmpSt+=", ";
00748                                           }
00749                                    } else
00750                                           tmpSt=" ";
00751                                    tmpD+=tmpStudentDuration.value(tmpSt);
00752                                    tmpStudentDuration.insert(tmpSt, tmpD);
00753                             }
00754                             if(TIMETABLE_HTML_LEVEL>=1)
00755                                    tos<<"          <td><table class=\"detailed\">";
00756                             else
00757                                    tos<<"          <td><table>";
00758                             if(TIMETABLE_HTML_LEVEL>=3)
00759                                    tos<<"<tr class=\"duration line1\">";
00760                             else   tos<<"<tr>";
00761                             QMapIterator<QString, int> it(tmpStudentDuration);
00762                             while(it.hasNext()){
00763                                    it.next();
00764                                    if(TIMETABLE_HTML_LEVEL>=1)
00765                                           tos<<"<td class=\"detailed\">";
00766                                    else
00767                                           tos<<"<td>";
00768                                    tos<<it.value()<<"</td>";   
00769                             }
00770                             tos<<"</tr>";
00771                             if(TIMETABLE_HTML_LEVEL>=3)
00772                                    tos<<"<tr class=\"student line2\">";
00773                             else   tos<<"<tr>";
00774                             QMapIterator<QString, int> it2(tmpStudentDuration);     //do it with the same iterator
00775                             while(it2.hasNext()){
00776                                    it2.next();
00777                                    if(TIMETABLE_HTML_LEVEL>=1)
00778                                           tos<<"<td class=\"detailed\">";
00779                                    else
00780                                           tos<<"<td>";
00781                                    tos<<it2.key()<<"</td>";    
00782                             }
00783                             tos<<"</tr>";
00784                             tos<<"</table></td>\n";
00785                      }
00786               }
00787               tos<<"          <th>";
00788               tos<<CustomFETString::number(subjectsTotalNumberOfHours.value(subjects));
00789               if(subjectsTotalNumberOfHours.value(subjects)!=subjectsTotalNumberOfHours4.value(subjects))
00790                      tos<<"<br />("<<CustomFETString::number(subjectsTotalNumberOfHours4.value(subjects))<<")";
00791               tos<<"</th>\n";
00792               tos<<"        </tr>\n";
00793        }
00794        
00795        progress.setValue(allSubjectsNames.count());
00796        
00797        tos<<"        <tr>\n";
00798        if(TIMETABLE_HTML_LEVEL>=2)
00799               tos<<"          <th class=\"xAxis\">";
00800        else
00801               tos<<"          <th>";
00802        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
00803        foreach(QString teachers, allTeachersNames){
00804               tos<<"          <th>"<<CustomFETString::number(teachersTotalNumberOfHours.value(teachers));
00805               if(teachersTotalNumberOfHours.value(teachers)!=teachersTotalNumberOfHours2.value(teachers))
00806                      tos<<"<br />("<<CustomFETString::number(teachersTotalNumberOfHours2.value(teachers))<<")";
00807               tos<<"</th>\n";
00808        }
00809        tos<<"          <th></th>\n        </tr>\n";
00810        //workaround begin.
00811        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allTeachersNames.size()+1<<"\">"<<StatisticsExport::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";
00812        //workaround end.
00813        tos<<"      </tbody>\n";
00814        tos<<"    </table>\n";
00815        tos<<"  </body>\n</html>\n";
00816 
00817        if(file.error()>0){
00818               QMessageBox::critical(parent, tr("FET critical"),
00819                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
00820               return false;
00821        }
00822        file.close();
00823        return true;
00824 }
00825 
00826 bool StatisticsExport::exportStatisticsSubjectsTeachers(QWidget* parent, QString saveTime){
00827        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
00828        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00829 
00830        if(s2.right(4)==".fet")
00831               s2=s2.left(s2.length()-4);
00832        //else if(INPUT_FILENAME_XML!="")
00833        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00834 
00835        QString bar;
00836        if(INPUT_FILENAME_XML=="")
00837               bar="";
00838        else
00839               bar="_";
00840 
00841        QString htmlfilename=PREFIX_STATISTICS+s2+bar+SUBJECTS_TEACHERS_STATISTICS;
00842 
00843        QFile file(htmlfilename);
00844        if(!file.open(QIODevice::WriteOnly)){
00845               QMessageBox::critical(parent, tr("FET critical"),
00846                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
00847               return false;
00848               assert(0);
00849        }
00850        QTextStream tos(&file);
00851        tos.setCodec("UTF-8");
00852        tos.setGenerateByteOrderMark(true);
00853 
00854        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
00855        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
00856 
00857        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
00858               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
00859        else
00860               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
00861        tos<<"  <head>\n";
00862        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
00863        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
00864        if(TIMETABLE_HTML_LEVEL>=1){
00865               QString bar;
00866               if(INPUT_FILENAME_XML=="")
00867                      bar="";
00868               else
00869                      bar="_";
00870        
00871               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
00872               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
00873        }
00874        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
00875               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
00876               tos<<"    <script type=\"text/javascript\">\n";
00877               tos<<"      function highlight(classval) {\n";
00878               tos<<"        var spans = document.getElementsByTagName('span');\n";
00879               tos<<"        for(var i=0;spans.length>i;i++) {\n";
00880               tos<<"          if (spans[i].className == classval) {\n";
00881               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
00882               tos<<"          } else {\n";
00883               tos<<"            spans[i].style.backgroundColor = 'white';\n";
00884               tos<<"          }\n";
00885               tos<<"        }\n";
00886               tos<<"      }\n";
00887               tos<<"    </script>\n";
00888        }
00889        tos<<"  </head>\n\n";
00890 
00891        tos<<"  <body>\n";
00892        tos<<"    <table border=\"1\">\n"; 
00893        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
00894        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allSubjectsNames.size()+1<<"\">"<<tr("Subjects - Teachers Matrix")<<"</th></tr>\n";
00895        tos<<"        <tr>\n          <!-- span -->\n";
00896        foreach(QString subjects, allSubjectsNames){
00897               if(TIMETABLE_HTML_LEVEL>=2)
00898                      tos<<"          <th class=\"xAxis\">";
00899               else
00900                      tos<<"          <th>";
00901               tos<<protect2(subjects)<<"</th>\n";
00902        }
00903        if(TIMETABLE_HTML_LEVEL>=2)
00904               tos<<"          <th class=\"xAxis\">";
00905        else
00906               tos<<"          <th>";
00907        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
00908        tos<<"        </tr>\n";
00909        tos<<"      </thead>\n";
00910        tos<<"      <tbody>\n";
00911        
00912        QProgressDialog progress(parent);
00913        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
00914        progress.setLabelText(tr("Processing subject with teachers...please wait"));
00915        progress.setRange(0, allTeachersNames.count());
00916        progress.setModal(true);
00917        
00918        int ttt=0;
00919        
00920        foreach(QString teachers, allTeachersNames){
00921               progress.setValue(ttt);
00922               //pqapplication->processEvents();
00923               if(progress.wasCanceled()){
00924                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
00925                      return false;
00926               }
00927               ttt++;
00928        
00929               QList<int> tmpTeachers;
00930               QMultiHash<QString, int> tmpSubjects;
00931               tmpTeachers.clear();
00932               tmpSubjects.clear();
00933               tmpTeachers=teachersActivities.values(teachers);
00934               foreach(int aidx, tmpTeachers){
00935                      Activity* act=gt.rules.activitiesList.at(aidx);
00936                      tmpSubjects.insert(act->subjectName, aidx);
00937               }
00938               tos<<"        <tr>\n";
00939               if(TIMETABLE_HTML_LEVEL>=2)
00940                      tos<<"          <th class=\"yAxis\">";
00941               else
00942                      tos<<"          <th>";
00943               tos<<protect2(teachers)<<"</th>\n";
00944               foreach(QString subjects, allSubjectsNames){
00945                      QList<int> tmpActivities;
00946                      tmpActivities.clear();
00947                      tmpActivities=tmpSubjects.values(subjects);
00948                      if(tmpActivities.isEmpty()){
00949                             switch(TIMETABLE_HTML_LEVEL){
00950                                    case 3 : ;
00951                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
00952                                    case 5 : ;
00953                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
00954                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
00955                             }
00956                      } else {
00957                             QMap<QString, int> tmpStudentDuration;    //not QHash, because i need the correct order of the activities
00958                             foreach(int tmpAct, tmpActivities){
00959                                    Activity* act=gt.rules.activitiesList[tmpAct];
00960                                    int tmpD=act->duration;
00961                                    QString tmpSt;
00962                                    if(act->studentsNames.size()>0){
00963                                           for(QStringList::Iterator st=act->studentsNames.begin(); st!=act->studentsNames.end(); st++){
00964                                                  switch(TIMETABLE_HTML_LEVEL){
00965                                                         case 4 : tmpSt+="<span class=\"ss_"+hashStudentIDsStatistics.value(*st)+"\">"+protect2(*st)+"</span>"; break;
00966                                                         case 5 : ;
00967                                                         case 6 : tmpSt+="<span class=\"ss_"+hashStudentIDsStatistics.value(*st)+"\" onmouseover=\"highlight('ss_"+hashStudentIDsStatistics.value(*st)+"')\">"+protect2(*st)+"</span>"; break;
00968                                                         default: tmpSt+=protect2(*st); break;
00969                                                         }
00970                                                  if(st!=act->studentsNames.end()-1)
00971                                                         tmpSt+=", ";
00972                                           }
00973                                    } else
00974                                           tmpSt=" ";
00975                                    tmpD+=tmpStudentDuration.value(tmpSt);
00976                                    tmpStudentDuration.insert(tmpSt, tmpD);
00977                             }
00978                             if(TIMETABLE_HTML_LEVEL>=1)
00979                                    tos<<"          <td><table class=\"detailed\">";
00980                             else
00981                                    tos<<"          <td><table>";
00982                             if(TIMETABLE_HTML_LEVEL>=3)
00983                                    tos<<"<tr class=\"duration line1\">";
00984                             else   tos<<"<tr>";
00985                             QMapIterator<QString, int> it(tmpStudentDuration);
00986                             while(it.hasNext()){
00987                                    it.next();
00988                                    if(TIMETABLE_HTML_LEVEL>=1)
00989                                           tos<<"<td class=\"detailed\">";
00990                                    else
00991                                           tos<<"<td>";
00992                                    tos<<it.value()<<"</td>";   
00993                             }
00994                             tos<<"</tr>";
00995                             if(TIMETABLE_HTML_LEVEL>=3)
00996                                    tos<<"<tr class=\"student line2\">";
00997                             else   tos<<"<tr>";
00998                             QMapIterator<QString, int> it2(tmpStudentDuration);     //do it with the same iterator
00999                             while(it2.hasNext()){
01000                                    it2.next();
01001                                    if(TIMETABLE_HTML_LEVEL>=1)
01002                                           tos<<"<td class=\"detailed\">";
01003                                    else
01004                                           tos<<"<td>";
01005                                    tos<<it2.key()<<"</td>";    
01006                             }
01007                             tos<<"</tr>";
01008                             tos<<"</table></td>\n";
01009                      }
01010               }
01011               tos<<"          <th>";
01012               tos<<CustomFETString::number(teachersTotalNumberOfHours.value(teachers));
01013               if(teachersTotalNumberOfHours.value(teachers)!=teachersTotalNumberOfHours2.value(teachers))
01014                      tos<<"<br />("<<CustomFETString::number(teachersTotalNumberOfHours2.value(teachers))<<")";
01015               tos<<"</th>\n";
01016               tos<<"        </tr>\n";
01017        }
01018        
01019        progress.setValue(allTeachersNames.count());
01020        
01021        tos<<"        <tr>\n";
01022        if(TIMETABLE_HTML_LEVEL>=2)
01023               tos<<"          <th class=\"xAxis\">";
01024        else
01025               tos<<"          <th>";
01026        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01027        foreach(QString subjects, allSubjectsNames){
01028               tos<<"          <th>"<<CustomFETString::number(subjectsTotalNumberOfHours.value(subjects));
01029               if(subjectsTotalNumberOfHours.value(subjects)!=subjectsTotalNumberOfHours4.value(subjects))
01030                      tos<<"<br />("<<CustomFETString::number(subjectsTotalNumberOfHours4.value(subjects))<<")";
01031               tos<<"</th>\n";
01032        }
01033        tos<<"          <th></th>\n        </tr>\n";
01034        //workaround begin.
01035        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allSubjectsNames.size()+1<<"\">"<<StatisticsExport::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";
01036        //workaround end.
01037        tos<<"      </tbody>\n";
01038        tos<<"    </table>\n";
01039        tos<<"  </body>\n</html>\n";
01040 
01041        if(file.error()>0){
01042               QMessageBox::critical(parent, tr("FET critical"),
01043                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
01044               return false;
01045        }
01046        file.close();
01047        return true;
01048 }
01049 
01050 bool StatisticsExport::exportStatisticsTeachersStudents(QWidget* parent, QString saveTime){
01051        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
01052        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
01053 
01054        if(s2.right(4)==".fet")
01055               s2=s2.left(s2.length()-4);
01056        //else if(INPUT_FILENAME_XML!="")
01057        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
01058 
01059        QString bar;
01060        if(INPUT_FILENAME_XML=="")
01061               bar="";
01062        else
01063               bar="_";
01064 
01065        QString htmlfilename=PREFIX_STATISTICS+s2+bar+TEACHERS_STUDENTS_STATISTICS;
01066 
01067        QFile file(htmlfilename);
01068        if(!file.open(QIODevice::WriteOnly)){
01069               QMessageBox::critical(parent, tr("FET critical"),
01070                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
01071               return false;
01072               assert(0);
01073        }
01074        QTextStream tos(&file);
01075        tos.setCodec("UTF-8");
01076        tos.setGenerateByteOrderMark(true);
01077 
01078        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
01079        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
01080 
01081        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
01082               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
01083        else
01084               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
01085        tos<<"  <head>\n";
01086        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
01087        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
01088        if(TIMETABLE_HTML_LEVEL>=1){
01089               QString bar;
01090               if(INPUT_FILENAME_XML=="")
01091                      bar="";
01092               else
01093                      bar="_";
01094        
01095               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
01096               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
01097        }
01098        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
01099               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
01100               tos<<"    <script type=\"text/javascript\">\n";
01101               tos<<"      function highlight(classval) {\n";
01102               tos<<"        var spans = document.getElementsByTagName('span');\n";
01103               tos<<"        for(var i=0;spans.length>i;i++) {\n";
01104               tos<<"          if (spans[i].className == classval) {\n";
01105               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
01106               tos<<"          } else {\n";
01107               tos<<"            spans[i].style.backgroundColor = 'white';\n";
01108               tos<<"          }\n";
01109               tos<<"        }\n";
01110               tos<<"      }\n";
01111               tos<<"    </script>\n";
01112        }
01113        tos<<"  </head>\n\n";
01114 
01115        tos<<"  <body>\n";
01116        tos<<"    <table border=\"1\">\n"; 
01117        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
01118        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allTeachersNames.size()+1<<"\">"<<tr("Teachers - Students Matrix")<<"</th></tr>\n";
01119        tos<<"        <tr>\n          <!-- span -->\n";
01120        foreach(QString teachers, allTeachersNames){
01121               if(TIMETABLE_HTML_LEVEL>=2)
01122                      tos<<"          <th class=\"xAxis\">";
01123               else
01124                      tos<<"          <th>";
01125               tos<<protect2(teachers)<<"</th>\n";
01126        }
01127        if(TIMETABLE_HTML_LEVEL>=2)
01128               tos<<"          <th class=\"xAxis\">";
01129        else
01130               tos<<"          <th>";
01131        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01132        tos<<"        </tr>\n";
01133        tos<<"      </thead>\n";
01134        tos<<"      <tbody>\n";
01135        
01136        QProgressDialog progress(parent);
01137        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
01138        progress.setLabelText(tr("Processing teachers with students...please wait"));
01139        progress.setRange(0, allStudentsNames.count());
01140        progress.setModal(true);
01141        
01142        int ttt=0;
01143        
01144        foreach(QString students, allStudentsNames){
01145               progress.setValue(ttt);
01146               //pqapplication->processEvents();
01147               if(progress.wasCanceled()){
01148                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
01149                      return false;
01150               }
01151               ttt++;
01152        
01153               QList<int> tmpStudents;
01154               QMultiHash<QString, int> tmpTeachers;
01155               tmpStudents.clear();
01156               tmpTeachers.clear();
01157               tmpStudents=studentsActivities.values(students);
01158               foreach(int aidx, tmpStudents){
01159                      Activity* act=gt.rules.activitiesList.at(aidx);
01160                      foreach(QString teacher, act->teachersNames){
01161                             tmpTeachers.insert(teacher, aidx);
01162                      }
01163               }
01164               tos<<"        <tr>\n";
01165               if(TIMETABLE_HTML_LEVEL>=2)
01166                      tos<<"          <th class=\"yAxis\">";
01167               else
01168                      tos<<"          <th>";
01169               tos<<protect2(students)<<"</th>\n";
01170               foreach(QString teachers, allTeachersNames){
01171                      QList<int> tmpActivities;
01172                      tmpActivities.clear();
01173                      tmpActivities=tmpTeachers.values(teachers);
01174                      if(tmpActivities.isEmpty()){
01175                             switch(TIMETABLE_HTML_LEVEL){
01176                                    case 3 : ;
01177                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01178                                    case 5 : ;
01179                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01180                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
01181                             }
01182                      } else {
01183                             QMap<QString, int> tmpSubjectDuration;    //not QHash, because i need the correct order of the activities
01184                             foreach(int tmpAct, tmpActivities){
01185                                    Activity* act=gt.rules.activitiesList[tmpAct];
01186                                    int tmpD=act->duration;
01187                                    QString tmpS;
01188                                    if(act->subjectName.size()>0||act->activityTagsNames.size()>0){
01189                                           if(act->subjectName.size()>0)
01190                                                  switch(TIMETABLE_HTML_LEVEL){
01191                                                         case 3 : tmpS+="<span class=\"subject\">"+protect2(act->subjectName)+"</span>"; break;
01192                                                         case 4 : tmpS+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsStatistics.value(act->subjectName)+"\">"+protect2(act->subjectName)+"</span></span>"; break;
01193                                                         case 5 : ;
01194                                                         case 6 : tmpS+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsStatistics.value(act->subjectName)+"\" onmouseover=\"highlight('s_"+hashSubjectIDsStatistics.value(act->subjectName)+"')\">"+protect2(act->subjectName)+"</span></span>"; break;
01195                                                         default: tmpS+=protect2(act->subjectName); break;
01196                                                  }
01197                                           for(QStringList::Iterator atn=act->activityTagsNames.begin(); atn!=act->activityTagsNames.end(); atn++){
01198                                                  switch(TIMETABLE_HTML_LEVEL){
01199                                                         case 3 : tmpS+=" <span class=\"activitytag\">"+protect2(*atn)+"</span>"; break;
01200                                                         case 4 : tmpS+=" <span class=\"activitytag\"><span class=\"at_"+hashActivityTagIDsStatistics.value(*atn)+"\">"+protect2(*atn)+"</span></span>"; break;
01201                                                         case 5 : ;
01202                                                         case 6 : tmpS+=" <span class=\"activitytag\"><span class=\"at_"+hashActivityTagIDsStatistics.value(*atn)+"\" onmouseover=\"highlight('at_"+hashActivityTagIDsStatistics.value(*atn)+"')\">"+protect2(*atn)+"</span></span>"; break;
01203                                                         default: tmpS+=" "+protect2(*atn); break;
01204                                                  }
01205                                                  if(atn!=act->activityTagsNames.end()-1)
01206                                                         tmpS+=", ";
01207                                           }
01208                                    } else
01209                                           tmpS=" ";
01210                                    tmpD+=tmpSubjectDuration.value(tmpS);
01211                                    tmpSubjectDuration.insert(tmpS, tmpD);
01212                             }
01213                             if(TIMETABLE_HTML_LEVEL>=1)
01214                                    tos<<"          <td><table class=\"detailed\">";
01215                             else
01216                                    tos<<"          <td><table>";
01217                             if(TIMETABLE_HTML_LEVEL>=3)
01218                                    tos<<"<tr class=\"duration line1\">";
01219                             else   tos<<"<tr>";
01220                             QMapIterator<QString, int> it(tmpSubjectDuration);
01221                             while(it.hasNext()){
01222                                    it.next();
01223                                    if(TIMETABLE_HTML_LEVEL>=1)
01224                                           tos<<"<td class=\"detailed\">";
01225                                    else
01226                                           tos<<"<td>";
01227                                    tos<<it.value()<<"</td>";   
01228                             }
01229                             tos<<"</tr>";
01230                             if(TIMETABLE_HTML_LEVEL>=3)
01231                                    tos<<"<tr class=\"subject line2\">";
01232                             else   tos<<"<tr>";
01233                             QMapIterator<QString, int> it2(tmpSubjectDuration);     //do it with the same iterator
01234                             while(it2.hasNext()){
01235                                    it2.next();
01236                                    if(TIMETABLE_HTML_LEVEL>=1)
01237                                           tos<<"<td class=\"detailed\">";
01238                                    else
01239                                           tos<<"<td>";
01240                                    tos<<it2.key()<<"</td>";    
01241                             }
01242                             tos<<"</tr>";
01243                             tos<<"</table></td>\n";
01244                      }
01245               }
01246               tos<<"          <th>";
01247               tos<<CustomFETString::number(studentsTotalNumberOfHours.value(students));
01248               if(studentsTotalNumberOfHours.value(students)!=studentsTotalNumberOfHours2.value(students))
01249                      tos<<"<br />("<<CustomFETString::number(studentsTotalNumberOfHours2.value(students))<<")";
01250               tos<<"</th>\n";
01251               tos<<"        </tr>\n";
01252        }
01253        
01254        progress.setValue(allStudentsNames.count());
01255        
01256        tos<<"        <tr>\n";
01257        if(TIMETABLE_HTML_LEVEL>=2)
01258               tos<<"          <th class=\"xAxis\">";
01259        else
01260               tos<<"          <th>";
01261        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01262        foreach(QString teachers, allTeachersNames){
01263               tos<<"          <th>"<<CustomFETString::number(teachersTotalNumberOfHours.value(teachers));
01264               if(teachersTotalNumberOfHours.value(teachers)!=teachersTotalNumberOfHours2.value(teachers))
01265                      tos<<"<br />("<<CustomFETString::number(teachersTotalNumberOfHours2.value(teachers))<<")";
01266               tos<<"</th>\n";
01267        }
01268        tos<<"          <th></th>\n        </tr>\n";
01269        //workaround begin.
01270        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allTeachersNames.size()+1<<"\">"<<StatisticsExport::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";
01271        //workaround end.
01272        tos<<"      </tbody>\n";
01273        tos<<"    </table>\n";
01274        tos<<"  </body>\n</html>\n";
01275 
01276        if(file.error()>0){
01277               QMessageBox::critical(parent, tr("FET critical"),
01278                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
01279               return false;
01280        }
01281        file.close();
01282        return true;
01283 }
01284 
01285 bool StatisticsExport::exportStatisticsStudentsTeachers(QWidget* parent, QString saveTime){
01286        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
01287        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
01288 
01289        if(s2.right(4)==".fet")
01290               s2=s2.left(s2.length()-4);
01291        //else if(INPUT_FILENAME_XML!="")
01292        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
01293 
01294        QString bar;
01295        if(INPUT_FILENAME_XML=="")
01296               bar="";
01297        else
01298               bar="_";
01299 
01300        QString htmlfilename=PREFIX_STATISTICS+s2+bar+STUDENTS_TEACHERS_STATISTICS;
01301 
01302        QFile file(htmlfilename);
01303        if(!file.open(QIODevice::WriteOnly)){
01304               QMessageBox::critical(parent, tr("FET critical"),
01305                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
01306               return false;
01307               assert(0);
01308        }
01309        QTextStream tos(&file);
01310        tos.setCodec("UTF-8");
01311        tos.setGenerateByteOrderMark(true);
01312 
01313        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
01314        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
01315 
01316        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
01317               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
01318        else
01319               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
01320        tos<<"  <head>\n";
01321        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
01322        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
01323        if(TIMETABLE_HTML_LEVEL>=1){
01324               QString bar;
01325               if(INPUT_FILENAME_XML=="")
01326                      bar="";
01327               else
01328                      bar="_";
01329        
01330               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
01331               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
01332        }
01333        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
01334               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
01335               tos<<"    <script type=\"text/javascript\">\n";
01336               tos<<"      function highlight(classval) {\n";
01337               tos<<"        var spans = document.getElementsByTagName('span');\n";
01338               tos<<"        for(var i=0;spans.length>i;i++) {\n";
01339               tos<<"          if (spans[i].className == classval) {\n";
01340               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
01341               tos<<"          } else {\n";
01342               tos<<"            spans[i].style.backgroundColor = 'white';\n";
01343               tos<<"          }\n";
01344               tos<<"        }\n";
01345               tos<<"      }\n";
01346               tos<<"    </script>\n";
01347        }
01348        tos<<"  </head>\n\n";
01349 
01350        tos<<"  <body>\n";
01351        tos<<"    <table border=\"1\">\n"; 
01352        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
01353        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allStudentsNames.size()+1<<"\">"<<tr("Students -Teachers Matrix")<<"</th></tr>\n";
01354        tos<<"        <tr>\n          <!-- span -->\n";
01355        foreach(QString students, allStudentsNames){
01356               if(TIMETABLE_HTML_LEVEL>=2)
01357                      tos<<"          <th class=\"xAxis\">";
01358               else
01359                      tos<<"          <th>";
01360               tos<<protect2(students)<<"</th>\n";
01361        }
01362        if(TIMETABLE_HTML_LEVEL>=2)
01363               tos<<"          <th class=\"xAxis\">";
01364        else
01365               tos<<"          <th>";
01366        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01367        tos<<"        </tr>\n";
01368        tos<<"      </thead>\n";
01369        tos<<"      <tbody>\n";
01370        
01371        QProgressDialog progress(parent);
01372        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
01373        progress.setLabelText(tr("Processing students with teachers...please wait"));
01374        progress.setRange(0, allTeachersNames.count());
01375        progress.setModal(true);
01376        
01377        int ttt=0;
01378        
01379        foreach(QString teachers, allTeachersNames){
01380               progress.setValue(ttt);
01381               //pqapplication->processEvents();
01382               if(progress.wasCanceled()){
01383                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
01384                      return false;
01385               }
01386               ttt++;
01387        
01388               QList<int> tmpTeachers;
01389               QMultiHash<QString, int> tmpStudents;
01390               tmpTeachers.clear();
01391               tmpStudents.clear();
01392               tmpTeachers=teachersActivities.values(teachers);
01393               foreach(int aidx, tmpTeachers){
01394                      Activity* act=gt.rules.activitiesList.at(aidx);
01395                      foreach(QString students, act->studentsNames){
01396                             tmpStudents.insert(students, aidx);
01397                      }
01398               }
01399               tos<<"        <tr>\n";
01400               if(TIMETABLE_HTML_LEVEL>=2)
01401                      tos<<"          <th class=\"yAxis\">";
01402               else
01403                      tos<<"          <th>";
01404               tos<<protect2(teachers)<<"</th>\n";
01405               foreach(QString students, allStudentsNames){
01406                      QList<int> tmpActivities;
01407                      tmpActivities.clear();
01408                      tmpActivities=tmpStudents.values(students);
01409                      if(tmpActivities.isEmpty()){
01410                             switch(TIMETABLE_HTML_LEVEL){
01411                                    case 3 : ;
01412                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01413                                    case 5 : ;
01414                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01415                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
01416                             }
01417                      } else {
01418                             QMap<QString, int> tmpSubjectDuration;    //not QHash, because i need the correct order of the activities
01419                             foreach(int tmpAct, tmpActivities){
01420                                    Activity* act=gt.rules.activitiesList[tmpAct];
01421                                    int tmpD=act->duration;
01422                                    QString tmpS;
01423                                    if(act->subjectName.size()>0||act->activityTagsNames.size()>0){
01424                                           if(act->subjectName.size()>0)
01425                                                  switch(TIMETABLE_HTML_LEVEL){
01426                                                         case 3 : tmpS+="<span class=\"subject\">"+protect2(act->subjectName)+"</span>"; break;
01427                                                         case 4 : tmpS+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsStatistics.value(act->subjectName)+"\">"+protect2(act->subjectName)+"</span></span>"; break;
01428                                                         case 5 : ;
01429                                                         case 6 : tmpS+="<span class=\"subject\"><span class=\"s_"+hashSubjectIDsStatistics.value(act->subjectName)+"\" onmouseover=\"highlight('s_"+hashSubjectIDsStatistics.value(act->subjectName)+"')\">"+protect2(act->subjectName)+"</span></span>"; break;
01430                                                         default: tmpS+=protect2(act->subjectName); break;
01431                                                  }
01432                                           for(QStringList::Iterator atn=act->activityTagsNames.begin(); atn!=act->activityTagsNames.end(); atn++){
01433                                                  switch(TIMETABLE_HTML_LEVEL){
01434                                                         case 3 : tmpS+=" <span class=\"activitytag\">"+protect2(*atn)+"</span>"; break;
01435                                                         case 4 : tmpS+=" <span class=\"activitytag\"><span class=\"at_"+hashActivityTagIDsStatistics.value(*atn)+"\">"+protect2(*atn)+"</span></span>"; break;
01436                                                         case 5 : ;
01437                                                         case 6 : tmpS+=" <span class=\"activitytag\"><span class=\"at_"+hashActivityTagIDsStatistics.value(*atn)+"\" onmouseover=\"highlight('at_"+hashActivityTagIDsStatistics.value(*atn)+"')\">"+protect2(*atn)+"</span></span>"; break;
01438                                                         default: tmpS+=" "+protect2(*atn); break;
01439                                                  }
01440                                                  if(atn!=act->activityTagsNames.end()-1)
01441                                                         tmpS+=", ";
01442                                           }
01443                                    } else
01444                                           tmpS=" ";
01445                                    tmpD+=tmpSubjectDuration.value(tmpS);
01446                                    tmpSubjectDuration.insert(tmpS, tmpD);
01447                             }
01448                             if(TIMETABLE_HTML_LEVEL>=1)
01449                                    tos<<"          <td><table class=\"detailed\">";
01450                             else
01451                                    tos<<"          <td><table>";
01452                             if(TIMETABLE_HTML_LEVEL>=3)
01453                                    tos<<"<tr class=\"duration line1\">";
01454                             else   tos<<"<tr>";
01455                             QMapIterator<QString, int> it(tmpSubjectDuration);
01456                             while(it.hasNext()){
01457                                    it.next();
01458                                    if(TIMETABLE_HTML_LEVEL>=1)
01459                                           tos<<"<td class=\"detailed\">";
01460                                    else
01461                                           tos<<"<td>";
01462                                    tos<<it.value()<<"</td>";   
01463                             }
01464                             tos<<"</tr>";
01465                             if(TIMETABLE_HTML_LEVEL>=3)
01466                                    tos<<"<tr class=\"subject line2\">";
01467                             else   tos<<"<tr>";
01468                             QMapIterator<QString, int> it2(tmpSubjectDuration);     //do it with the same iterator
01469                             while(it2.hasNext()){
01470                                    it2.next();
01471                                    if(TIMETABLE_HTML_LEVEL>=1)
01472                                           tos<<"<td class=\"detailed\">";
01473                                    else
01474                                           tos<<"<td>";
01475                                    tos<<it2.key()<<"</td>";    
01476                             }
01477                             tos<<"</tr>";
01478                             tos<<"</table></td>\n";
01479                      }
01480               }
01481               tos<<"          <th>";
01482               tos<<CustomFETString::number(teachersTotalNumberOfHours.value(teachers));
01483               if(teachersTotalNumberOfHours.value(teachers)!=teachersTotalNumberOfHours2.value(teachers))
01484                      tos<<"<br />("<<CustomFETString::number(teachersTotalNumberOfHours2.value(teachers))<<")";
01485               tos<<"</th>\n";
01486               tos<<"        </tr>\n";
01487        }
01488        
01489        progress.setValue(allTeachersNames.count());
01490        
01491        tos<<"        <tr>\n";
01492        if(TIMETABLE_HTML_LEVEL>=2)
01493               tos<<"          <th class=\"xAxis\">";
01494        else
01495               tos<<"          <th>";
01496        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01497        foreach(QString students, allStudentsNames){
01498               tos<<"          <th>"<<CustomFETString::number(studentsTotalNumberOfHours.value(students));
01499               if(studentsTotalNumberOfHours.value(students)!=studentsTotalNumberOfHours2.value(students))
01500                      tos<<"<br />("<<CustomFETString::number(studentsTotalNumberOfHours2.value(students))<<")";
01501               tos<<"</th>\n";
01502        }
01503        tos<<"          <th></th>\n        </tr>\n";
01504        //workaround begin.
01505        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allStudentsNames.size()+1<<"\">"<<StatisticsExport::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";
01506        //workaround end.
01507        tos<<"      </tbody>\n";
01508        tos<<"    </table>\n";
01509        tos<<"  </body>\n</html>\n";
01510 
01511        if(file.error()>0){
01512               QMessageBox::critical(parent, tr("FET critical"),
01513                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
01514               return false;
01515        }
01516        file.close();
01517        return true;
01518 }
01519 
01520 bool StatisticsExport::exportStatisticsSubjectsStudents(QWidget* parent, QString saveTime){
01521        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
01522        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
01523 
01524        if(s2.right(4)==".fet")
01525               s2=s2.left(s2.length()-4);
01526        //else if(INPUT_FILENAME_XML!="")
01527        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
01528 
01529        QString bar;
01530        if(INPUT_FILENAME_XML=="")
01531               bar="";
01532        else
01533               bar="_";
01534 
01535        QString htmlfilename=PREFIX_STATISTICS+s2+bar+SUBJECTS_STUDENTS_STATISTICS;
01536 
01537        QFile file(htmlfilename);
01538        if(!file.open(QIODevice::WriteOnly)){
01539               QMessageBox::critical(parent, tr("FET critical"),
01540                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
01541               return false;
01542               assert(0);
01543        }
01544        QTextStream tos(&file);
01545        tos.setCodec("UTF-8");
01546        tos.setGenerateByteOrderMark(true);
01547 
01548        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
01549        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
01550 
01551        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
01552               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
01553        else
01554               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
01555        tos<<"  <head>\n";
01556        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
01557        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
01558        if(TIMETABLE_HTML_LEVEL>=1){
01559               QString bar;
01560               if(INPUT_FILENAME_XML=="")
01561                      bar="";
01562               else
01563                      bar="_";
01564        
01565               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
01566               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
01567        }
01568        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
01569               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
01570               tos<<"    <script type=\"text/javascript\">\n";
01571               tos<<"      function highlight(classval) {\n";
01572               tos<<"        var spans = document.getElementsByTagName('span');\n";
01573               tos<<"        for(var i=0;spans.length>i;i++) {\n";
01574               tos<<"          if (spans[i].className == classval) {\n";
01575               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
01576               tos<<"          } else {\n";
01577               tos<<"            spans[i].style.backgroundColor = 'white';\n";
01578               tos<<"          }\n";
01579               tos<<"        }\n";
01580               tos<<"      }\n";
01581               tos<<"    </script>\n";
01582        }
01583        tos<<"  </head>\n\n";
01584 
01585        tos<<"  <body>\n";
01586        tos<<"    <table border=\"1\">\n"; 
01587        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
01588        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allSubjectsNames.size()+1<<"\">"<<tr("Subjects - Students Matrix")<<"</th></tr>\n";
01589        tos<<"        <tr>\n          <!-- span -->\n";
01590        foreach(QString subjects, allSubjectsNames){
01591               if(TIMETABLE_HTML_LEVEL>=2)
01592                      tos<<"          <th class=\"xAxis\">";
01593               else
01594                      tos<<"          <th>";
01595               tos<<protect2(subjects)<<"</th>\n";
01596        }
01597        if(TIMETABLE_HTML_LEVEL>=2)
01598               tos<<"          <th class=\"xAxis\">";
01599        else
01600               tos<<"          <th>";
01601        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01602        tos<<"        </tr>\n";
01603        tos<<"      </thead>\n";
01604        tos<<"      <tbody>\n";
01605        
01606        QProgressDialog progress(parent);
01607        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
01608        progress.setLabelText(tr("Processing subjects with students...please wait"));
01609        progress.setRange(0, allStudentsNames.count());
01610        progress.setModal(true);
01611        
01612        int ttt=0;
01613        
01614        foreach(QString students, allStudentsNames){
01615               progress.setValue(ttt);
01616               //pqapplication->processEvents();
01617               if(progress.wasCanceled()){
01618                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
01619                      return false;
01620               }
01621               ttt++;
01622        
01623               QList<int> tmpStudents;
01624               QMultiHash<QString, int> tmpSubjects;
01625               tmpStudents.clear();
01626               tmpSubjects.clear();
01627               tmpStudents=studentsActivities.values(students);
01628               foreach(int aidx, tmpStudents){
01629                      Activity* act=gt.rules.activitiesList.at(aidx);
01630                      tmpSubjects.insert(act->subjectName, aidx);
01631               }
01632               tos<<"        <tr>\n";
01633               if(TIMETABLE_HTML_LEVEL>=2)
01634                      tos<<"          <th class=\"yAxis\">";
01635               else
01636                      tos<<"          <th>";
01637               tos<<protect2(students)<<"</th>\n";
01638               foreach(QString subjects, allSubjectsNames){
01639                      QList<int> tmpActivities;
01640                      tmpActivities.clear();
01641                      tmpActivities=tmpSubjects.values(subjects);
01642                      if(tmpActivities.isEmpty()){
01643                             switch(TIMETABLE_HTML_LEVEL){
01644                                    case 3 : ;
01645                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01646                                    case 5 : ;
01647                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01648                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
01649                             }
01650                      } else {
01651                             QMap<QString, int> tmpTeacherDuration;    //not QHash, because i need the correct order of the activities
01652                             foreach(int tmpAct, tmpActivities){
01653                                    Activity* act=gt.rules.activitiesList[tmpAct];
01654                                    int tmpD=act->duration;
01655                                    QString tmpT;
01656                                    if(act->teachersNames.size()>0){
01657                                           for(QStringList::Iterator it=act->teachersNames.begin(); it!=act->teachersNames.end(); it++){
01658                                                  switch(TIMETABLE_HTML_LEVEL){
01659                                                         case 4 : tmpT+="<span class=\"t_"+hashTeacherIDsStatistics.value(*it)+"\">"+protect2(*it)+"</span>"; break;
01660                                                         case 5 : ;
01661                                                         case 6 : tmpT+="<span class=\"t_"+hashTeacherIDsStatistics.value(*it)+"\" onmouseover=\"highlight('t_"+hashTeacherIDsStatistics.value(*it)+"')\">"+protect2(*it)+"</span>"; break;
01662                                                         default: tmpT+=protect2(*it); break;
01663                                                  }
01664                                                  if(it!=act->teachersNames.end()-1)
01665                                                         tmpT+=", ";
01666                                           }
01667                                    } else
01668                                           tmpT=" ";
01669                                    tmpD+=tmpTeacherDuration.value(tmpT);
01670                                    tmpTeacherDuration.insert(tmpT, tmpD);
01671                             }
01672                             if(TIMETABLE_HTML_LEVEL>=1)
01673                                    tos<<"          <td><table class=\"detailed\">";
01674                             else
01675                                    tos<<"          <td><table>";
01676                             if(TIMETABLE_HTML_LEVEL>=3)
01677                                    tos<<"<tr class=\"duration line1\">";
01678                             else   tos<<"<tr>";
01679                             QMapIterator<QString, int> it(tmpTeacherDuration);
01680                             while(it.hasNext()){
01681                                    it.next();
01682                                    if(TIMETABLE_HTML_LEVEL>=1)
01683                                           tos<<"<td class=\"detailed\">";
01684                                    else
01685                                           tos<<"<td>";
01686                                    tos<<it.value()<<"</td>";   
01687                             }
01688                             tos<<"</tr>";
01689                             if(TIMETABLE_HTML_LEVEL>=3)
01690                                    tos<<"<tr class=\"teacher line2\">";
01691                             else   tos<<"<tr>";
01692                             QMapIterator<QString, int> it2(tmpTeacherDuration);     //do it with the same iterator
01693                             while(it2.hasNext()){
01694                                    it2.next();
01695                                    if(TIMETABLE_HTML_LEVEL>=1)
01696                                           tos<<"<td class=\"detailed\">";
01697                                    else
01698                                           tos<<"<td>";
01699                                    tos<<it2.key()<<"</td>";    
01700                             }
01701                             tos<<"</tr>";
01702                             tos<<"</table></td>\n";
01703                      }
01704               }
01705               tos<<"          <th>";
01706               tos<<CustomFETString::number(studentsTotalNumberOfHours.value(students));
01707               if(studentsTotalNumberOfHours.value(students)!=studentsTotalNumberOfHours2.value(students))
01708                      tos<<"<br />("<<CustomFETString::number(studentsTotalNumberOfHours2.value(students))<<")";
01709               tos<<"</th>\n";
01710               tos<<"        </tr>\n";
01711        }
01712        
01713        progress.setValue(allStudentsNames.count());
01714 
01715        tos<<"        <tr>\n";
01716        if(TIMETABLE_HTML_LEVEL>=2)
01717               tos<<"          <th class=\"xAxis\">";
01718        else
01719               tos<<"          <th>";
01720        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01721        foreach(QString subjects, allSubjectsNames){
01722               tos<<"          <th>"<<CustomFETString::number(subjectsTotalNumberOfHours.value(subjects));
01723               if(subjectsTotalNumberOfHours.value(subjects)!=subjectsTotalNumberOfHours4.value(subjects))
01724                      tos<<"<br />("<<CustomFETString::number(subjectsTotalNumberOfHours4.value(subjects))<<")";
01725               tos<<"</th>\n";
01726        }
01727        tos<<"          <th></th>\n        </tr>\n";
01728        //workaround begin.
01729        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allTeachersNames.size()+1<<"\">"<<StatisticsExport::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";
01730        //workaround end.
01731        tos<<"      </tbody>\n";
01732        tos<<"    </table>\n";
01733        tos<<"  </body>\n</html>\n";
01734 
01735        if(file.error()>0){
01736               QMessageBox::critical(parent, tr("FET critical"),
01737                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
01738               return false;
01739        }
01740        file.close();
01741        return true;
01742 }
01743 
01744 bool StatisticsExport::exportStatisticsStudentsSubjects(QWidget* parent, QString saveTime){
01745        assert(gt.rules.initialized); // && gt.rules.internalStructureComputed);
01746        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
01747 
01748        if(s2.right(4)==".fet")
01749               s2=s2.left(s2.length()-4);
01750        //else if(INPUT_FILENAME_XML!="")
01751        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
01752 
01753        QString bar;
01754        if(INPUT_FILENAME_XML=="")
01755               bar="";
01756        else
01757               bar="_";
01758 
01759        QString htmlfilename=PREFIX_STATISTICS+s2+bar+STUDENTS_SUBJECTS_STATISTICS;
01760 
01761        QFile file(htmlfilename);
01762        if(!file.open(QIODevice::WriteOnly)){
01763               QMessageBox::critical(parent, tr("FET critical"),
01764                StatisticsExport::tr("Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(htmlfilename));
01765               return false;
01766               assert(0);
01767        }
01768        QTextStream tos(&file);
01769        tos.setCodec("UTF-8");
01770        tos.setGenerateByteOrderMark(true);
01771        tos<<"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
01772        tos<<"  \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\n";
01773 
01774        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==false)
01775               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\">\n";
01776        else
01777               tos<<"<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\""<<LANGUAGE_FOR_HTML<<"\" xml:lang=\""<<LANGUAGE_FOR_HTML<<"\" dir=\"rtl\">\n";
01778        tos<<"  <head>\n";
01779        tos<<"    <title>"<<protect2(gt.rules.institutionName)<<"</title>\n";
01780        tos<<"    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
01781        if(TIMETABLE_HTML_LEVEL>=1){
01782               QString bar;
01783               if(INPUT_FILENAME_XML=="")
01784                      bar="";
01785               else
01786                      bar="_";
01787        
01788               QString cssfilename=s2+bar+STYLESHEET_STATISTICS;
01789               tos<<"    <link rel=\"stylesheet\" media=\"all\" href=\""<<cssfilename<<"\" type=\"text/css\" />\n";
01790        }
01791        if(TIMETABLE_HTML_LEVEL>=5){  // the following JavaScript code is pretty similar to an example of Les Richardson
01792               tos<<"    <meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\" />\n";
01793               tos<<"    <script type=\"text/javascript\">\n";
01794               tos<<"      function highlight(classval) {\n";
01795               tos<<"        var spans = document.getElementsByTagName('span');\n";
01796               tos<<"        for(var i=0;spans.length>i;i++) {\n";
01797               tos<<"          if (spans[i].className == classval) {\n";
01798               tos<<"            spans[i].style.backgroundColor = 'lime';\n";
01799               tos<<"          } else {\n";
01800               tos<<"            spans[i].style.backgroundColor = 'white';\n";
01801               tos<<"          }\n";
01802               tos<<"        }\n";
01803               tos<<"      }\n";
01804               tos<<"    </script>\n";
01805        }
01806        tos<<"  </head>\n\n";
01807 
01808        tos<<"  <body>\n";
01809        tos<<"    <table border=\"1\">\n"; 
01810        tos<<"      <caption>"<<protect2(gt.rules.institutionName)<<"</caption>\n";
01811        tos<<"      <thead>\n        <tr><td rowspan=\"2\"></td><th colspan=\""<<allStudentsNames.size()+1<<"\">"<<tr("Students -Subjects Matrix")<<"</th></tr>\n";
01812        tos<<"        <tr>\n          <!-- span -->\n";
01813 
01814        foreach(QString students, allStudentsNames){
01815               if(TIMETABLE_HTML_LEVEL>=2)
01816                      tos<<"          <th class=\"xAxis\">";
01817               else
01818                      tos<<"          <th>";
01819               tos<<protect2(students)<<"</th>\n";
01820        }
01821        if(TIMETABLE_HTML_LEVEL>=2)
01822               tos<<"          <th class=\"xAxis\">";
01823        else
01824               tos<<"          <th>";
01825        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01826        tos<<"        </tr>\n";
01827        tos<<"      </thead>\n";
01828        tos<<"      <tbody>\n";
01829        
01830        QProgressDialog progress(parent);
01831        progress.setWindowTitle(tr("Exporting statistics", "Title of a progress dialog"));
01832        progress.setLabelText(tr("Processing students with subjects...please wait"));
01833        progress.setRange(0, allSubjectsNames.count());
01834        progress.setModal(true);
01835        
01836        int ttt=0;
01837        
01838        foreach(QString subjects, allSubjectsNames){
01839               progress.setValue(ttt);
01840               //pqapplication->processEvents();
01841               if(progress.wasCanceled()){
01842                      QMessageBox::warning(parent, tr("FET warning"), tr("Canceled"));
01843                      return false;
01844               }
01845               ttt++;
01846        
01847               QList<int> tmpSubjects;
01848               QMultiHash<QString, int> tmpStudents;
01849               tmpSubjects.clear();
01850               tmpStudents.clear();
01851               tmpSubjects=subjectsActivities.values(subjects);
01852               foreach(int aidx, tmpSubjects){
01853                      Activity* act=gt.rules.activitiesList.at(aidx);
01854                      foreach(QString students, act->studentsNames){
01855                             tmpStudents.insert(students, aidx);
01856                      }
01857               }
01858               tos<<"        <tr>\n";
01859               if(TIMETABLE_HTML_LEVEL>=2)
01860                      tos<<"          <th class=\"yAxis\">";
01861               else
01862                      tos<<"          <th>";
01863               tos<<protect2(subjects)<<"</th>\n";
01864               foreach(QString students, allStudentsNames){
01865                      QList<int> tmpActivities;
01866                      tmpActivities.clear();
01867                      tmpActivities=tmpStudents.values(students);
01868                      if(tmpActivities.isEmpty()){
01869                             switch(TIMETABLE_HTML_LEVEL){
01870                                    case 3 : ;
01871                                    case 4 : tos<<"          <td class=\"empty\"><span class=\"empty\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01872                                    case 5 : ;
01873                                    case 6 : tos<<"          <td class=\"empty\"><span class=\"empty\" onmouseover=\"highlight('empty')\">"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</span></td>\n"; break;
01874                                    default: tos<<"          <td>"<<protect2(STRING_EMPTY_SLOT_STATISTICS)<<"</td>\n";
01875                             }
01876                      } else {
01877                             QMap<QString, int> tmpTeacherDuration;    //not QHash, because i need the correct order of the activities
01878                             foreach(int tmpAct, tmpActivities){
01879                                    Activity* act=gt.rules.activitiesList[tmpAct];
01880                                    int tmpD=act->duration;
01881                                    QString tmpT;
01882                                    if(act->teachersNames.size()>0){
01883                                           for(QStringList::Iterator it=act->teachersNames.begin(); it!=act->teachersNames.end(); it++){
01884                                                  switch(TIMETABLE_HTML_LEVEL){
01885                                                         case 4 : tmpT+="<span class=\"t_"+hashTeacherIDsStatistics.value(*it)+"\">"+protect2(*it)+"</span>"; break;
01886                                                         case 5 : ;
01887                                                         case 6 : tmpT+="<span class=\"t_"+hashTeacherIDsStatistics.value(*it)+"\" onmouseover=\"highlight('t_"+hashTeacherIDsStatistics.value(*it)+"')\">"+protect2(*it)+"</span>"; break;
01888                                                         default: tmpT+=protect2(*it); break;
01889                                                  }
01890                                                  if(it!=act->teachersNames.end()-1)
01891                                                         tmpT+=", ";
01892                                           }
01893                                    } else
01894                                           tmpT=" ";
01895                                    tmpD+=tmpTeacherDuration.value(tmpT);
01896                                    tmpTeacherDuration.insert(tmpT, tmpD);
01897                             }
01898                             if(TIMETABLE_HTML_LEVEL>=1)
01899                                    tos<<"          <td><table class=\"detailed\">";
01900                             else
01901                                    tos<<"          <td><table>";
01902                             if(TIMETABLE_HTML_LEVEL>=3)
01903                                    tos<<"<tr class=\"duration line1\">";
01904                             else   tos<<"<tr>";
01905                             QMapIterator<QString, int> it(tmpTeacherDuration);
01906                             while(it.hasNext()){
01907                                    it.next();
01908                                    if(TIMETABLE_HTML_LEVEL>=1)
01909                                           tos<<"<td class=\"detailed\">";
01910                                    else
01911                                           tos<<"<td>";
01912                                    tos<<it.value()<<"</td>";   
01913                             }
01914                             tos<<"</tr>";
01915                             if(TIMETABLE_HTML_LEVEL>=3)
01916                                    tos<<"<tr class=\"teacher line2\">";
01917                             else   tos<<"<tr>";
01918                             QMapIterator<QString, int> it2(tmpTeacherDuration);     //do it with the same iterator
01919                             while(it2.hasNext()){
01920                                    it2.next();
01921                                    if(TIMETABLE_HTML_LEVEL>=1)
01922                                           tos<<"<td class=\"detailed\">";
01923                                    else
01924                                           tos<<"<td>";
01925                                    tos<<it2.key()<<"</td>";    
01926                             }
01927                             tos<<"</tr>";
01928                             tos<<"</table></td>\n";
01929                      }
01930               }
01931               tos<<"          <th>";
01932               tos<<CustomFETString::number(subjectsTotalNumberOfHours.value(subjects));
01933               if(subjectsTotalNumberOfHours.value(subjects)!=subjectsTotalNumberOfHours4.value(subjects))
01934                      tos<<"<br />("<<CustomFETString::number(subjectsTotalNumberOfHours4.value(subjects))<<")";
01935               tos<<"</th>\n";
01936               tos<<"        </tr>\n";
01937        }
01938        
01939        progress.setValue(allSubjectsNames.count());
01940 
01941        tos<<"        <tr>\n";
01942        if(TIMETABLE_HTML_LEVEL>=2)
01943               tos<<"          <th class=\"xAxis\">";
01944        else
01945               tos<<"          <th>";
01946        tos<<protect2(tr("Sum", "This means the sum of more values, the total"))<<"</th>\n";
01947        foreach(QString students, allStudentsNames){
01948               tos<<"          <th>"<<CustomFETString::number(studentsTotalNumberOfHours.value(students));
01949               if(studentsTotalNumberOfHours.value(students)!=studentsTotalNumberOfHours2.value(students))
01950                      tos<<"<br />("<<CustomFETString::number(studentsTotalNumberOfHours2.value(students))<<")";
01951               tos<<"</th>\n";      
01952        }
01953        tos<<"          <th></th>\n        </tr>\n";
01954        //workaround begin.
01955        tos<<"      <tr class=\"foot\"><td></td><td colspan=\""<<allStudentsNames.size()+1<<"\">"<<StatisticsExport::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";
01956        //workaround end.
01957        tos<<"      </tbody>\n";
01958        tos<<"    </table>\n";
01959        tos<<"  </body>\n</html>\n";
01960 
01961        if(file.error()>0){
01962               QMessageBox::critical(parent, tr("FET critical"),
01963                StatisticsExport::tr("Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(htmlfilename).arg(file.error()));
01964               return false;
01965        }
01966        file.close();
01967        return true;
01968 }