Back to index

fet  5.18.0
fet.cpp
Go to the documentation of this file.
00001 /*
00002 File fet.cpp - this is where the program FET starts
00003 */
00004 
00005 /*
00006 Copyright 2002, 2003 Lalescu Liviu.
00007 
00008 This file is part of FET.
00009 
00010 FET is free software; you can redistribute it and/or modify
00011 it under the terms of the GNU General Public License as published by
00012 the Free Software Foundation; either version 2 of the License, or
00013 (at your option) any later version.
00014 
00015 FET is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with timetable; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 
00025 #include "fet.h"
00026 
00027 #include "matrix.h"
00028 
00029 #include <QMessageBox>
00030 
00031 #include <QWidget>
00032 
00033 #include <QLocale>
00034 #include <QTime>
00035 #include <QDate>
00036 #include <QDateTime>
00037 
00038 #include <ctime>
00039 
00040 #include "timetableexport.h"
00041 #include "generate.h"
00042 
00043 #include "timetable_defs.h"
00044 #include "timetable.h"
00045 #include "fetmainform.h"
00046 
00047 #include "helpaboutform.h"
00048 #include "helpfaqform.h"
00049 #include "helptipsform.h"
00050 #include "helpinstructionsform.h"
00051 
00052 #include "timetableshowconflictsform.h"
00053 #include "timetableviewstudentsform.h"
00054 #include "timetableviewteachersform.h"
00055 #include "timetableviewroomsform.h"
00056 
00057 #include <QApplication>
00058 #include <QMutex>
00059 #include <QString>
00060 #include <QTranslator>
00061 
00062 #include <QCoreApplication>
00063 
00064 #include <QDir>
00065 
00066 #include <QSettings>
00067 
00068 #include <QRect>
00069 
00070 #include <QTextStream>
00071 #include <QFile>
00072 
00073 #include <csignal>
00074 
00075 #include <fstream>
00076 #include <iostream>
00077 using namespace std;
00078 
00079 extern QRect mainFormSettingsRect;
00080 extern int MAIN_FORM_SHORTCUTS_TAB_POSITION;
00081 
00082 extern Solution highestStageSolution;
00083 
00084 extern int maxActivitiesPlaced;
00085 
00086 extern int initialOrderOfActivitiesIndices[MAX_ACTIVITIES];
00087 
00088 extern bool students_schedule_ready, teachers_schedule_ready, rooms_schedule_ready;
00089 
00090 extern QMutex mutex;
00091 
00092 void writeDefaultSimulationParameters();
00093 
00094 QTranslator translator;
00095 
00099 Timetable gt;
00100 
00104 ofstream logg;
00105 
00109 QString INPUT_FILENAME_XML;
00110 
00114 QString WORKING_DIRECTORY;
00115 
00119 QString IMPORT_DIRECTORY;
00120 
00121 /*qint16 teachers_timetable_weekly[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00122 qint16 students_timetable_weekly[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00123 qint16 rooms_timetable_weekly[MAX_ROOMS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];*/
00124 Matrix3D<qint16> teachers_timetable_weekly;
00125 Matrix3D<qint16> students_timetable_weekly;
00126 Matrix3D<qint16> rooms_timetable_weekly;
00127 //QList<qint16> teachers_free_periods_timetable_weekly[TEACHERS_FREE_PERIODS_N_CATEGORIES][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00128 Matrix3D<QList<qint16> > teachers_free_periods_timetable_weekly;
00129 
00130 QApplication* pqapplication=NULL;
00131 
00132 FetMainForm* pFetMainForm=NULL;
00133 
00134 extern int XX;
00135 extern int YY;
00136 
00137 Generate* terminateGeneratePointer;
00138 
00139 //for command line version, if the user stops using a signal
00140 void terminate(int param)
00141 {
00142        Q_UNUSED(param);
00143 
00144        assert(terminateGeneratePointer!=NULL);
00145        
00146        terminateGeneratePointer->abortOptimization=true;
00147 }
00148 
00149 void usage(QTextStream& out, const QString& error)
00150 {
00151        QString s="";
00152        
00153        s+=QString("Incorrect command line parameters (%1).").arg(error);
00154        
00155        s+="\n\n";
00156        
00157        s+=QString(
00158               "Command line usage: \"fet --inputfile=x [--outputdir=d] [--timelimitseconds=y] [--htmllevel=z] [--language=t] [--printnotavailable=u] [--printbreak=b] "
00159               "[--dividetimeaxisbydays=v] [--printsimultaneousactivities=w] [--randomseedx=rx --randomseedy=ry] [--warnifusingnotperfectconstraints=s]"
00160               " [--warnifusingstudentsminhoursdailywithallowemptydays=p]\",\n"
00161               "where:\nx is the input file, for instance \"data.fet\"\n"
00162               "d is the path to results directory, without trailing slash or backslash (default is current working path). "
00163               "Make sure you have write permissions there.\n"
00164               "y is integer (seconds) (default 2000000000, which is practically infinite).\n"
00165               "z is integer from 0 to 6 and represents the detail level for the generated html timetables "
00166               "(default 2, larger values have more details/facilities and larger file sizes).\n"
00167               "t is one of en_US, ar, ca, da, de, el, es, fa, fr, gl, he, hu, id, it, lt, mk, ms, nl, pl, pt_BR, ro, ru, si, sk, sr, tr, uk, uz, vi (default en_US).\n"
00168               "u is either \"true\" or \"false\" and represents if you want -x- (for true) or --- (for false) in the generated timetables for the "
00169               "not available slots (default true).\n"
00170               "b is either \"true\" or \"false\" and represents if you want -X- (for true) or --- (for false) in the generated timetables for the "
00171               "break slots (default true).\n"
00172               "v is either true or false, represents if you want html timetables with time-axis divided by days (default false).\n"
00173               "w is either true or false, represents if you want html timetables to show related activities which have constraints with same starting time (default false).\n"
00174               "(for instance, if A1 (T1, G1) and A2 (T2, G2) have constraint activities same starting time, then in T1's timetable will appear also A2, at the same slot "
00175               "as A1).\n"
00176               "rx is the random seed X component, minimum 1 to maximum 2147483646, ry is the random seed Y component, minimum 1 to maximum 2147483398"
00177               " (you can get the same timetable if the input file is identical, if the FET version is the same and if the random seed X and Y components are the same).\n"
00178               "s is either true or false, represents whether you want a message box to be shown, with a warning, if the input file contains not perfect constraints "
00179               "(activity tag max hours daily or students max gaps per day) (default true).\n"
00180               "p is either true or false, represents whether you want a message box to be shown, with a warning, if the input file contains nonstandard constraints "
00181               "students min hours daily with allow empty days (default true).\n"
00182               "\n"
00183               "Alternatively, you can run \"fet --version [--outputdir=d]\" to get the current FET version. "
00184               "where:\nd is the path to results directory, without trailing slash or backslash (default is current working path). "
00185               "Make sure you have write permissions there.\n"
00186               "(If you specify the \"--version\" argument, FET just prints version number on the command line prompt and in the output directory and exits.)\n"
00187               "\n"
00188               "You can ask the FET command line process to stop the timetable generation, by sending it the SIGTERM signal. "
00189               "FET will then write the current timetable and the highest stage timetable and exit."
00190        );
00191        
00192        cout<<qPrintable(s)<<endl;
00193        out<<qPrintable(s)<<endl;
00194 }
00195 
00196 void readSimulationParameters()
00197 {
00198        const QString predefDir=QDir::homePath()+FILE_SEP+"fet-results";
00199 
00200        QSettings newSettings(COMPANY, PROGRAM);
00201 
00202        if(newSettings.contains("output-directory")){
00203               OUTPUT_DIR=newSettings.value("output-directory").toString();
00204               QDir dir;
00205               if(!dir.exists(OUTPUT_DIR)){
00206                      bool t=dir.mkpath(OUTPUT_DIR);
00207                      if(!t){
00208                             QMessageBox::warning(NULL, FetTranslate::tr("FET warning"), FetTranslate::tr("Output directory %1 does not exist and cannot be"
00209                              " created - output directory will be made the default value %2")
00210                              .arg(QDir::toNativeSeparators(OUTPUT_DIR)).arg(QDir::toNativeSeparators(predefDir)));
00211                             OUTPUT_DIR=predefDir;
00212                      }
00213               }
00214        }
00215        else{
00216               OUTPUT_DIR=predefDir;
00217        }
00218 
00219        FET_LANGUAGE=newSettings.value("language", "en_US").toString();
00220        if(FET_LANGUAGE=="en_GB") //because older versions of FET used en_GB as the default language. I changed it to en_US
00221               FET_LANGUAGE="en_US";
00222        WORKING_DIRECTORY=newSettings.value("working-directory", "examples").toString();
00223        IMPORT_DIRECTORY=newSettings.value("import-directory", OUTPUT_DIR).toString();
00224        
00225        QDir d(WORKING_DIRECTORY);
00226        if(!d.exists())
00227               WORKING_DIRECTORY="examples";
00228        QDir d2(WORKING_DIRECTORY);
00229        if(!d2.exists())
00230               WORKING_DIRECTORY=QDir::homePath();
00231        else
00232               WORKING_DIRECTORY=d2.absolutePath();
00233 
00234        QDir i(IMPORT_DIRECTORY);
00235        if(!i.exists())
00236               IMPORT_DIRECTORY=OUTPUT_DIR;
00237        
00238        checkForUpdates=newSettings.value("check-for-updates", "false").toBool();
00239 
00240        QString ver=newSettings.value("version", "-1").toString();
00241        
00242        TIMETABLE_HTML_LEVEL=newSettings.value("html-level", "2").toInt();
00243 
00244        PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME=newSettings.value("print-activities-with-same-starting-time", "false").toBool();
00245        PRINT_NOT_AVAILABLE_TIME_SLOTS=newSettings.value("print-not-available", "true").toBool();
00246        PRINT_BREAK_TIME_SLOTS=newSettings.value("print-break", "true").toBool();
00247        DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS=newSettings.value("divide-html-timetables-with-time-axis-by-days", "false").toBool();
00248        
00249        USE_GUI_COLORS=newSettings.value("use-gui-colors", "false").toBool();
00250 
00252        CONFIRM_ACTIVITY_PLANNING=newSettings.value("confirm-activity-planning", "true").toBool();
00253        CONFIRM_SPREAD_ACTIVITIES=newSettings.value("confirm-spread-activities", "true").toBool();
00254        CONFIRM_REMOVE_REDUNDANT=newSettings.value("confirm-remove-redundant", "true").toBool();
00255        CONFIRM_SAVE_TIMETABLE=newSettings.value("confirm-save-data-and-timetable", "true").toBool();
00257 
00258        ENABLE_ACTIVITY_TAG_MAX_HOURS_DAILY=newSettings.value("enable-activity-tag-max-hours-daily", "false").toBool();
00259        ENABLE_STUDENTS_MAX_GAPS_PER_DAY=newSettings.value("enable-students-max-gaps-per-day", "false").toBool();
00260        SHOW_WARNING_FOR_NOT_PERFECT_CONSTRAINTS=newSettings.value("warn-if-using-not-perfect-constraints", "true").toBool();
00261        ENABLE_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS=newSettings.value("enable-students-min-hours-daily-with-allow-empty-days", "false").toBool();
00262        SHOW_WARNING_FOR_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS=newSettings.value("warn-if-using-students-min-hours-daily-with-allow-empty-days", "true").toBool();
00263        
00264        //main form
00265        QRect rect=newSettings.value("FetMainForm/geometry", QRect(0,0,0,0)).toRect();
00266        mainFormSettingsRect=rect;
00267        MAIN_FORM_SHORTCUTS_TAB_POSITION=newSettings.value("FetMainForm/shortcuts-tab-position", "0").toInt();
00268        SHOW_SHORTCUTS_ON_MAIN_WINDOW=newSettings.value("FetMainForm/show-shortcuts", "true").toBool();
00269        
00270        cout<<"Settings read"<<endl;
00271 }
00272 
00273 void writeSimulationParameters()
00274 {
00275        QSettings settings(COMPANY, PROGRAM);
00276 
00277        settings.setValue("output-directory", OUTPUT_DIR);
00278        settings.setValue("language", FET_LANGUAGE);
00279        settings.setValue("working-directory", WORKING_DIRECTORY);
00280        settings.setValue("import-directory", IMPORT_DIRECTORY);
00281        settings.setValue("version", FET_VERSION);
00282        settings.setValue("check-for-updates", checkForUpdates);
00283        settings.setValue("html-level", TIMETABLE_HTML_LEVEL);
00284        
00285        settings.setValue("print-activities-with-same-starting-time", PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME);
00286        settings.setValue("divide-html-timetables-with-time-axis-by-days", DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS);
00287        settings.setValue("print-not-available", PRINT_NOT_AVAILABLE_TIME_SLOTS);
00288        settings.setValue("print-break", PRINT_BREAK_TIME_SLOTS);
00289        
00290        settings.setValue("use-gui-colors", USE_GUI_COLORS);
00291        
00293        settings.setValue("confirm-activity-planning", CONFIRM_ACTIVITY_PLANNING);
00294        settings.setValue("confirm-spread-activities", CONFIRM_SPREAD_ACTIVITIES);
00295        settings.setValue("confirm-remove-redundant", CONFIRM_REMOVE_REDUNDANT);
00296        settings.setValue("confirm-save-data-and-timetable", CONFIRM_SAVE_TIMETABLE);
00298 
00299        settings.setValue("enable-activity-tag-max-hours-daily", ENABLE_ACTIVITY_TAG_MAX_HOURS_DAILY);
00300        settings.setValue("enable-students-max-gaps-per-day", ENABLE_STUDENTS_MAX_GAPS_PER_DAY);
00301        settings.setValue("warn-if-using-not-perfect-constraints", SHOW_WARNING_FOR_NOT_PERFECT_CONSTRAINTS);
00302        settings.setValue("enable-students-min-hours-daily-with-allow-empty-days", ENABLE_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS);
00303        settings.setValue("warn-if-using-students-min-hours-daily-with-allow-empty-days", SHOW_WARNING_FOR_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS);
00304 
00305        //main form
00306        settings.setValue("FetMainForm/geometry", mainFormSettingsRect);
00307        settings.setValue("FetMainForm/shortcuts-tab-position", MAIN_FORM_SHORTCUTS_TAB_POSITION);
00308        settings.setValue("FetMainForm/show-shortcuts", SHOW_SHORTCUTS_ON_MAIN_WINDOW);
00309 }
00310 
00311 void setLanguage(QApplication& qapplication, QWidget* parent)
00312 {
00313        static int cntTranslators=0;
00314        
00315        if(cntTranslators>0){
00316               qapplication.removeTranslator(&translator);
00317               cntTranslators=0;
00318        }
00319 
00320        //translator stuff
00321        QDir d("/usr/share/fet/translations");
00322        
00323        bool translation_loaded=false;
00324        
00325        //this is one place (out of 2) in which you need to add a new language
00326        if(FET_LANGUAGE=="ar" || FET_LANGUAGE=="ca" || FET_LANGUAGE=="de" || FET_LANGUAGE=="es"
00327         || FET_LANGUAGE=="el" || FET_LANGUAGE=="fr" || FET_LANGUAGE=="hu" || FET_LANGUAGE=="mk"
00328         || FET_LANGUAGE=="ms" || FET_LANGUAGE=="nl" || FET_LANGUAGE=="pl" || FET_LANGUAGE=="ro"
00329         || FET_LANGUAGE=="tr" || FET_LANGUAGE=="id" || FET_LANGUAGE=="it" || FET_LANGUAGE=="lt"
00330         || FET_LANGUAGE=="ru" || FET_LANGUAGE=="fa" || FET_LANGUAGE=="uk" || FET_LANGUAGE=="pt_BR"
00331         || FET_LANGUAGE=="da" || FET_LANGUAGE=="si" || FET_LANGUAGE=="sk" || FET_LANGUAGE=="he"
00332         || FET_LANGUAGE=="sr" || FET_LANGUAGE=="gl" || FET_LANGUAGE=="vi" || FET_LANGUAGE=="uz"){
00333 
00334               translation_loaded=translator.load("fet_"+FET_LANGUAGE, qapplication.applicationDirPath());
00335               if(!translation_loaded){
00336                      translation_loaded=translator.load("fet_"+FET_LANGUAGE, qapplication.applicationDirPath()+"/translations");
00337                      if(!translation_loaded){
00338                             if(d.exists()){
00339                                    translation_loaded=translator.load("fet_"+FET_LANGUAGE, "/usr/share/fet/translations");
00340                             }
00341                      }
00342               }
00343        }
00344        else{
00345               if(FET_LANGUAGE!="en_US"){
00346                      QMessageBox::warning(parent, QString("FET warning"),
00347                       QString("Specified language is incorrect - making it en_US (US English)"));
00348                      FET_LANGUAGE="en_US";
00349               }
00350               
00351               assert(FET_LANGUAGE=="en_US");
00352               
00353               translation_loaded=true;
00354        }
00355        
00356        if(!translation_loaded){
00357               QMessageBox::warning(parent, QString("FET warning"),
00358                QString("Translation for specified language not loaded - maybe the translation file is missing - setting the language to en_US (US English)")
00359                +"\n\n"+
00360                QString("FET searched for the translation file %1 in the directory %2, then in the directory %3 and "
00361                "then in the directory %4 (under systems that support such a directory), but could not find it.")
00362                .arg("fet_"+FET_LANGUAGE+".qm")
00363                .arg(QDir::toNativeSeparators(qapplication.applicationDirPath()))
00364                .arg(QDir::toNativeSeparators(qapplication.applicationDirPath()+"/translations"))
00365                .arg("/usr/share/fet/translations")
00366                );
00367               FET_LANGUAGE="en_US";
00368        }
00369        
00370        if(FET_LANGUAGE=="ar" || FET_LANGUAGE=="he" || FET_LANGUAGE=="fa" || FET_LANGUAGE=="ur" /* and others? */){
00371               LANGUAGE_STYLE_RIGHT_TO_LEFT=true;
00372        }
00373        else{
00374               LANGUAGE_STYLE_RIGHT_TO_LEFT=false;
00375        }
00376        
00377        if(FET_LANGUAGE=="zh_CN"){
00378               LANGUAGE_FOR_HTML="zh-Hans";
00379        }
00380        else if(FET_LANGUAGE=="zh_TW"){
00381               LANGUAGE_FOR_HTML="zh-Hant";
00382        }
00383        else if(FET_LANGUAGE=="en_US"){
00384               LANGUAGE_FOR_HTML=FET_LANGUAGE.left(2);
00385        }
00386        else{
00387               LANGUAGE_FOR_HTML=FET_LANGUAGE;
00388               LANGUAGE_FOR_HTML.replace(QString("_"), QString("-"));
00389        }
00390        
00391        assert(cntTranslators==0);
00392        if(FET_LANGUAGE!="en_US"){
00393               qapplication.installTranslator(&translator);
00394               cntTranslators=1;
00395        }
00396        
00397        if(LANGUAGE_STYLE_RIGHT_TO_LEFT==true)
00398               qapplication.setLayoutDirection(Qt::RightToLeft);
00399        
00400        //retranslate
00401        QList<QWidget*> tlwl=qapplication.topLevelWidgets();
00402 
00403        foreach(QWidget* wi, tlwl)
00404               if(wi->isVisible()){
00405                      FetMainForm* mainform=qobject_cast<FetMainForm*>(wi);
00406                      if(mainform!=NULL){
00407                             mainform->retranslateUi(mainform);
00408                             continue;
00409                      }
00410 
00411                      //help
00412                      HelpAboutForm* aboutf=qobject_cast<HelpAboutForm*>(wi);
00413                      if(aboutf!=NULL){
00414                             aboutf->retranslateUi(aboutf);
00415                             continue;
00416                      }
00417 
00418                      HelpFaqForm* faqf=qobject_cast<HelpFaqForm*>(wi);
00419                      if(faqf!=NULL){
00420                             faqf->retranslateUi(faqf);
00421                             faqf->setText();
00422                             continue;
00423                      }
00424 
00425                      HelpTipsForm* tipsf=qobject_cast<HelpTipsForm*>(wi);
00426                      if(tipsf!=NULL){
00427                             tipsf->retranslateUi(tipsf);
00428                             tipsf->setText();
00429                             continue;
00430                      }
00431 
00432                      HelpInstructionsForm* instrf=qobject_cast<HelpInstructionsForm*>(wi);
00433                      if(instrf!=NULL){
00434                             instrf->retranslateUi(instrf);
00435                             instrf->setText();
00436                             continue;
00437                      }
00439                      
00440                      //timetable
00441                      TimetableViewStudentsForm* vsf=qobject_cast<TimetableViewStudentsForm*>(wi);
00442                      if(vsf!=NULL){
00443                             vsf->retranslateUi(vsf);
00444                             vsf->updateStudentsTimetableTable();
00445                             continue;
00446                      }
00447 
00448                      TimetableViewTeachersForm* vtchf=qobject_cast<TimetableViewTeachersForm*>(wi);
00449                      if(vtchf!=NULL){
00450                             vtchf->retranslateUi(vtchf);
00451                             vtchf->updateTeachersTimetableTable();
00452                             continue;
00453                      }
00454 
00455                      TimetableViewRoomsForm* vrf=qobject_cast<TimetableViewRoomsForm*>(wi);
00456                      if(vrf!=NULL){
00457                             vrf->retranslateUi(vrf);
00458                             vrf->updateRoomsTimetableTable();
00459                             continue;
00460                      }
00461 
00462                      TimetableShowConflictsForm* scf=qobject_cast<TimetableShowConflictsForm*>(wi);
00463                      if(scf!=NULL){
00464                             scf->retranslateUi(scf);
00465                             continue;
00466                      }
00467               }
00468 }
00469 
00470 void SomeQtTranslations()
00471 {
00472        //This function is never actually used
00473        //It just contains some commonly used Qt strings, so that some Qt strings of FET are translated.
00474        QString s1=QCoreApplication::translate("QDialogButtonBox", "&OK", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different");
00475        Q_UNUSED(s1);
00476        QString s2=QCoreApplication::translate("QDialogButtonBox", "OK");
00477        Q_UNUSED(s2);
00478        
00479        QString s3=QCoreApplication::translate("QDialogButtonBox", "&Cancel", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different");
00480        Q_UNUSED(s3);
00481        QString s4=QCoreApplication::translate("QDialogButtonBox", "Cancel");
00482        Q_UNUSED(s4);
00483        
00484        QString s5=QCoreApplication::translate("QDialogButtonBox", "&Yes", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different");
00485        Q_UNUSED(s5);
00486        QString s6=QCoreApplication::translate("QDialogButtonBox", "Yes to &All", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different. Please keep the translation short.");
00487        Q_UNUSED(s6);
00488        QString s7=QCoreApplication::translate("QDialogButtonBox", "&No", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different");
00489        Q_UNUSED(s7);
00490        QString s8=QCoreApplication::translate("QDialogButtonBox", "N&o to All", "Accelerator key (letter after ampersand) for &OK, &Cancel, &Yes, Yes to &All, &No, N&o to All, must be different. Please keep the translation short.");
00491        Q_UNUSED(s8);
00492 }
00493 
00497 int main(int argc, char **argv)
00498 {
00499        terminateGeneratePointer=NULL;
00500        
00501        QApplication qapplication(argc, argv);
00502        
00503        QObject::connect(&qapplication, SIGNAL(lastWindowClosed()), &qapplication, SLOT(quit()));
00504 
00505        srand(unsigned(time(NULL))); //useless, I use randomKnuth(), but just in case I use somewhere rand() by mistake...
00506 
00507        initRandomKnuth();
00508 
00509        OUTPUT_DIR=QDir::homePath()+FILE_SEP+"fet-results";
00510        
00511        QStringList _args=QCoreApplication::arguments();
00512 
00513        if(_args.count()==1){
00514               readSimulationParameters();
00515        
00516               QDir dir;
00517        
00518               bool t=true;
00519 
00520               //make sure that the output directory exists
00521               if(!dir.exists(OUTPUT_DIR))
00522                      t=dir.mkpath(OUTPUT_DIR);
00523 
00524               if(!t){
00525                      QMessageBox::critical(NULL, FetTranslate::tr("FET critical"), FetTranslate::tr("Cannot create or use %1 directory (where the results should be stored) - you can continue operation, but you might not be able to work with FET."
00526                       " Maybe you can try to change the output directory from the 'Settings' menu. If this is a bug - please report it.").arg(QDir::toNativeSeparators(OUTPUT_DIR)));
00527               }
00528               
00529               QString testFileName=OUTPUT_DIR+FILE_SEP+"test_write_permissions_1.tmp";
00530               QFile test(testFileName);
00531               bool existedBefore=test.exists();
00532               bool t_t=test.open(QIODevice::ReadWrite);
00533               if(!t_t){
00534                      QMessageBox::critical(NULL, FetTranslate::tr("FET critical"), FetTranslate::tr("You don't have write permissions in the output directory "
00535                       "(FET cannot open or create file %1) - you might not be able to work correctly with FET. Maybe you can try to change the output directory from the 'Settings' menu."
00536                       " If this is a bug - please report it.").arg(testFileName));
00537               }
00538               else{
00539                      test.close();
00540                      if(!existedBefore)
00541                             test.remove();
00542               }
00543        }
00544 
00545        students_schedule_ready=0;
00546        teachers_schedule_ready=0;
00547        rooms_schedule_ready=0;
00548 
00550        //begin command line
00551        if(_args.count()>1){
00552               int randomSeedX=-1;
00553               int randomSeedY=-1;
00554               bool randomSeedXSpecified=false;
00555               bool randomSeedYSpecified=false;
00556        
00557               QString outputDirectory="";
00558        
00559               INPUT_FILENAME_XML="";
00560               
00561               QString filename="";
00562               
00563               int secondsLimit=2000000000;
00564               
00565               TIMETABLE_HTML_LEVEL=2;
00566               
00567               FET_LANGUAGE="en_US";
00568               
00569               PRINT_NOT_AVAILABLE_TIME_SLOTS=true;
00570               
00571               PRINT_BREAK_TIME_SLOTS=true;
00572               
00573               DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS=false;
00574 
00575               PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME=false;
00576               
00577               QStringList unrecognizedOptions;
00578               
00579               SHOW_WARNING_FOR_NOT_PERFECT_CONSTRAINTS=true;
00580               
00581               SHOW_WARNING_FOR_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS=true;
00582               
00583               bool showVersion=false;
00584               
00585               for(int i=1; i<_args.count(); i++){
00586                      QString s=_args[i];
00587                      
00588                      if(s.left(12)=="--inputfile=")
00589                             filename=QDir::fromNativeSeparators(s.right(s.length()-12));
00590                      else if(s.left(19)=="--timelimitseconds=")
00591                             secondsLimit=s.right(s.length()-19).toInt();
00592                      else if(s.left(21)=="--timetablehtmllevel=")
00593                             TIMETABLE_HTML_LEVEL=s.right(s.length()-21).toInt();
00594                      else if(s.left(12)=="--htmllevel=")
00595                             TIMETABLE_HTML_LEVEL=s.right(s.length()-12).toInt();
00596                      else if(s.left(11)=="--language=")
00597                             FET_LANGUAGE=s.right(s.length()-11);
00598                      else if(s.left(20)=="--printnotavailable="){
00599                             if(s.right(5)=="false")
00600                                    PRINT_NOT_AVAILABLE_TIME_SLOTS=false;
00601                             else
00602                                    PRINT_NOT_AVAILABLE_TIME_SLOTS=true;
00603                      }
00604                      else if(s.left(13)=="--printbreak="){
00605                             if(s.right(5)=="false")
00606                                    PRINT_BREAK_TIME_SLOTS=false;
00607                             else
00608                                    PRINT_BREAK_TIME_SLOTS=true;
00609                      }
00610                      else if(s.left(23)=="--dividetimeaxisbydays="){
00611                             if(s.right(5)=="false")
00612                                    DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS=false;
00613                             else
00614                                    DIVIDE_HTML_TIMETABLES_WITH_TIME_AXIS_BY_DAYS=true;
00615                      }
00616                      else if(s.left(12)=="--outputdir="){
00617                             outputDirectory=QDir::fromNativeSeparators(s.right(s.length()-12));
00618                      }
00619                      else if(s.left(30)=="--printsimultaneousactivities="){
00620                             if(s.right(5)=="false")
00621                                    PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME=false;
00622                             else
00623                                    PRINT_ACTIVITIES_WITH_SAME_STARTING_TIME=true;
00624                      }
00625                      else if(s.left(14)=="--randomseedx="){
00626                             randomSeedXSpecified=true;
00627                             randomSeedX=s.right(s.length()-14).toInt();
00628                      }
00629                      else if(s.left(14)=="--randomseedy="){
00630                             randomSeedYSpecified=true;
00631                             randomSeedY=s.right(s.length()-14).toInt();
00632                      }
00633                      else if(s.left(35)=="--warnifusingnotperfectconstraints="){
00634                             if(s.right(5)=="false")
00635                                    SHOW_WARNING_FOR_NOT_PERFECT_CONSTRAINTS=false;
00636                      }
00637                      else if(s.left(53)=="--warnifusingstudentsminhoursdailywithallowemptydays="){
00638                             if(s.right(5)=="false")
00639                                    SHOW_WARNING_FOR_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS=false;
00640                      }
00641                      else if(s=="--version"){
00642                             showVersion=true;
00643                      }
00644                      else
00645                             unrecognizedOptions.append(s);
00646               }
00647               
00648               INPUT_FILENAME_XML=filename;
00649               
00650               QString initialDir=outputDirectory;
00651               if(initialDir!="")
00652                      initialDir.append(FILE_SEP);
00653               
00654               if(outputDirectory!="")
00655                      outputDirectory.append(FILE_SEP);
00656               outputDirectory.append("timetables");
00657 
00659               if(INPUT_FILENAME_XML!=""){
00660                      outputDirectory.append(FILE_SEP);
00661                      outputDirectory.append(INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1));
00662                      if(outputDirectory.right(4)==".fet")
00663                             outputDirectory=outputDirectory.left(outputDirectory.length()-4);
00664               }
00666               
00667               QDir dir;
00668               QString logsDir=initialDir+"logs";
00669               if(!dir.exists(logsDir))
00670                      dir.mkpath(logsDir);
00671               logsDir.append(FILE_SEP);
00672               
00674               QFile logFile(logsDir+"result.txt");
00675               bool tttt=logFile.open(QIODevice::WriteOnly);
00676               if(!tttt){
00677                      cout<<"FET critical - you don't have write permissions in the output directory - (FET cannot open or create file "<<qPrintable(logsDir)<<"result.txt)."
00678                       " If this is a bug - please report it."<<endl;
00679                      return 1;
00680               }
00681               QTextStream out(&logFile);
00683               
00684               setLanguage(qapplication, NULL);
00685               
00686               if(showVersion){
00687                      out<<"This file contains the result (log) of last operation"<<endl<<endl;
00688               
00689                      QDate dat=QDate::currentDate();
00690                      QTime tim=QTime::currentTime();
00691                      QLocale loc(FET_LANGUAGE);
00692                      QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
00693                      out<<"FET command line request for version started on "<<qPrintable(sTime)<<endl<<endl;
00694        
00695                      //QString qv=qVersion();
00696                      out<<"FET version "<<qPrintable(FET_VERSION)<<endl;
00697                      out<<"Free timetabling software, licensed under GNU GPL v2 or later"<<endl;
00698                      out<<"Copyright (C) 2002-2012 Liviu Lalescu"<<endl;
00699                      out<<"Homepage: http://lalescu.ro/liviu/fet/"<<endl;
00700                      //out<<" (Using Qt version "<<qPrintable(qv)<<")"<<endl;
00701                      cout<<"FET version "<<qPrintable(FET_VERSION)<<endl;
00702                      cout<<"Free timetabling software, licensed under GNU GPL v2 or later"<<endl;
00703                      cout<<"Copyright (C) 2002-2012 Liviu Lalescu"<<endl;
00704                      cout<<"Homepage: http://lalescu.ro/liviu/fet/"<<endl;
00705                      //cout<<" (Using Qt version "<<qPrintable(qv)<<")"<<endl;
00706 
00707                      if(unrecognizedOptions.count()>0){
00708                             out<<endl;
00709                             cout<<endl;
00710                             foreach(QString s, unrecognizedOptions){
00711                                    cout<<"Unrecognized option: "<<qPrintable(s)<<endl;
00712                                    out<<"Unrecognized option: "<<qPrintable(s)<<endl;
00713                             }
00714                      }
00715 
00716                      logFile.close();
00717                      return 0;
00718               }
00719               
00720               QFile maxPlacedActivityFile(logsDir+"max_placed_activities.txt");
00721               maxPlacedActivityFile.open(QIODevice::WriteOnly);
00722               QTextStream maxPlacedActivityStream(&maxPlacedActivityFile);
00723               maxPlacedActivityStream.setCodec("UTF-8");
00724               maxPlacedActivityStream.setGenerateByteOrderMark(true);
00725               maxPlacedActivityStream<<FetTranslate::tr("This is the list of max placed activities, chronologically. If FET could reach maximum n-th activity, look at the n+1-st activity"
00726                      " in the initial order of the activities")<<endl<<endl;
00727                             
00728               QFile initialOrderFile(logsDir+"initial_order.txt");
00729               initialOrderFile.open(QIODevice::WriteOnly);
00730               QTextStream initialOrderStream(&initialOrderFile);
00731               initialOrderStream.setCodec("UTF-8");
00732               initialOrderStream.setGenerateByteOrderMark(true);
00733                                           
00734               out<<"This file contains the result (log) of last operation"<<endl<<endl;
00735               
00736               QDate dat=QDate::currentDate();
00737               QTime tim=QTime::currentTime();
00738               QLocale loc(FET_LANGUAGE);
00739               QString sTime=loc.toString(dat, QLocale::ShortFormat)+" "+loc.toString(tim, QLocale::ShortFormat);
00740               out<<"FET command line simulation started on "<<qPrintable(sTime)<<endl<<endl;
00741               
00742               if(unrecognizedOptions.count()>0){
00743                      foreach(QString s, unrecognizedOptions){
00744                             cout<<"Unrecognized option: "<<qPrintable(s)<<endl;
00745                             out<<"Unrecognized option: "<<qPrintable(s)<<endl;
00746                      }
00747                      cout<<endl;
00748                      out<<endl;
00749               }
00750               
00751               if(outputDirectory!="")
00752                      if(!dir.exists(outputDirectory))
00753                             dir.mkpath(outputDirectory);
00754               
00755               if(outputDirectory!="")
00756                      outputDirectory.append(FILE_SEP);
00757                      
00758               QFile test(outputDirectory+"test_write_permissions_2.tmp");
00759               bool existedBefore=test.exists();
00760               bool t_t=test.open(QIODevice::ReadWrite);
00761               if(!t_t){
00762                      cout<<"fet: critical error - you don't have write permissions in the output directory - (FET cannot open or create file "<<qPrintable(outputDirectory)<<"test_write_permissions_2.tmp)."
00763                       " If this is a bug - please report it."<<endl;
00764                      out<<"fet: critical error - you don't have write permissions in the output directory - (FET cannot open or create file "<<qPrintable(outputDirectory)<<"test_write_permissions_2.tmp)."
00765                       " If this is a bug - please report it."<<endl;
00766                      return 1;
00767               }
00768               else{
00769                      test.close();
00770                      if(!existedBefore)
00771                             test.remove();
00772               }
00773 
00774               if(filename==""){
00775                      usage(out, QString("Input file not specified"));
00776                      logFile.close();
00777                      return 1;
00778               }
00779               if(secondsLimit==0){
00780                      usage(out, QString("Time limit is 0 seconds"));
00781                      logFile.close();
00782                      return 1;
00783               }
00784               if(TIMETABLE_HTML_LEVEL>6 || TIMETABLE_HTML_LEVEL<0){
00785                      usage(out, QString("Html level must be 0, 1, 2, 3, 4, 5 or 6"));
00786                      logFile.close();
00787                      return 1;
00788               }
00789               if(randomSeedXSpecified != randomSeedYSpecified){
00790                      if(randomSeedXSpecified){
00791                             usage(out, QString("If you want to specify the random seed, you need to specify both the X and the Y components, not only the X component"));
00792                      }
00793                      else{
00794                             assert(randomSeedYSpecified);
00795                             usage(out, QString("If you want to specify the random seed, you need to specify both the X and the Y components, not only the Y component"));
00796                      }
00797                      logFile.close();
00798                      return 1;
00799               }
00800               assert(randomSeedXSpecified==randomSeedYSpecified);
00801               if(randomSeedXSpecified){
00802                      if(randomSeedX<=0 || randomSeedX>=MM){
00803                             usage(out, QString("Random seed X component must be at least 1 and at most %1").arg(MM-1));
00804                             logFile.close();
00805                             return 1;
00806                      }
00807               }
00808               if(randomSeedYSpecified){
00809                      if(randomSeedY<=0 || randomSeedY>=MMM){
00810                             usage(out, QString("Random seed Y component must be at least 1 and at most %1").arg(MMM-1));
00811                             logFile.close();
00812                             return 1;
00813                      }
00814               }
00815               
00816               if(randomSeedXSpecified){
00817                      assert(randomSeedYSpecified);
00818                      if(randomSeedX>0 && randomSeedX<MM && randomSeedY>0 && randomSeedY<MMM){
00819                             XX=randomSeedX;
00820                             YY=randomSeedY;
00821                      }
00822               }
00823               
00824               if(TIMETABLE_HTML_LEVEL>6 || TIMETABLE_HTML_LEVEL<0)
00825                      TIMETABLE_HTML_LEVEL=2;
00826        
00827               bool t=gt.rules.read(NULL, filename, true, initialDir);
00828               if(!t){
00829                      cout<<"fet: cannot read input file (not existing or in use) - aborting"<<endl;
00830                      out<<"Cannot read input file (not existing or in use) - aborting"<<endl;
00831                      logFile.close();
00832                      return 1;
00833               }
00834               
00835               t=gt.rules.computeInternalStructure(NULL);
00836               if(!t){
00837                      cout<<"Cannot compute internal structure - aborting"<<endl;
00838                      out<<"Cannot compute internal structure - aborting"<<endl;
00839                      logFile.close();
00840                      return 1;
00841               }
00842        
00843               Generate gen;
00844 
00845               terminateGeneratePointer=&gen;
00846               signal(SIGTERM, terminate);
00847        
00848               gen.abortOptimization=false;
00849               bool ok=gen.precompute(NULL, &initialOrderStream);
00850               
00851               initialOrderFile.close();
00852               
00853               if(!ok){
00854                      cout<<"Cannot precompute - data is wrong - aborting"<<endl;
00855                      out<<"Cannot precompute - data is wrong - aborting"<<endl;
00856                      logFile.close();
00857                      return 1;
00858               }
00859        
00860               bool impossible, timeExceeded;
00861               
00862               cout<<"secondsLimit=="<<secondsLimit<<endl;
00863               //out<<"secondsLimit=="<<secondsLimit<<endl;
00864                             
00865               TimetableExport::writeRandomSeedCommandLine(NULL, outputDirectory, true); //true represents 'before' state
00866 
00867               gen.generate(secondsLimit, impossible, timeExceeded, false, &maxPlacedActivityStream); //false means no thread
00868               
00869               maxPlacedActivityFile.close();
00870        
00871               if(impossible){
00872                      cout<<"Impossible"<<endl;
00873                      out<<"Impossible"<<endl;
00874               }
00875               //2012-01-24 - suggestion and code by Ian Holden (ian@ianholden.com), to write best and current timetable on time exceeded
00876               //previously, FET saved best and current timetable only on receiving SIGTERM
00877               //by Ian Holden (begin)
00878               else if(timeExceeded || gen.abortOptimization){
00879                      if(timeExceeded){
00880                             cout<<"Time exceeded"<<endl;
00881                             out<<"Time exceeded"<<endl;
00882                      }
00883                      else if(gen.abortOptimization){
00884                             cout<<"Simulation stopped"<<endl;
00885                             out<<"Simulation stopped"<<endl;
00886                      }
00887                      //by Ian Holden (end)
00888                      
00889                      //2011-11-11 (1)
00890                      //write current stage timetable
00891                      Solution& cc=gen.c;
00892 
00893                      //needed to find the conflicts strings
00894                      QString tmp;
00895                      cc.fitness(gt.rules, &tmp);
00896 
00897                      TimetableExport::getStudentsTimetable(cc);
00898                      TimetableExport::getTeachersTimetable(cc);
00899                      TimetableExport::getRoomsTimetable(cc);
00900 
00901                      QString toc=outputDirectory;
00902                      if(toc!="" && toc.count()>=1 && toc.endsWith(FILE_SEP)){
00903                             toc.chop(1);
00904                             toc+=QString("-current"+FILE_SEP);
00905                      }
00906                      else if(toc==""){
00907                             toc=QString("current"+FILE_SEP);
00908                      }
00909                      
00910                      if(toc!="")
00911                             if(!dir.exists(toc))
00912                                    dir.mkpath(toc);
00913 
00914                      TimetableExport::writeSimulationResultsCommandLine(NULL, toc);
00915                      
00916                      QString s;
00917 
00918                      if(maxActivitiesPlaced>=0 && maxActivitiesPlaced<gt.rules.nInternalActivities 
00919                       && initialOrderOfActivitiesIndices[maxActivitiesPlaced]>=0 && initialOrderOfActivitiesIndices[maxActivitiesPlaced]<gt.rules.nInternalActivities){
00920                             s=FetTranslate::tr("FET managed to schedule correctly the first %1 most difficult activities."
00921                              " You can see initial order of placing the activities in the corresponding output file. The activity which might cause problems"
00922                              " might be the next activity in the initial order of evaluation. This activity is listed below:").arg(maxActivitiesPlaced);
00923                             s+=QString("\n\n");
00924                      
00925                             int ai=initialOrderOfActivitiesIndices[maxActivitiesPlaced];
00926 
00927                             s+=FetTranslate::tr("Id: %1 (%2)", "%1 is id of activity, %2 is detailed description of activity")
00928                              .arg(gt.rules.internalActivitiesList[ai].id)
00929                              .arg(getActivityDetailedDescription(gt.rules, gt.rules.internalActivitiesList[ai].id));
00930                      }
00931                      else
00932                             s=FetTranslate::tr("Difficult activity cannot be computed - please report possible bug");
00933                      
00934                      s+=QString("\n\n----------\n\n");
00935                      
00936                      s+=FetTranslate::tr("Here are the placed activities which lead to an inconsistency, "
00937                       "in order from the first one to the last (the last one FET failed to schedule "
00938                       "and the last ones are most likely impossible):");
00939                      s+="\n\n";
00940                      for(int i=0; i<gen.nDifficultActivities; i++){
00941                             int ai=gen.difficultActivities[i];
00942 
00943                             s+=FetTranslate::tr("No: %1").arg(i+1);
00944               
00945                             s+=", ";
00946 
00947                             s+=FetTranslate::tr("Id: %1 (%2)", "%1 is id of activity, %2 is detailed description of activity")
00948                                    .arg(gt.rules.internalActivitiesList[ai].id)
00949                                    .arg(getActivityDetailedDescription(gt.rules, gt.rules.internalActivitiesList[ai].id));
00950 
00951                             s+="\n";
00952                      }
00953                      
00954                      QFile difficultActivitiesFile(logsDir+"difficult_activities.txt");
00955                      bool t=difficultActivitiesFile.open(QIODevice::WriteOnly);
00956                      if(!t){
00957                             cout<<"FET critical - you don't have write permissions in the output directory - (FET cannot open or create file "<<qPrintable(logsDir)<<"difficult_activities.txt)."
00958                              " If this is a bug - please report it."<<endl;
00959                             return 1;
00960                      }
00961                      QTextStream difficultActivitiesOut(&difficultActivitiesFile);
00962                      difficultActivitiesOut.setCodec("UTF-8");
00963                      difficultActivitiesOut.setGenerateByteOrderMark(true);
00964                      
00965                      difficultActivitiesOut<<s<<endl;
00966                      
00967                      //2011-11-11 (2)
00968                      //write highest stage timetable
00969                      Solution& ch=highestStageSolution;
00970 
00971                      //needed to find the conflicts strings
00972                      QString tmp2;
00973                      ch.fitness(gt.rules, &tmp2);
00974 
00975                      TimetableExport::getStudentsTimetable(ch);
00976                      TimetableExport::getTeachersTimetable(ch);
00977                      TimetableExport::getRoomsTimetable(ch);
00978 
00979                      QString toh=outputDirectory;
00980                      if(toh!="" && toh.count()>=1 && toh.endsWith(FILE_SEP)){
00981                             toh.chop(1);
00982                             toh+=QString("-highest"+FILE_SEP);
00983                      }
00984                      else if(toh==""){
00985                             toh=QString("highest"+FILE_SEP);
00986                      }
00987                      
00988                      if(toh!="")
00989                             if(!dir.exists(toh))
00990                                    dir.mkpath(toh);
00991 
00992                      TimetableExport::writeSimulationResultsCommandLine(NULL, toh);
00993               }
00994               else{
00995                      cout<<"Simulation successful"<<endl;
00996                      out<<"Simulation successful"<<endl;
00997               
00998                      TimetableExport::writeRandomSeedCommandLine(NULL, outputDirectory, false); //false represents 'before' state
00999 
01000                      Solution& c=gen.c;
01001 
01002                      //needed to find the conflicts strings
01003                      QString tmp;
01004                      c.fitness(gt.rules, &tmp);
01005                      
01006                      TimetableExport::getStudentsTimetable(c);
01007                      TimetableExport::getTeachersTimetable(c);
01008                      TimetableExport::getRoomsTimetable(c);
01009 
01010                      TimetableExport::writeSimulationResultsCommandLine(NULL, outputDirectory);
01011               }
01012        
01013               logFile.close();
01014               return 0;
01015        }
01016        //end command line
01018 
01019        setLanguage(qapplication, NULL);
01020 
01021        pqapplication=&qapplication;
01022        FetMainForm fetMainForm;
01023        pFetMainForm=&fetMainForm;
01024        fetMainForm.show();
01025 
01026        int tmp2=qapplication.exec();
01027        
01028        writeSimulationParameters();
01029        
01030        cout<<"Settings saved"<<endl;
01031        
01032        pFetMainForm=NULL;
01033        
01034        return tmp2;
01035 }