Back to index

fet  5.18.0
export.cpp
Go to the documentation of this file.
00001 /*
00002 File export.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                           export.cpp  -  description
00012                              -------------------
00013     begin                : Mar 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 
00027 //TODO: protect export strings. textquote must be dubbled
00028 //TODO: count skipped min day constraints?
00029 //TODO: add cancel button
00030 
00031 #include <QtGui>
00032 #include <QHash>
00033 #include <QSet>
00034 
00035 class QWidget;
00036 void centerWidgetOnScreen(QWidget* widget);
00037 
00038 #include "timetable_defs.h"        //needed, because of QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00039 #include "export.h"
00040 #include "solution.h"
00041 
00042 extern Timetable gt;
00043 extern Solution best_solution;
00044 extern bool teachers_schedule_ready;
00045 extern bool students_schedule_ready;
00046 extern bool rooms_schedule_ready;
00047 
00048 const char CSVActivities[]="activities.csv";
00049 const char CSVActivitiesStatistic[]="statistics_activities.csv";
00050 const char CSVActivityTags[]="activity_tags.csv";
00051 const char CSVRoomsAndBuildings[]="rooms_and_buildings.csv";
00052 const char CSVSubjects[]="subjects.csv";
00053 const char CSVTeachers[]="teachers.csv";
00054 const char CSVStudents[]="students.csv";
00055 const char CSVTimetable[]="timetable.csv";
00056 QString DIRECTORY_CSV;
00057 QString PREFIX_CSV;
00058 
00059 Export::Export()
00060 {
00061 }
00062 
00063 Export::~Export()
00064 {
00065 }
00066 
00067 
00068 bool Export::okToWrite(QWidget* parent, const QString& file, QMessageBox::StandardButton& msgBoxButton)
00069 {
00070        if(QFile::exists(file)){
00071               if(msgBoxButton==QMessageBox::YesToAll){
00072                      return true;
00073               }
00074               else if(msgBoxButton==QMessageBox::NoToAll){
00075                      return false;
00076               }
00077               else if(msgBoxButton==QMessageBox::No ||
00078                msgBoxButton==QMessageBox::Yes ||
00079                msgBoxButton==QMessageBox::NoButton){
00080               
00081                      QMessageBox msgBox(parent);
00082                      msgBox.setWindowTitle(tr("FET warning"));
00083                      msgBox.setIcon(QMessageBox::Warning);
00084                      msgBox.setText(tr("File %1 exists - are you sure you want to overwrite existing file?").arg(file));
00085                      msgBox.setStandardButtons(QMessageBox::Yes|QMessageBox::No|QMessageBox::YesToAll|QMessageBox::NoToAll);
00086                      msgBox.setDefaultButton(QMessageBox::Yes);
00087                      
00088                      msgBoxButton=((QMessageBox::StandardButton)(msgBox.exec()));
00089                      
00090 /*                   msgBoxButton=QMessageBox::warning(parent, tr("FET warning"),
00091                       tr("File %1 exists - are you sure you want to overwrite existing file?")
00092                       .arg(file),
00093                       QMessageBox::Yes|QMessageBox::No|QMessageBox::YesToAll|QMessageBox::NoToAll,
00094                       QMessageBox::Yes
00095                       );*/
00096                      
00097                      if(msgBoxButton==QMessageBox::No || msgBoxButton==QMessageBox::NoToAll)
00098                             return false;
00099                      else
00100                             return true;
00101               }
00102               else{
00103                      assert(0);
00104                      return false;
00105               }
00106        }
00107        else
00108               return true;
00109 }
00110 
00111 
00112 void Export::exportCSV(QWidget* parent){
00113        QString fieldSeparator=",";
00114        QString textquote="\"";
00115        QString setSeparator="+";
00116        bool head=true;
00117        bool ok=true;
00118 
00119        DIRECTORY_CSV=OUTPUT_DIR+FILE_SEP+"csv";
00120 
00121        QString s2;
00122        if(INPUT_FILENAME_XML=="")
00123               s2="unnamed";
00124        else{
00125               s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);     //TODO: remove s2, because to long filenames!
00126 
00127               if(s2.right(4)==".fet")
00128                      s2=s2.left(s2.length()-4);
00129               //else if(INPUT_FILENAME_XML!="")
00130               //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00131        }
00132        DIRECTORY_CSV.append(FILE_SEP);
00133        DIRECTORY_CSV.append(s2);
00134        
00135 
00136        PREFIX_CSV=DIRECTORY_CSV+FILE_SEP;
00137 
00138        QDir dir;
00139        if(!dir.exists(OUTPUT_DIR))
00140               dir.mkpath(OUTPUT_DIR);
00141        if(!dir.exists(DIRECTORY_CSV))
00142               dir.mkpath(DIRECTORY_CSV);
00143 
00144        QDialog* newParent;
00145        ok=selectSeparatorAndTextquote(parent, newParent, textquote, fieldSeparator, head);
00146        
00147        QString lastWarnings;
00148        if(!ok){
00149               lastWarnings.insert(0,Export::tr("Export aborted")+"\n");
00150        } else {
00151               bool okat, okr, oks, okt, okst, okact, okacts, oktim;
00152 
00153               QMessageBox::StandardButton msgBoxButton=QMessageBox::NoButton;
00154 
00155               okat=exportCSVActivityTags(newParent, lastWarnings, textquote, head, setSeparator, msgBoxButton);
00156               okr=exportCSVRoomsAndBuildings(newParent, lastWarnings, textquote, fieldSeparator, head, msgBoxButton);
00157               oks=exportCSVSubjects(newParent, lastWarnings, textquote, head, msgBoxButton);
00158               okt=exportCSVTeachers(newParent, lastWarnings, textquote, head, setSeparator, msgBoxButton);
00159               okst=exportCSVStudents(newParent, lastWarnings, textquote, fieldSeparator, head, setSeparator, msgBoxButton);
00160               okact=exportCSVActivities(newParent, lastWarnings, textquote, fieldSeparator, head, msgBoxButton);
00161               okacts=exportCSVActivitiesStatistic(newParent, lastWarnings, textquote, fieldSeparator, head, msgBoxButton);
00162               oktim=exportCSVTimetable(newParent, lastWarnings, textquote, fieldSeparator, head, msgBoxButton);
00163               
00164               ok=okat && okr && oks && okt && okst && okact && okacts && oktim;
00165                      
00166               lastWarnings.insert(0,Export::tr("CSV files were exported to directory %1.").arg(QDir::toNativeSeparators(DIRECTORY_CSV))+"\n");
00167               if(ok)
00168                      lastWarnings.insert(0,Export::tr("Exported complete")+"\n");
00169               else
00170                      lastWarnings.insert(0,Export::tr("Export incomplete")+"\n");
00171        }
00172 
00173        LastWarningsDialogE lwd(newParent, lastWarnings);
00174        int w=lwd.sizeHint().width();
00175        int h=lwd.sizeHint().height();
00176        lwd.resize(w,h);
00177        centerWidgetOnScreen(&lwd);
00178        
00179        ok=lwd.exec();
00180 }
00181 
00182 
00183 
00184 QString Export::protectCSV(const QString& str){
00185        QString p=str;
00186        p.replace("\"", "\"\"");
00187        return p;
00188 }
00189 
00190 
00191 
00192 bool Export::checkSetSeparator(const QString& str, const QString setSeparator){
00193        if(str.contains(setSeparator))
00194               return false;
00195        return true;
00196 }
00197 
00198 bool Export::isActivityNotManualyEdited(const int activityIndex, bool& diffTeachers, bool& diffSubject, bool& diffActivityTags, bool& diffStudents, bool& diffCompNStud, bool& diffNStud, bool& diffActive){ //similar to ActivitiesForm::modifyActivity() by Liviu Lalescu, but added diffActive
00199        diffTeachers=diffSubject=diffActivityTags=diffStudents=diffCompNStud=diffNStud=diffActive=false;
00200 
00201        assert(activityIndex>=0);
00202        assert(activityIndex<gt.rules.activitiesList.size());
00203 
00204        Activity* act=gt.rules.activitiesList[activityIndex];
00205        assert(act!=NULL);
00206        
00207        QStringList teachers=act->teachersNames;
00208        QString subject=act->subjectName;
00209        QStringList activityTags=act->activityTagsNames;
00210        QStringList students=act->studentsNames;
00211        
00212        int nTotalStudents=act->nTotalStudents;
00213        
00214        bool computeNTotalStudents=act->computeNTotalStudents;
00215        bool active=act->active;
00216 
00217        if(act->isSplit()){
00218               for(int i=activityIndex; i<gt.rules.activitiesList.size(); i++){      //possible speed improvement: not i=0. do i=act->activityGroupId
00219                      Activity* act2=gt.rules.activitiesList[i];                     //possible speed improvement: if(act2->activityGroupId changed) break;
00220                      if(act2->activityGroupId!=0 && act2->activityGroupId==act->activityGroupId){
00221                             if(teachers!=act2->teachersNames){
00222                                    //return false;
00223                                    diffTeachers=true;
00224                             }
00225                             if(subject!=act2->subjectName){
00226                                    //return false;
00227                                    diffSubject=true;
00228                             }
00229                             if(activityTags!=act2->activityTagsNames){
00230                                    diffActivityTags=true;
00231                                    //return false;
00232                             }
00233                             if(students!=act2->studentsNames){
00234                                    diffStudents=true;
00235                                    //return false;
00236                             }
00237                             if( /* !computeNTotalStudents && !act2->computeNTotalStudents && */ nTotalStudents!=act2->nTotalStudents){
00238                                    diffNStud=true;
00239                                    //return false;
00240                             }
00241                             if(computeNTotalStudents!=act2->computeNTotalStudents){
00242                                    diffCompNStud=true;
00243                                    //return false;
00244                             }
00245                             if(active!=act2->active){
00246                                    diffActive=true;
00247                                    //return false;      
00248                             }
00249                      }
00250                      else
00251                             i=gt.rules.activitiesList.size();
00252               }
00253        }
00254        if(!diffTeachers && !diffSubject && !diffActivityTags && !diffStudents && !diffCompNStud && !diffNStud && !diffActive)
00255               return true;
00256        else
00257               return false;
00258 }
00259 
00260 
00261 bool Export::selectSeparatorAndTextquote(QWidget* parent, QDialog* &newParent, QString& textquote, QString& fieldSeparator, bool& head){
00262        assert(gt.rules.initialized);
00263 
00264        newParent=((QDialog*)parent);
00265 
00266        QStringList separators;
00267        QStringList textquotes;
00268        separators<<","<<";"<<"|";
00269        //textquotes<<"\""<<"'"<<Export::tr("no textquote", "The translated field must contain at least 2 characters (normally it should), otherwise the export filter does not work");
00270        const QString NO_TEXTQUOTE_TRANSLATED=Export::tr("no textquote", "Please use at least 2 characters for the translation of this field, so that the program works OK");
00271        textquotes<<"\""<<"'"<<NO_TEXTQUOTE_TRANSLATED;
00272        const int NO_TEXTQUOTE_POS=2; //if you modify line above, modify also this variable to be the position of the no textquote (starts from 0)
00273        //also, if you add textquotes longer than one character, take care of line 309 (later in the same function) (assert textquote.size()==1)
00274        //it is permitted for position NO_TEXTQUOTE_POS to have a string longer than 1 QChar
00275        
00276        /*if(textquotes[2].size()<=1){
00277               QMessageBox::warning(parent, tr("FET warning"), tr("Translation is wrong, because translation of 'no textquote' is too short - falling back to English words. Please report bug"));
00278               textquote=QString("no textquote");
00279        }
00280        assert(textquotes[2].size()>1);*/
00281        
00282        const QString settingsName=QString("ExportSelectSeparatorsDialog");
00283 
00284        newParent=new QDialog(parent);
00285        QDialog& separatorsDialog=(*newParent);
00286        
00287        separatorsDialog.setWindowTitle(tr("FET question"));
00288        QVBoxLayout* separatorsMainLayout=new QVBoxLayout(&separatorsDialog);
00289 
00290        QHBoxLayout* top=new QHBoxLayout();
00291        QLabel* topText=new QLabel();
00292        topText->setText(Export::tr("Please keep the default settings.\nImport of data will be easier with these settings."));
00293        top->addWidget(topText);
00294 
00295        QGroupBox* separatorsGroupBox = new QGroupBox(Export::tr("Please specify the separator between fields:"));
00296        QComboBox* separatorsCB=NULL;
00297        if(separators.size()>1){
00298               QHBoxLayout* separatorBoxChoose=new QHBoxLayout();
00299               separatorsCB=new QComboBox();
00300 
00301               QLabel* separatorTextChoose=new QLabel();
00302               separatorTextChoose->setText(Export::tr("Use field separator:"));
00303               separatorsCB->insertItems(0,separators);
00304               separatorBoxChoose->addWidget(separatorTextChoose);
00305               separatorBoxChoose->addWidget(separatorsCB);
00306               separatorsGroupBox->setLayout(separatorBoxChoose);
00307        }
00308 
00309        QGroupBox* textquoteGroupBox = new QGroupBox(Export::tr("Please specify the text quote of text fields:"));
00310        QComboBox* textquoteCB=NULL;
00311        if(separators.size()>1){
00312               QHBoxLayout* textquoteBoxChoose=new QHBoxLayout();
00313               textquoteCB=new QComboBox();
00314               
00315               QLabel* textquoteTextChoose=new QLabel();
00316               textquoteTextChoose->setText(Export::tr("Use textquote:"));
00317               textquoteCB->insertItems(0,textquotes);
00318               textquoteBoxChoose->addWidget(textquoteTextChoose);
00319               textquoteBoxChoose->addWidget(textquoteCB);
00320               textquoteGroupBox->setLayout(textquoteBoxChoose);
00321        }
00322 
00323        QGroupBox* firstLineGroupBox = new QGroupBox(Export::tr("Please specify the contents of the first line:"));
00324        QVBoxLayout* firstLineChooseBox=new QVBoxLayout();
00325        QRadioButton* firstLineRadio1 = new QRadioButton(Export::tr("The first line is the heading."));
00326        QRadioButton* firstLineRadio2 = new QRadioButton(Export::tr("The first line contains data. Don't export heading."));
00327        firstLineRadio1->setChecked(true);
00328        firstLineChooseBox->addWidget(firstLineRadio1);
00329        firstLineChooseBox->addWidget(firstLineRadio2);
00330        firstLineGroupBox->setLayout(firstLineChooseBox);
00331 
00332        QPushButton* pb=new QPushButton(tr("OK"));
00333        QPushButton* cancelpb=new QPushButton(tr("Cancel"));
00334        QHBoxLayout* hl=new QHBoxLayout();
00335        hl->addStretch();
00336        hl->addWidget(pb);
00337        hl->addWidget(cancelpb);
00338        
00339        separatorsMainLayout->addLayout(top);
00340        separatorsMainLayout->addWidget(separatorsGroupBox);
00341        separatorsMainLayout->addWidget(textquoteGroupBox);
00342 
00343        separatorsMainLayout->addWidget(firstLineGroupBox);
00344        separatorsMainLayout->addLayout(hl);
00345 
00346        pb->setDefault(true);
00347        pb->setFocus();
00348        
00349        QObject::connect(pb, SIGNAL(clicked()), &separatorsDialog, SLOT(accept()));
00350        QObject::connect(cancelpb, SIGNAL(clicked()), &separatorsDialog, SLOT(reject()));
00351               
00352        int w=separatorsDialog.sizeHint().width();
00353        int h=separatorsDialog.sizeHint().height();
00354        separatorsDialog.resize(w,h);
00355        
00356        centerWidgetOnScreen(&separatorsDialog);
00357        restoreFETDialogGeometry(&separatorsDialog, settingsName);
00358 
00359        int ok=separatorsDialog.exec();
00360        saveFETDialogGeometry(&separatorsDialog, settingsName);
00361        if(ok!=QDialog::Accepted) return false;
00362 
00363        // TODO: if is always true. maybe clean source (also 2 previous if)
00364        if(separators.size()>1){
00365               assert(separatorsCB!=NULL);
00366               assert(textquoteCB!=NULL);
00367               fieldSeparator=separatorsCB->currentText();
00368               textquote=textquoteCB->currentText();
00369               if(textquoteCB->currentIndex()==NO_TEXTQUOTE_POS){
00370                      assert(textquote==NO_TEXTQUOTE_TRANSLATED);
00371                      textquote=QString("no tquote"); //must have length >= 2
00372               }
00373               else{
00374                      assert(textquote.size()==1);
00375                      //assert(textquote=="\"" || textquote=="'");
00376               }
00377        }
00378        else{
00379               assert(separatorsCB==NULL);
00380               assert(textquoteCB==NULL);
00381               fieldSeparator="";
00382               textquote="";
00383        }
00384 
00385        if(textquote.size()!=1)
00386               textquote="";
00387 
00388        if(firstLineRadio1->isChecked())
00389               head=true;
00390        else head=false;
00391        return true;
00392 }
00393 
00394 
00395 
00396 LastWarningsDialogE::LastWarningsDialogE(QWidget* parent, QString lastWarning): QDialog(parent)
00397 {
00398        this->setWindowTitle(tr("FET - export comment", "The comment of the exporting operation"));
00399        QVBoxLayout* lastWarningsMainLayout=new QVBoxLayout(this);
00400 
00401        QPlainTextEdit* lastWarningsText=new QPlainTextEdit();
00402        lastWarningsText->setMinimumWidth(500);                        //width
00403        lastWarningsText->setMinimumHeight(250);
00404        lastWarningsText->setReadOnly(true);
00405        lastWarningsText->setWordWrapMode(QTextOption::NoWrap);
00406        lastWarningsText->setPlainText(lastWarning);
00407 
00408        //Start Buttons
00409        QPushButton* pb1=new QPushButton(tr("&Ok"));
00410        //pb1->setAutoDefault(true);
00411 
00412        QHBoxLayout* hl=new QHBoxLayout();
00413        hl->addStretch();
00414        hl->addWidget(pb1);
00415 
00416        //Start adding all into main layout
00417        lastWarningsMainLayout->addWidget(lastWarningsText);
00418        lastWarningsMainLayout->addLayout(hl);
00419 
00420        QObject::connect(pb1, SIGNAL(clicked()), this, SLOT(accept()));
00421        
00422        //pb1->setDefault(true);
00423 
00424        pb1->setDefault(true);
00425        pb1->setFocus();
00426 }
00427 
00428 LastWarningsDialogE::~LastWarningsDialogE()
00429 {
00430 }
00431 
00432 
00433 bool Export::exportCSVActivityTags(QWidget* parent, QString& lastWarnings, const QString textquote, const bool head, const QString setSeparator, QMessageBox::StandardButton& msgBoxButton){
00434        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00435 
00436        if(s2.right(4)==".fet")
00437               s2=s2.left(s2.length()-4);
00438        //else if(INPUT_FILENAME_XML!="")
00439        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00440 
00441        QString UNDERSCORE="_";
00442        if(INPUT_FILENAME_XML=="")
00443               UNDERSCORE="";
00444        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVActivityTags;
00445        
00446        if(!Export::okToWrite(parent, file, msgBoxButton))
00447               return false;
00448        
00449        QFile fileExport(file);
00450        if(!fileExport.open(QIODevice::WriteOnly)){
00451               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00452               return false;
00453               assert(0);
00454        }
00455        QTextStream tosExport(&fileExport);
00456        tosExport.setCodec("UTF-8");
00457        tosExport.setGenerateByteOrderMark(true);
00458 
00459        if(head)
00460               tosExport<<textquote<<"Activity Tag"<<textquote<<endl;
00461 
00462        foreach(ActivityTag* a, gt.rules.activityTagsList){
00463               tosExport<<textquote<<protectCSV(a->name)<<textquote<<endl;
00464               if(!checkSetSeparator(a->name, setSeparator))
00465                      lastWarnings+=Export::tr("Warning! Import of activities will fail, because %1 include set separator +.").arg(a->name)+"\n";
00466        }
00467 
00468        lastWarnings+=Export::tr("%1 activity tags exported.").arg(gt.rules.activityTagsList.size())+"\n";
00469        if(fileExport.error()>0){
00470               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error()+"\n");
00471               return false;
00472        }
00473        fileExport.close();
00474        return true;
00475 }
00476 
00477 
00478 
00479 bool Export::exportCSVRoomsAndBuildings(QWidget* parent, QString& lastWarnings, const QString textquote, const QString fieldSeparator, const bool head, QMessageBox::StandardButton& msgBoxButton){
00480        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00481 
00482        if(s2.right(4)==".fet")
00483               s2=s2.left(s2.length()-4);
00484        //else if(INPUT_FILENAME_XML!="")
00485        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00486 
00487        QString UNDERSCORE="_";
00488        if(INPUT_FILENAME_XML=="")
00489               UNDERSCORE="";
00490        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVRoomsAndBuildings;
00491 
00492        if(!Export::okToWrite(parent, file, msgBoxButton))
00493               return false;
00494        
00495        QFile fileExport(file);
00496        if(!fileExport.open(QIODevice::WriteOnly)){
00497               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00498               return false;
00499               assert(0);
00500        }
00501        QTextStream tosExport(&fileExport);
00502        tosExport.setCodec("UTF-8");
00503        tosExport.setGenerateByteOrderMark(true);
00504        
00505        if(head)
00506               tosExport     <<textquote<<"Room"<<textquote<<fieldSeparator
00507                             <<textquote<<"Room Capacity"<<textquote<<fieldSeparator
00508                             <<textquote<<"Building"<<textquote<<endl;
00509 
00510        QStringList checkBuildings;
00511        foreach(Room* r, gt.rules.roomsList){
00512               tosExport     <<textquote<<protectCSV(r->name)<<textquote<<fieldSeparator
00513                             <<CustomFETString::number(r->capacity)<<fieldSeparator
00514                             <<textquote<<protectCSV(r->building)<<textquote<<endl;
00515               if(!checkBuildings.contains(r->building)&&!r->building.isEmpty())
00516                      checkBuildings<<r->building;
00517        }
00518 
00519        lastWarnings+=Export::tr("%1 rooms (with buildings) exported.").arg(gt.rules.roomsList.size())+"\n";
00520        if(gt.rules.buildingsList.size()!=checkBuildings.size()){
00521               lastWarnings+=Export::tr("Warning! Only %1 of %2 building names are exported, because %3 buildings don't contain any room.").arg(checkBuildings.size()).arg(gt.rules.buildingsList.size()).arg(gt.rules.buildingsList.size()-checkBuildings.size())+"\n";
00522        }
00523        
00524        if(fileExport.error()>0){
00525               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error()+"\n");
00526               return false;
00527        }
00528        fileExport.close();
00529        return true;
00530 }
00531 
00532 
00533 
00534 bool Export::exportCSVSubjects(QWidget* parent, QString& lastWarnings, const QString textquote, const bool head, QMessageBox::StandardButton& msgBoxButton){
00535        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00536 
00537        if(s2.right(4)==".fet")
00538               s2=s2.left(s2.length()-4);
00539        //else if(INPUT_FILENAME_XML!="")
00540        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00541 
00542        QString UNDERSCORE="_";
00543        if(INPUT_FILENAME_XML=="")
00544               UNDERSCORE="";
00545        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVSubjects;
00546 
00547        if(!Export::okToWrite(parent, file, msgBoxButton))
00548               return false;
00549        
00550        QFile fileExport(file);
00551        if(!fileExport.open(QIODevice::WriteOnly)){
00552               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00553               return false;
00554               assert(0);
00555        }
00556        QTextStream tosExport(&fileExport);
00557        tosExport.setCodec("UTF-8");
00558        tosExport.setGenerateByteOrderMark(true);
00559        
00560        if(head)
00561               tosExport<<textquote<<"Subject"<<textquote<<endl;
00562 
00563        foreach(Subject* s, gt.rules.subjectsList){
00564               tosExport<<textquote<<protectCSV(s->name)<<textquote<<endl;
00565        }
00566 
00567        lastWarnings+=Export::tr("%1 subjects exported.").arg(gt.rules.subjectsList.size())+"\n";  
00568        if(fileExport.error()>0){
00569               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error()+"\n");
00570               return false;
00571        }
00572        fileExport.close();
00573        return true;
00574 }
00575 
00576 
00577 
00578 bool Export::exportCSVTeachers(QWidget* parent, QString& lastWarnings, const QString textquote, const bool head, const QString setSeparator, QMessageBox::StandardButton& msgBoxButton){
00579        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00580 
00581        if(s2.right(4)==".fet")
00582               s2=s2.left(s2.length()-4);
00583        //else if(INPUT_FILENAME_XML!="")
00584        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00585 
00586        QString UNDERSCORE="_";
00587        if(INPUT_FILENAME_XML=="")
00588               UNDERSCORE="";
00589        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVTeachers;
00590 
00591        if(!Export::okToWrite(parent, file, msgBoxButton))
00592               return false;
00593        
00594        QFile fileExport(file);
00595        if(!fileExport.open(QIODevice::WriteOnly)){
00596               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00597               return false;
00598               assert(0);
00599        }
00600        QTextStream tosExport(&fileExport);
00601        tosExport.setCodec("UTF-8");
00602        tosExport.setGenerateByteOrderMark(true);
00603        
00604        if(head)
00605               tosExport<<textquote<<"Teacher"<<textquote<<endl;
00606 
00607        foreach(Teacher* t, gt.rules.teachersList){
00608               tosExport<<textquote<<protectCSV(t->name)<<textquote<<endl;
00609               if(!checkSetSeparator(t->name, setSeparator))
00610                      lastWarnings+=Export::tr("Warning! Import of activities will fail, because %1 include set separator +.").arg(t->name)+"\n";
00611        }
00612 
00613        lastWarnings+=Export::tr("%1 teachers exported.").arg(gt.rules.teachersList.size())+"\n";
00614        if(fileExport.error()>0){
00615               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error()+"\n");
00616               return false;
00617        }
00618        fileExport.close();
00619        return true;
00620 }
00621 
00622 
00623 
00624 bool Export::exportCSVStudents(QWidget* parent, QString& lastWarnings, const QString textquote, const QString fieldSeparator, const bool head, const QString setSeparator, QMessageBox::StandardButton& msgBoxButton){
00625        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00626 
00627        if(s2.right(4)==".fet")
00628               s2=s2.left(s2.length()-4);
00629        //else if(INPUT_FILENAME_XML!="")
00630        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00631 
00632        QString UNDERSCORE="_";
00633        if(INPUT_FILENAME_XML=="")
00634               UNDERSCORE="";
00635        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVStudents;
00636 
00637        if(!Export::okToWrite(parent, file, msgBoxButton))
00638               return false;
00639        
00640        QFile fileExport(file);
00641        if(!fileExport.open(QIODevice::WriteOnly)){
00642               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00643               return false;
00644               assert(0);
00645        }
00646        QTextStream tosExport(&fileExport);
00647        tosExport.setCodec("UTF-8");
00648        tosExport.setGenerateByteOrderMark(true);
00649        
00650        if(head)
00651               tosExport     <<textquote<<"Year"<<textquote<<fieldSeparator
00652                             <<textquote<<"Number of Students per Year"<<textquote<<fieldSeparator
00653                             <<textquote<<"Group"<<textquote<<fieldSeparator
00654                             <<textquote<<"Number of Students per Group"<<textquote<<fieldSeparator
00655                             <<textquote<<"Subgroup"<<textquote<<fieldSeparator
00656                             <<textquote<<"Number of Students per Subgroup"<<textquote<<endl;
00657 
00658        int ig=0;
00659        int is=0;
00660        foreach(StudentsYear* sty, gt.rules.yearsList){
00661               tosExport<<textquote<<protectCSV(sty->name)<<textquote<<fieldSeparator
00662                                    <<CustomFETString::number(sty->numberOfStudents)<<fieldSeparator<<fieldSeparator<<fieldSeparator<<fieldSeparator<<endl;
00663               if(!checkSetSeparator(sty->name, setSeparator))
00664                      lastWarnings+=Export::tr("Warning! Import of activities will fail, because %1 include set separator +.").arg(sty->name)+"\n";
00665               foreach(StudentsGroup* stg, sty->groupsList){
00666                      ig++;
00667                      tosExport     <<textquote<<protectCSV(sty->name)<<textquote<<fieldSeparator
00668                                    <<CustomFETString::number(sty->numberOfStudents)<<fieldSeparator
00669                                    <<textquote<<protectCSV(stg->name)<<textquote<<fieldSeparator
00670                                    <<CustomFETString::number(stg->numberOfStudents)<<fieldSeparator<<fieldSeparator<<endl;
00671                      if(!checkSetSeparator(stg->name, setSeparator))
00672                             lastWarnings+=Export::tr("Warning! Import of activities will fail, because %1 include set separator +.").arg(stg->name)+"\n";
00673                      foreach(StudentsSubgroup* sts, stg->subgroupsList){
00674                             is++;
00675                             tosExport     <<textquote<<protectCSV(sty->name)<<textquote<<fieldSeparator
00676                                           <<CustomFETString::number(sty->numberOfStudents)<<fieldSeparator
00677                                           <<textquote<<protectCSV(stg->name)<<textquote<<fieldSeparator
00678                                           <<CustomFETString::number(stg->numberOfStudents)<<fieldSeparator
00679                                           <<textquote<<protectCSV(sts->name)<<textquote<<fieldSeparator
00680                                           <<CustomFETString::number(sts->numberOfStudents)<<endl;
00681                             if(!checkSetSeparator(sts->name, setSeparator))
00682                                    lastWarnings+=Export::tr("Warning! Import of activities will fail, because %1 include set separator +.").arg(sts->name)+"\n";
00683                      }
00684               }
00685        }
00686 
00687        lastWarnings+=Export::tr("%1 years exported.").arg(gt.rules.yearsList.size())+"\n";
00688        lastWarnings+=Export::tr("%1 groups exported.").arg(ig)+"\n";
00689        lastWarnings+=Export::tr("%1 subgroups exported.").arg(is)+"\n";
00690        if(fileExport.error()>0){
00691               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error()+"\n");
00692               return false;
00693        }
00694        fileExport.close();
00695        return true;
00696 }
00697 
00698 
00699 
00700 bool Export::exportCSVActivities(QWidget* parent, QString& lastWarnings, const QString textquote, const QString fieldSeparator, const bool head, QMessageBox::StandardButton& msgBoxButton){
00701        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00702 
00703        if(s2.right(4)==".fet")
00704               s2=s2.left(s2.length()-4);
00705        //else if(INPUT_FILENAME_XML!="")
00706        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00707 
00708        QString UNDERSCORE="_";
00709        if(INPUT_FILENAME_XML=="")
00710               UNDERSCORE="";
00711        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVActivities;
00712 
00713        if(!Export::okToWrite(parent, file, msgBoxButton))
00714               return false;
00715        
00716        QFile fileExport(file);
00717        if(!fileExport.open(QIODevice::WriteOnly)){
00718               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00719               return false;
00720               assert(0);
00721        }
00722        QTextStream tosExport(&fileExport);
00723        tosExport.setCodec("UTF-8");
00724        tosExport.setGenerateByteOrderMark(true);
00725        
00726        if(head)
00727               tosExport     <<textquote<<"Students Sets"<<textquote<<fieldSeparator
00728                             <<textquote<<"Subject"<<textquote<<fieldSeparator
00729                             <<textquote<<"Teachers"<<textquote<<fieldSeparator
00730                             <<textquote<<"Activity Tags"<<textquote<<fieldSeparator
00731                             <<textquote<<"Total Duration"<<textquote<<fieldSeparator
00732                             <<textquote<<"Split Duration"<<textquote<<fieldSeparator
00733                             <<textquote<<"Min Days"<<textquote<<fieldSeparator
00734                             <<textquote<<"Weight"<<textquote<<fieldSeparator
00735                             <<textquote<<"Consecutive"<<textquote<<endl;
00736 
00737        //code by Liviu Lalescu (begin)
00738        //better detection of min day constraint
00739        QHash<int, int> activitiesRepresentant;
00740        QHash<int, int> activitiesNumberOfSubactivities;
00741        QHash<int, ConstraintMinDaysBetweenActivities*>activitiesConstraints;
00742        
00743        activitiesRepresentant.clear();
00744        activitiesNumberOfSubactivities.clear();
00745        activitiesConstraints.clear();
00746        
00747        foreach(Activity* act, gt.rules.activitiesList){
00748               assert(!activitiesRepresentant.contains(act->id));
00749               activitiesRepresentant.insert(act->id, act->activityGroupId); //act->id is key, act->agid is value
00750        
00751               if(act->activityGroupId>0){
00752                      int n=activitiesNumberOfSubactivities.value(act->activityGroupId, 0); //0 here means default value
00753                      n++;
00754                      activitiesNumberOfSubactivities.insert(act->activityGroupId, n); //overwrites old value
00755               }
00756        }
00757        foreach(TimeConstraint* tc, gt.rules.timeConstraintsList){
00758               if(tc->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES && tc->active){
00759                      ConstraintMinDaysBetweenActivities* c=(ConstraintMinDaysBetweenActivities*) tc;
00760        
00761                      QSet<int> aset;
00762                      int repres=-1;
00763        
00764                      for(int i=0; i<c->n_activities; i++){
00765                             int aid=c->activitiesId[i];
00766                             aset.insert(aid);
00767        
00768                             if(activitiesRepresentant.value(aid,0)==aid)
00769                                    repres=aid; //does not matter if there are more representants in this constraint, the constraint will be skipped anyway in this case
00770                      }
00771        
00772                      bool oktmp=false;
00773        
00774                      if(repres>0){
00775                             if(aset.count()==activitiesNumberOfSubactivities.value(repres, 0)){
00776                                    oktmp=true;
00777                                    foreach(int aid, aset)
00778                                           if(activitiesRepresentant.value(aid, 0)!=repres){
00779                                                  oktmp=false;
00780                                                  break;
00781                                           }
00782                             }
00783                      }
00784        
00785                      if(!oktmp){
00786                             lastWarnings+=Export::tr("Note: Constraint")+" "+c->getDescription(gt.rules)+" "+tr("was skipped, because"
00787                             " it refers not to a whole larger container activity")+"\n";
00788                      }
00789        
00790                      if(oktmp){
00791                             ConstraintMinDaysBetweenActivities* oldc=activitiesConstraints.value(repres, NULL);
00792                             if(oldc!=NULL){
00793                                    if(oldc->weightPercentage < c->weightPercentage){
00794                                           activitiesConstraints.insert(repres, c); //overwrites old value
00795                                           lastWarnings+=Export::tr("Note: Constraint")+" "+oldc->getDescription(gt.rules)+" "+tr("was skipped, because"
00796                                                  " there exists another constraint of this type with larger weight percentage, referring to the same activities")+"\n";
00797                                    }
00798                                    else if(oldc->weightPercentage > c->weightPercentage){
00799                                           lastWarnings+=Export::tr("Note: Constraint")+" "+c->getDescription(gt.rules)+" "+tr("was skipped, because"
00800                                                  " there exists another constraint of this type with larger weight percentage, referring to the same activities")+"\n";
00801                                    }
00802        
00803                                    //equal weights - choose the lowest number of min days
00804                                    else if(oldc->minDays > c->minDays){
00805                                           lastWarnings+=Export::tr("Note: Constraint")+" "+c->getDescription(gt.rules)+" "+tr("was skipped, because"
00806                                                  " there exists another constraint of this type with same weight percentage and higher number of min days, referring to the same activities")+"\n";
00807                                    }
00808                                    else if(oldc->minDays < c->minDays){
00809                                           activitiesConstraints.insert(repres, c); //overwrites old value
00810                                           lastWarnings+=Export::tr("Note: Constraint")+" "+oldc->getDescription(gt.rules)+" "+tr("was skipped, because"
00811                                                  " there exists another constraint of this type with same weight percentage and higher number of min days, referring to the same activities")+"\n";
00812                                    }
00813        
00814                                    //equal weights and min days - choose the one with consecutive is same day true
00815                                    else if(oldc->consecutiveIfSameDay==true){
00816                                           lastWarnings+=Export::tr("Note: Constraint")+" "+c->getDescription(gt.rules)+" "+tr("was skipped, because"
00817                                                  " there exists another constraint of this type with same weight percentage and same number of min days and"
00818                                                  " consecutive if same day true, referring to the same activities")+"\n";
00819                                    }
00820                                    else if(c->consecutiveIfSameDay==true){
00821                                           activitiesConstraints.insert(repres, c); //overwrites old value
00822                                           lastWarnings+=Export::tr("Note: Constraint")+" "+oldc->getDescription(gt.rules)+" "+tr("was skipped, because"
00823                                                  " there exists another constraint of this type with same weight percentage and same number of min days and"
00824                                                  " consecutive if same day true, referring to the same activities")+"\n";
00825                                    }
00826        
00827                             }
00828                             else
00829                                    activitiesConstraints.insert(repres, c);
00830                      }
00831               }
00832        }
00833        //code by Liviu Lalescu (end)
00834        
00835        bool manuallyEdited=false;
00836 
00837        Activity* acti;
00838        Activity* actiNext;
00839        int countExportedActivities=0;
00840        for(int ai=0; ai<gt.rules.activitiesList.size(); ai++){
00841               acti=gt.rules.activitiesList[ai];
00842               //if(acti->active){
00843                      if((acti->activityGroupId==acti->id)||(acti->activityGroupId==0)){
00844                             bool diffTeachers, diffSubject, diffActivityTag, diffStudents, diffCompNStud, diffNStud, diffActive;
00845                             if(isActivityNotManualyEdited(ai, diffTeachers, diffSubject, diffActivityTag, diffStudents, diffCompNStud, diffNStud, diffActive)){
00846                             }
00847                             else{
00848                                    QStringList s;
00849                                    if(diffTeachers)
00850                                           s.append(tr("different teachers"));
00851                                    if(diffSubject)
00852                                           s.append(tr("different subject"));
00853                                    if(diffActivityTag)
00854                                           s.append(tr("different activity tags"));
00855                                    if(diffStudents)
00856                                           s.append(tr("different students"));
00857                                    if(diffCompNStud)
00858                                           s.append(tr("different boolean variable 'must compute n total students'"));
00859                                    if(diffNStud)
00860                                           s.append(tr("different number of students"));
00861                                    if(diffActive)
00862                                           s.append(tr("different active flag"));
00863                                    
00864                                    manuallyEdited=true;
00865                                    
00866                                    lastWarnings+=tr("Subactivities with activity group id %1 are different between themselves (they were separately edited),"
00867                                           " so the export will not be very accurate. The fields which are different will be considered those of the representative subactivity. Fields which were"
00868                                           " different are: %2").arg(CustomFETString::number(acti->activityGroupId)).arg(s.join(", "))+"\n";
00869                             }
00870                             if(!acti->active){
00871                                    if(acti->activityGroupId==0)
00872                                           lastWarnings+=tr("Activity with id %1 has disabled active flag but it is exported.").arg(CustomFETString::number(acti->id))+"\n";
00873                                    else
00874                                           lastWarnings+=tr("Subactivities with activity group id %1 have disabled active flag but they are exported.").arg(CustomFETString::number(acti->activityGroupId))+"\n";
00875                             }
00876                             
00877                             countExportedActivities++;
00878                             //students set
00879                             tosExport<<textquote;
00880                             for(int s=0; s<acti->studentsNames.size(); s++){
00881                                    if(s!=0)
00882                                           tosExport<<"+";
00883                                    tosExport<<protectCSV(acti->studentsNames[s]);
00884                             }
00885                             tosExport<<textquote<<fieldSeparator<<textquote;
00886                             //subject
00887                             tosExport<<protectCSV(acti->subjectName);
00888                             tosExport<<textquote<<fieldSeparator<<textquote;
00889                             //teachers
00890                             for(int t=0; t<acti->teachersNames.size(); t++){
00891                                    if(t!=0)
00892                                           tosExport<<"+";
00893                                    tosExport<<protectCSV(acti->teachersNames[t]);
00894                             }
00895                             tosExport<<textquote<<fieldSeparator<<textquote;
00896                             //activity tags
00897                             for(int s=0; s<acti->activityTagsNames.size(); s++){
00898                                    if(s!=0)
00899                                           tosExport<<"+";
00900                                    tosExport<<protectCSV(acti->activityTagsNames[s]);
00901                             }
00902                             tosExport<<textquote<<fieldSeparator;
00903                             //total duration
00904                             tosExport<<CustomFETString::number(acti->totalDuration);
00905                             tosExport<<fieldSeparator<<textquote;
00906                             //split duration
00907                             for(int aiNext=ai; aiNext<gt.rules.activitiesList.size(); aiNext++){
00908                                    actiNext=gt.rules.activitiesList[aiNext];
00909                                    if(acti->activityGroupId!=0&&actiNext->activityGroupId==acti->activityGroupId){
00910                                           if(aiNext!=ai)
00911                                                  tosExport<<"+";
00912                                           tosExport<<actiNext->duration;
00913                                    } else {
00914                                           if(acti->activityGroupId==0&&actiNext->activityGroupId==acti->activityGroupId){
00915                                                  assert(ai==aiNext);
00916                                                  assert(actiNext->duration==actiNext->totalDuration);
00917                                                  if(actiNext->duration>1)
00918                                                         tosExport<<actiNext->duration;
00919                                           }      
00920                                           aiNext=gt.rules.activitiesList.size();
00921                                    }      
00922                             }
00923                             tosExport<<textquote<<fieldSeparator;
00924                             //min days
00925                             //start new code, because of Liviu's detection
00926                             bool careAboutMinDay=false;
00927                             ConstraintMinDaysBetweenActivities* tcmd=activitiesConstraints.value(acti->id, NULL);
00928                             if(acti->id==acti->activityGroupId){
00929                                    if(tcmd!=NULL){
00930                                           careAboutMinDay=true;
00931                                    }
00932                             }
00933                             //end new code
00934                             if(careAboutMinDay){
00935                                    assert(tcmd->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES);
00936                                    tosExport<<CustomFETString::number(tcmd->minDays);
00937                             }
00938                             tosExport<<fieldSeparator;
00939                             //min days weight
00940                             if(careAboutMinDay)
00941                                    tosExport<<CustomFETString::number(tcmd->weightPercentage);
00942                             tosExport<<fieldSeparator;
00943                             //min days consecutive
00944                             if(careAboutMinDay)
00945                                    tosExport<<tcmd->consecutiveIfSameDay;
00946                             tosExport<<endl;
00947                      }
00948               //}
00949        }
00950        
00951        if(manuallyEdited){
00952               QMessageBox msgBox(parent);
00953               msgBox.setWindowTitle(tr("FET warning"));
00954               msgBox.setIcon(QMessageBox::Warning);
00955               msgBox.setText(tr("There are subactivities which were modified separately - so the "
00956                "components had different values for subject, activity tags, teachers, students or number of students from the representative subactivity. The export was done, but it is not very accurate."));
00957               msgBox.setStandardButtons(QMessageBox::Ok);
00958               msgBox.setDefaultButton(QMessageBox::Ok);
00959               
00960               msgBox.exec();
00961        }
00962 
00963        lastWarnings+=Export::tr("%1 activities exported.").arg(countExportedActivities)+"\n";
00964        if(fileExport.error()>0){
00965               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error())+"\n";
00966               return false;
00967        }
00968        fileExport.close();
00969        return true;
00970 }
00971 
00972 
00973 
00974 
00975 bool Export::exportCSVActivitiesStatistic(QWidget* parent, QString& lastWarnings, const QString textquote, const QString fieldSeparator, const bool head, QMessageBox::StandardButton& msgBoxButton){
00976        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
00977 
00978        if(s2.right(4)==".fet")
00979               s2=s2.left(s2.length()-4);
00980        //else if(INPUT_FILENAME_XML!="")
00981        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
00982 
00983        QString UNDERSCORE="_";
00984        if(INPUT_FILENAME_XML=="")
00985               UNDERSCORE="";
00986        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVActivitiesStatistic;
00987 
00988        if(!Export::okToWrite(parent, file, msgBoxButton))
00989               return false;
00990        
00991        QFile fileExport(file);
00992        if(!fileExport.open(QIODevice::WriteOnly)){
00993               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
00994               return false;
00995               assert(0);
00996        }
00997        QTextStream tosExport(&fileExport);
00998        tosExport.setCodec("UTF-8");
00999        tosExport.setGenerateByteOrderMark(true);
01000        
01001        if(head)
01002               tosExport     <<textquote<<"Students Sets"<<textquote<<fieldSeparator
01003                             <<textquote<<"Subject"<<textquote<<fieldSeparator
01004                             <<textquote<<"Teachers"<<textquote<<fieldSeparator
01005                             <<textquote<<"Total Duration"<<textquote<<"\n";
01006 
01007 
01008 
01009        Activity* acti;
01010        int countExportedActivities=0;
01011        QMap<QString, int> tmpIdentDuration;      //not QHash, because i want a nice order of the activities
01012        for(int ai=0; ai<gt.rules.activitiesList.size(); ai++){
01013               acti=gt.rules.activitiesList[ai];
01014               if(acti->active){
01015                      int tmpD=acti->duration;
01016                      QString tmpIdent=textquote;
01017                      if(acti->studentsNames.size()>0){
01018                             for(QStringList::Iterator it=acti->studentsNames.begin(); it!=acti->studentsNames.end(); it++){
01019                                    tmpIdent+=protectCSV(*it);
01020                                    if(it!=acti->studentsNames.end()-1)
01021                                           tmpIdent+="+";
01022                             }
01023                      }
01024                      tmpIdent+=textquote+fieldSeparator+textquote+protectCSV(acti->subjectName)+textquote+fieldSeparator+textquote;
01025                      if(acti->teachersNames.size()>0){
01026                             for(QStringList::Iterator it=acti->teachersNames.begin(); it!=acti->teachersNames.end(); it++){
01027                                    tmpIdent+=protectCSV(*it);
01028                                    if(it!=acti->teachersNames.end()-1)
01029                                           tmpIdent+="+";
01030                             }
01031                      }
01032                      tmpIdent+=textquote+fieldSeparator;
01033                      tmpD+=tmpIdentDuration.value(tmpIdent);
01034                      tmpIdentDuration.insert(tmpIdent, tmpD);
01035               }
01036        }
01037        QMapIterator<QString, int> it(tmpIdentDuration);
01038        while(it.hasNext()){
01039               countExportedActivities++;
01040               it.next();
01041               tosExport<<it.key();
01042               tosExport<<textquote<<CustomFETString::number(it.value())<<textquote<<"\n";
01043        }
01044 
01045        lastWarnings+=Export::tr("%1 active activities statistics exported.").arg(countExportedActivities)+"\n";
01046        if(fileExport.error()>0){
01047               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error())+"\n";
01048               return false;
01049        }
01050        fileExport.close();
01051        return true;
01052 }
01053 
01054 
01055 
01056 bool Export::exportCSVTimetable(QWidget* parent, QString& lastWarnings, const QString textquote, const QString fieldSeparator, const bool head, QMessageBox::StandardButton& msgBoxButton){
01057        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);    //TODO: remove s2, because to long filenames!
01058 
01059        if(s2.right(4)==".fet")
01060               s2=s2.left(s2.length()-4);
01061        //else if(INPUT_FILENAME_XML!="")
01062        //     cout<<"Minor problem - input file does not end in .fet extension - might be a problem when saving the timetables"<<" (file:"<<__FILE__<<", line:"<<__LINE__<<")"<<endl;
01063 
01064        QString UNDERSCORE="_";
01065        if(INPUT_FILENAME_XML=="")
01066               UNDERSCORE="";
01067        QString file=PREFIX_CSV+s2+UNDERSCORE+CSVTimetable;
01068        
01069        if(!Export::okToWrite(parent, file, msgBoxButton))
01070               return false;
01071        
01072        QFile fileExport(file);
01073        if(!fileExport.open(QIODevice::WriteOnly)){
01074               lastWarnings+=Export::tr("FET critical. Cannot open file %1 for writing. Please check your disk's free space. Saving of %1 aborted.").arg(file)+"\n";
01075               return false;
01076               assert(0);
01077        }
01078        QTextStream tosExport(&fileExport);
01079        tosExport.setCodec("UTF-8");
01080        tosExport.setGenerateByteOrderMark(true);
01081        
01082        //section "Activity Id" was added by Liviu Lalescu on 2010-01-26, as suggested on the forum
01083        if(head)
01084               tosExport
01085                             <<textquote<<"Activity Id"<<textquote<<fieldSeparator
01086                             <<textquote<<"Day"<<textquote<<fieldSeparator
01087                             <<textquote<<"Hour"<<textquote<<fieldSeparator
01088                             <<textquote<<"Students Sets"<<textquote<<fieldSeparator
01089                             <<textquote<<"Subject"<<textquote<<fieldSeparator
01090                             <<textquote<<"Teachers"<<textquote<<fieldSeparator
01091                             <<textquote<<"Activity Tags"<<textquote<<fieldSeparator
01092                             <<textquote<<"Room"<<textquote<<fieldSeparator
01093                             <<textquote<<"Comments"<<textquote<<endl;
01094 
01095        if(gt.rules.initialized && gt.rules.internalStructureComputed
01096         && students_schedule_ready && teachers_schedule_ready && rooms_schedule_ready){
01097               Activity *act;
01098               int exportedActivities=0;
01099               for(int i=0; i<gt.rules.nInternalActivities; i++){
01100                      if(best_solution.times[i]!=UNALLOCATED_TIME) {
01101                             exportedActivities++;
01102                             act=&gt.rules.internalActivitiesList[i];
01103                             int hour=best_solution.times[i]/gt.rules.nDaysPerWeek;
01104                             int day=best_solution.times[i]%gt.rules.nDaysPerWeek;
01105                             int r=best_solution.rooms[i];
01106                             for(int dd=0; dd < act->duration; dd++){
01107                                    assert(hour+dd<gt.rules.nHoursPerDay);
01108                                    
01109                                    //Activity id - added by Liviu on 2010-01-26
01110                                    tosExport<<textquote<<CustomFETString::number(act->id)<<textquote<<fieldSeparator;
01111                                    
01112                                    //Day
01113                                    tosExport<<textquote<<protectCSV(gt.rules.daysOfTheWeek[day])<<textquote<<fieldSeparator;
01114                                    //Period
01115                                    tosExport<<textquote<<protectCSV(gt.rules.hoursOfTheDay[hour+dd])<<textquote<<fieldSeparator<<textquote;
01116                                    //Students Sets
01117                                    for(int s=0; s<act->studentsNames.size(); s++){
01118                                           if(s!=0)
01119                                                  tosExport<<"+";
01120                                           tosExport<<protectCSV(act->studentsNames[s]);
01121                                    }
01122                                    tosExport<<textquote<<fieldSeparator<<textquote;
01123                                    //Subject
01124                                    tosExport<<protectCSV(act->subjectName);
01125                                    tosExport<<textquote<<fieldSeparator<<textquote;
01126                                    //Teachers
01127                                    for(int t=0; t<act->teachersNames.size(); t++){
01128                                           if(t!=0)
01129                                                  tosExport<<"+";
01130                                           tosExport<<protectCSV(act->teachersNames[t]);
01131                                    }
01132                                    tosExport<<textquote<<fieldSeparator<<textquote;
01133                                    //Activity Tags
01134                                    for(int s=0; s<act->activityTagsNames.size(); s++){
01135                                           if(s!=0)
01136                                                  tosExport<<"+";
01137                                           tosExport<<protectCSV(act->activityTagsNames[s]);
01138                                    }
01139                                    tosExport<<textquote<<fieldSeparator<<textquote;
01140                                    //Room
01141                                    if(best_solution.rooms[i] != UNSPECIFIED_ROOM && best_solution.rooms[i] != UNALLOCATED_SPACE){
01142                                           assert(best_solution.rooms[i]>=0 && best_solution.rooms[i]<gt.rules.nInternalRooms);
01143                                           tosExport<<protectCSV(gt.rules.internalRoomsList[r]->name);
01144                                    }
01145                                    tosExport<<textquote<<fieldSeparator<<textquote;
01146                                    //Comments
01147                                    QString tmpString=protectCSV(act->comments);
01148                                    tmpString.replace("\n", " ");
01149                                    tosExport<<tmpString<<textquote<<endl;
01150                             }
01151                      }
01152               }      
01153               lastWarnings+=Export::tr("%1 scheduled activities exported.").arg(exportedActivities)+"\n";
01154        } else {
01155               lastWarnings+=Export::tr("0 scheduled activities exported, because no timetable was generated.")+"\n";
01156        }
01157        if(fileExport.error()>0){
01158               lastWarnings+=Export::tr("FET critical. Writing %1 gave error code %2, which means saving is compromised. Please check your disk's free space.").arg(file).arg(fileExport.error())+"\n";
01159               return false;
01160        }
01161        fileExport.close();
01162        return true;
01163 }