Back to index

fet  5.18.0
addactivityform.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           addactivityform.cpp  -  description
00003                              -------------------
00004     begin                : Wed Apr 23 2003
00005     copyright            : (C) 2003 by Lalescu Liviu
00006     email                : Please see http://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "longtextmessagebox.h"
00019 
00020 #include "addactivityform.h"
00021 #include "teacher.h"
00022 #include "subject.h"
00023 #include "studentsset.h"
00024 
00025 #include "activityplanningform.h"
00026 
00027 #include <QMessageBox>
00028 
00029 #include <QDialog>
00030 
00031 #include <QtGui>
00032 
00033 #include <QList>
00034 
00035 #include <QListWidget>
00036 #include <QAbstractItemView>
00037 #include <QModelIndex>
00038 #include <QScrollBar>
00039 
00040 QSpinBox* AddActivityForm::dur(int i)
00041 {
00042        assert(i>=0 && i<durList.count());
00043        assert(i<MAX_SPLIT_OF_AN_ACTIVITY);
00044        return durList.at(i);
00045 }
00046 
00047 QCheckBox* AddActivityForm::activ(int i)
00048 {
00049        assert(i>=0 && i<activList.count());
00050        assert(i<MAX_SPLIT_OF_AN_ACTIVITY);
00051        return activList.at(i);
00052 }
00053 
00054 AddActivityForm::AddActivityForm(QWidget* parent, const QString& teacherName, const QString& studentsSetName, const QString& subjectName, const QString& activityTagName): QDialog(parent)
00055 {
00056        setupUi(this);
00057        
00058        allTeachersListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00059        selectedTeachersListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00060        allStudentsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00061        selectedStudentsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00062        allActivityTagsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00063        selectedActivityTagsListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
00064 
00065        splitSpinBox->setMaximum(MAX_SPLIT_OF_AN_ACTIVITY);
00066 
00067        durList.clear();
00068        durList.append(duration1SpinBox);
00069        durList.append(duration2SpinBox);
00070        durList.append(duration3SpinBox);
00071        durList.append(duration4SpinBox);
00072        durList.append(duration5SpinBox);
00073        durList.append(duration6SpinBox);
00074        durList.append(duration7SpinBox);
00075        durList.append(duration8SpinBox);
00076        durList.append(duration9SpinBox);
00077        durList.append(duration10SpinBox);
00078        durList.append(duration11SpinBox);
00079        durList.append(duration12SpinBox);
00080        durList.append(duration13SpinBox);
00081        durList.append(duration14SpinBox);
00082        durList.append(duration15SpinBox);
00083        durList.append(duration16SpinBox);
00084        durList.append(duration17SpinBox);
00085        durList.append(duration18SpinBox);
00086        durList.append(duration19SpinBox);
00087        durList.append(duration20SpinBox);
00088        durList.append(duration21SpinBox);
00089        durList.append(duration22SpinBox);
00090        durList.append(duration23SpinBox);
00091        durList.append(duration24SpinBox);
00092        durList.append(duration25SpinBox);
00093        durList.append(duration26SpinBox);
00094        durList.append(duration27SpinBox);
00095        durList.append(duration28SpinBox);
00096        durList.append(duration29SpinBox);
00097        durList.append(duration30SpinBox);
00098        durList.append(duration31SpinBox);
00099        durList.append(duration32SpinBox);
00100        durList.append(duration33SpinBox);
00101        durList.append(duration34SpinBox);
00102        durList.append(duration35SpinBox);
00103        
00104        for(int i=0; i<MAX_SPLIT_OF_AN_ACTIVITY; i++)
00105               dur(i)->setMaximum(gt.rules.nHoursPerDay);
00106 
00107        activList.clear();
00108        activList.append(active1CheckBox);
00109        activList.append(active2CheckBox);
00110        activList.append(active3CheckBox);
00111        activList.append(active4CheckBox);
00112        activList.append(active5CheckBox);
00113        activList.append(active6CheckBox);
00114        activList.append(active7CheckBox);
00115        activList.append(active8CheckBox);
00116        activList.append(active9CheckBox);
00117        activList.append(active10CheckBox);
00118        activList.append(active11CheckBox);
00119        activList.append(active12CheckBox);
00120        activList.append(active13CheckBox);
00121        activList.append(active14CheckBox);
00122        activList.append(active15CheckBox);
00123        activList.append(active16CheckBox);
00124        activList.append(active17CheckBox);
00125        activList.append(active18CheckBox);
00126        activList.append(active19CheckBox);
00127        activList.append(active20CheckBox);
00128        activList.append(active21CheckBox);
00129        activList.append(active22CheckBox);
00130        activList.append(active23CheckBox);
00131        activList.append(active24CheckBox);
00132        activList.append(active25CheckBox);
00133        activList.append(active26CheckBox);
00134        activList.append(active27CheckBox);
00135        activList.append(active28CheckBox);
00136        activList.append(active29CheckBox);
00137        activList.append(active30CheckBox);
00138        activList.append(active31CheckBox);
00139        activList.append(active32CheckBox);
00140        activList.append(active33CheckBox);
00141        activList.append(active34CheckBox);
00142        activList.append(active35CheckBox);
00143 
00144        connect(subgroupsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showSubgroupsChanged()));
00145        connect(groupsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showGroupsChanged()));
00146        connect(yearsCheckBox, SIGNAL(toggled(bool)), this, SLOT(showYearsChanged()));
00147 
00148        connect(splitSpinBox, SIGNAL(valueChanged(int)), this, SLOT(splitChanged()));
00149 
00150        connect(closePushButton, SIGNAL(clicked()), this, SLOT(close()));
00151        connect(addActivityPushButton, SIGNAL(clicked()), this, SLOT(addActivity()));
00152        connect(helpPushButton, SIGNAL(clicked()), this, SLOT(help()));
00153 
00154        connect(allTeachersListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addTeacher()));
00155        connect(selectedTeachersListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeTeacher()));
00156        connect(allStudentsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addStudents()));
00157        connect(selectedStudentsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeStudents()));
00158        connect(allActivityTagsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(addActivityTag()));
00159        connect(selectedActivityTagsListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(removeActivityTag()));
00160 
00161        connect(clearActivityTagPushButton, SIGNAL(clicked()), this, SLOT(clearActivityTags()));
00162        connect(clearStudentsPushButton, SIGNAL(clicked()), this, SLOT(clearStudents()));
00163        connect(clearTeacherPushButton, SIGNAL(clicked()), this, SLOT(clearTeachers()));
00164 
00165        connect(minDayDistanceSpinBox, SIGNAL(valueChanged(int)), this, SLOT(minDaysChanged()));
00166 
00167        centerWidgetOnScreen(this);
00168        restoreFETDialogGeometry(this);
00169        
00170        QSize tmp3=subjectsComboBox->minimumSizeHint();
00171        Q_UNUSED(tmp3);
00172        
00173        selectedStudentsListWidget->clear();
00174        updateStudentsListWidget();
00175        updateTeachersListWidget();
00176        updateSubjectsComboBox();
00177        updateActivityTagsListWidget();
00178 
00179        minDayDistanceSpinBox->setMaximum(gt.rules.nDaysPerWeek);
00180        minDayDistanceSpinBox->setMinimum(0);
00181        minDayDistanceSpinBox->setValue(1);
00182        
00183        int nSplit=splitSpinBox->value();
00184        for(int i=0; i<MAX_SPLIT_OF_AN_ACTIVITY; i++){
00185               if(i<nSplit)
00186                      subactivitiesTabWidget->setTabEnabled(i, true);
00187               else
00188                      subactivitiesTabWidget->setTabEnabled(i, false);
00189        }
00190        
00191        minDayDistanceTextLabel->setEnabled(nSplit>=2);
00192        minDayDistanceSpinBox->setEnabled(nSplit>=2);
00193        percentageTextLabel->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00194        percentageLineEdit->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00195        forceConsecutiveCheckBox->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00196        
00197        subactivitiesTabWidget->setCurrentIndex(0);
00198        
00199        nStudentsSpinBox->setMinimum(-1);
00200        nStudentsSpinBox->setMaximum(MAX_ROOM_CAPACITY);
00201        nStudentsSpinBox->setValue(-1);
00202 
00203        addActivityPushButton->setDefault(true);
00204        addActivityPushButton->setFocus();
00205        
00206        if(teacherName!="")
00207               selectedTeachersListWidget->addItem(teacherName);
00208        if(studentsSetName!="")
00209               selectedStudentsListWidget->addItem(studentsSetName);
00210        if(subjectName!=""){
00211               int pos=-1;
00212               for(int i=0; i<subjectsComboBox->count(); i++){
00213                      if(subjectsComboBox->itemText(i)==subjectName){
00214                             pos=i;
00215                             break;
00216                      }
00217               }
00218               assert(pos>=0);
00219               subjectsComboBox->setCurrentIndex(pos);
00220        }
00221        else{
00222               //begin trick to pass a Qt 4.6.0 bug: the first entry is not highlighted with mouse until you move to second entry and then back up
00223               if(subjectsComboBox->view()){
00224                      subjectsComboBox->view()->setCurrentIndex(QModelIndex());
00225               }
00226               //end trick
00227               subjectsComboBox->setCurrentIndex(-1);
00228        }
00229        if(activityTagName!="")
00230               selectedActivityTagsListWidget->addItem(activityTagName);
00231 }
00232 
00233 AddActivityForm::~AddActivityForm()
00234 {
00235        saveFETDialogGeometry(this);
00236 }
00237 
00238 void AddActivityForm::updateTeachersListWidget()
00239 {
00240        allTeachersListWidget->clear();
00241        for(int i=0; i<gt.rules.teachersList.size(); i++){
00242               Teacher* tch=gt.rules.teachersList[i];
00243               allTeachersListWidget->addItem(tch->name);
00244        }
00245        
00246        selectedTeachersListWidget->clear();
00247 }
00248 
00249 void AddActivityForm::addTeacher()
00250 {
00251        if(allTeachersListWidget->currentRow()<0 || allTeachersListWidget->currentRow()>=allTeachersListWidget->count())
00252               return;
00253        
00254        for(int i=0; i<selectedTeachersListWidget->count(); i++)
00255               if(selectedTeachersListWidget->item(i)->text()==allTeachersListWidget->currentItem()->text())
00256                      return;
00257                      
00258        selectedTeachersListWidget->addItem(allTeachersListWidget->currentItem()->text());
00259        selectedTeachersListWidget->setCurrentRow(selectedTeachersListWidget->count()-1);
00260 }
00261 
00262 void AddActivityForm::removeTeacher()
00263 {
00264        if(selectedTeachersListWidget->count()<=0 || selectedTeachersListWidget->currentRow()<0 ||
00265         selectedTeachersListWidget->currentRow()>=selectedTeachersListWidget->count())
00266               return;
00267        
00268        int i=selectedTeachersListWidget->currentRow();
00269        selectedTeachersListWidget->setCurrentRow(-1);
00270        QListWidgetItem* item=selectedTeachersListWidget->takeItem(i);
00271        delete item;
00272        if(i<selectedTeachersListWidget->count())
00273               selectedTeachersListWidget->setCurrentRow(i);
00274        else
00275               selectedTeachersListWidget->setCurrentRow(selectedTeachersListWidget->count()-1);
00276 }
00277 
00278 void AddActivityForm::addStudents()
00279 {
00280        if(allStudentsListWidget->currentRow()<0 || allStudentsListWidget->currentRow()>=allStudentsListWidget->count())
00281               return;
00282        
00283        assert(canonicalStudentsSetsNames.count()==allStudentsListWidget->count());
00284        QString sn=canonicalStudentsSetsNames.at(allStudentsListWidget->currentRow());
00285 
00286        for(int i=0; i<selectedStudentsListWidget->count(); i++)
00287               if(selectedStudentsListWidget->item(i)->text()==sn)
00288                      return;
00289        
00290        selectedStudentsListWidget->addItem(sn);
00291        selectedStudentsListWidget->setCurrentRow(selectedStudentsListWidget->count()-1);
00292 }
00293 
00294 void AddActivityForm::removeStudents()
00295 {
00296        if(selectedStudentsListWidget->count()<=0 || selectedStudentsListWidget->currentRow()<0 ||
00297         selectedStudentsListWidget->currentRow()>=selectedStudentsListWidget->count())
00298               return;
00299        
00300        int i=selectedStudentsListWidget->currentRow();
00301        selectedStudentsListWidget->setCurrentRow(-1);
00302        QListWidgetItem* item=selectedStudentsListWidget->takeItem(i);
00303        delete item;
00304        if(i<selectedStudentsListWidget->count())
00305               selectedStudentsListWidget->setCurrentRow(i);
00306        else
00307               selectedStudentsListWidget->setCurrentRow(selectedStudentsListWidget->count()-1);
00308 }
00309 
00310 void AddActivityForm::addActivityTag()
00311 {
00312        if(allActivityTagsListWidget->currentRow()<0 || allActivityTagsListWidget->currentRow()>=allActivityTagsListWidget->count())
00313               return;
00314        
00315        for(int i=0; i<selectedActivityTagsListWidget->count(); i++)
00316               if(selectedActivityTagsListWidget->item(i)->text()==allActivityTagsListWidget->currentItem()->text())
00317                      return;
00318        
00319        selectedActivityTagsListWidget->addItem(allActivityTagsListWidget->currentItem()->text());
00320        selectedActivityTagsListWidget->setCurrentRow(selectedActivityTagsListWidget->count()-1);
00321 }
00322 
00323 void AddActivityForm::removeActivityTag()
00324 {
00325        if(selectedActivityTagsListWidget->count()<=0 || selectedActivityTagsListWidget->currentRow()<0 ||
00326         selectedActivityTagsListWidget->currentRow()>=selectedActivityTagsListWidget->count())
00327               return;
00328        
00329        int i=selectedActivityTagsListWidget->currentRow();
00330        selectedActivityTagsListWidget->setCurrentRow(-1);
00331        QListWidgetItem* item=selectedActivityTagsListWidget->takeItem(i);
00332        delete item;
00333        if(i<selectedActivityTagsListWidget->count())
00334               selectedActivityTagsListWidget->setCurrentRow(i);
00335        else
00336               selectedActivityTagsListWidget->setCurrentRow(selectedActivityTagsListWidget->count()-1);
00337 }
00338 
00339 void AddActivityForm::updateSubjectsComboBox()
00340 {
00341        subjectsComboBox->clear();
00342        for(int i=0; i<gt.rules.subjectsList.size(); i++){
00343               Subject* sbj=gt.rules.subjectsList[i];
00344               subjectsComboBox->addItem(sbj->name);
00345        }
00346 }
00347 
00348 void AddActivityForm::updateActivityTagsListWidget()
00349 {
00350        allActivityTagsListWidget->clear();
00351        for(int i=0; i<gt.rules.activityTagsList.size(); i++){
00352               ActivityTag* at=gt.rules.activityTagsList[i];
00353               allActivityTagsListWidget->addItem(at->name);
00354        }
00355        
00356        selectedActivityTagsListWidget->clear();
00357 }
00358 
00359 void AddActivityForm::showYearsChanged()
00360 {
00361        updateStudentsListWidget();
00362 }
00363 
00364 void AddActivityForm::showGroupsChanged()
00365 {
00366        updateStudentsListWidget();
00367 }
00368 
00369 void AddActivityForm::showSubgroupsChanged()
00370 {
00371        updateStudentsListWidget();
00372 }
00373 
00374 void AddActivityForm::updateStudentsListWidget()
00375 {
00376        const int INDENT=2;
00377 
00378        bool showYears=yearsCheckBox->isChecked();
00379        bool showGroups=groupsCheckBox->isChecked();
00380        bool showSubgroups=subgroupsCheckBox->isChecked();
00381 
00382        allStudentsListWidget->clear();
00383        canonicalStudentsSetsNames.clear();
00384        for(int i=0; i<gt.rules.yearsList.size(); i++){
00385               StudentsYear* sty=gt.rules.yearsList[i];
00386               if(showYears){
00387                      allStudentsListWidget->addItem(sty->name);
00388                      canonicalStudentsSetsNames.append(sty->name);
00389               }
00390               for(int j=0; j<sty->groupsList.size(); j++){
00391                      StudentsGroup* stg=sty->groupsList[j];
00392                      if(showGroups){
00393                             QString begin=QString("");
00394                             QString end=QString("");
00395                             begin=QString(INDENT, ' ');
00396                             allStudentsListWidget->addItem(begin+stg->name+end);
00397                             canonicalStudentsSetsNames.append(stg->name);
00398                      }
00399                      for(int k=0; k<stg->subgroupsList.size(); k++){
00400                             StudentsSubgroup* sts=stg->subgroupsList[k];
00401                             if(showSubgroups){
00402                                    QString begin=QString("");
00403                                    QString end=QString("");
00404                                    begin=QString(2*INDENT, ' ');
00405                                    allStudentsListWidget->addItem(begin+sts->name+end);
00406                                    canonicalStudentsSetsNames.append(sts->name);
00407                             }
00408                      }
00409               }
00410        }
00411        
00412        int q=allStudentsListWidget->verticalScrollBar()->minimum();
00413        allStudentsListWidget->verticalScrollBar()->setValue(q);
00414 }
00415 
00416 void AddActivityForm::splitChanged()
00417 {
00418        int nSplit=splitSpinBox->value();
00419        
00420        minDayDistanceTextLabel->setEnabled(nSplit>=2);
00421        minDayDistanceSpinBox->setEnabled(nSplit>=2);
00422        percentageTextLabel->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00423        percentageLineEdit->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00424        forceConsecutiveCheckBox->setEnabled(nSplit>=2 && minDayDistanceSpinBox->value()>0);
00425 
00426        for(int i=0; i<MAX_SPLIT_OF_AN_ACTIVITY; i++)
00427               if(i<nSplit)
00428                      subactivitiesTabWidget->setTabEnabled(i, true);
00429               else
00430                      subactivitiesTabWidget->setTabEnabled(i, false);
00431 }
00432 
00433 SecondMinDaysDialog::SecondMinDaysDialog(QWidget* p, int minD, double w) :QDialog(p)
00434 {
00435        weight=-1;
00436 
00437        QString l=tr
00438         ("You selected min days between activities %1 (above 1) and weight %2 (under 100.0). "
00439          "Would you like to add also a second constraint to ensure that almost certainly the "
00440          "distance between activities is at least %3 (%1-1) days? If yes, please select weight (recommended "
00441          "95.0%-100.0%) and click Yes. If no, please click No (only one constraint will be added)").arg(CustomFETString::number(minD)).arg(w).arg(minD-1);
00442        l+="\n\n";
00443        l+=tr("(Yes means to add an additional constraint min %1 days between activities, weight 0.0%-100.0%. "
00444          "If you say Yes, you will have 2 constraints min days added for current activities. "
00445          "Adding the second constraint might lead to impossible timetables if the condition is "
00446          "too tight, but you can remove the second constraint at any time).").arg(minD-1);
00447        l+="\n\n";
00448        l+=tr("Note: 95% is usually enough for min days constraints referring to same activities. "
00449          "The weights are cumulated if referring to the same activities. If you have 2 constraints with say 95%"
00450          " (say min n days and min n-1 days), "
00451          "the min n days constraint is skipped with probability 5%, then min n-1 days constraint is skipped with "
00452          "probability 0.25%=5%*5%, so you'll get in 99.75% cases the min n-1 days constraint respected.");
00453        l+="\n\n";
00454        l+=tr("Recommended answer is Yes, 95% (or higher).");
00455 
00456        setWindowTitle(tr("Add a second constraint or not?"));
00457                             
00458        QVBoxLayout* vl=new QVBoxLayout(this);
00459        
00460        QPlainTextEdit* la=new QPlainTextEdit();
00461        la->setPlainText(l);
00462        la->setReadOnly(true);
00463 
00464        vl->addWidget(la);
00465                             
00466        QPushButton* yes=new QPushButton(tr("Yes"));
00467        yes->setDefault(true);
00468        
00469        QPushButton* no=new QPushButton(tr("No"));
00470 
00471        QLabel* percLabel=new QLabel(this);
00472        percLabel->setText("Percentage");
00473        percText=new QLineEdit(this);
00474        percText->setText("95.0");
00475        
00476        //QHBoxLayout* hl2=new QHBoxLayout(vl);
00477        QHBoxLayout* hl2=new QHBoxLayout();
00478        vl->addLayout(hl2);
00479        
00481        QLabel* minDaysLabel=new QLabel(this);
00482        minDaysLabel->setText("Min days");
00483        QSpinBox* minDaysSpinBox=new QSpinBox(this);
00484        minDaysSpinBox->setMinimum(minD-1);
00485        minDaysSpinBox->setMaximum(minD-1);
00486        minDaysSpinBox->setValue(minD-1);
00487        minDaysSpinBox->setEnabled(false);
00489 
00491        hl2->addStretch(1);
00492        hl2->addWidget(minDaysLabel);
00493        hl2->addWidget(minDaysSpinBox);
00495        
00496        hl2->addStretch(1);
00497        hl2->addWidget(percLabel);
00498        hl2->addWidget(percText);
00499        
00500        //QHBoxLayout* hl=new QHBoxLayout(vl);
00501        QHBoxLayout* hl=new QHBoxLayout();
00502        vl->addLayout(hl);
00503        
00504        hl->addStretch(1);
00505        hl->addWidget(yes);
00506        hl->addWidget(no);
00507        
00508        connect(yes, SIGNAL(clicked()), this, SLOT(yesPressed()));
00509        connect(no, SIGNAL(clicked()), this, SLOT(reject()));
00510        
00511        int ww=this->sizeHint().width();
00512        if(ww>1000)
00513               ww=1000;
00514        if(ww<590)
00515               ww=590;
00516 
00517        int hh=this->sizeHint().height();
00518        if(hh>650)
00519               hh=650;
00520        if(hh<380)
00521               hh=380;
00522        
00523        this->resize(ww, hh);
00524        centerWidgetOnScreen(this);
00525        restoreFETDialogGeometry(this);
00526 }
00527 
00528 SecondMinDaysDialog::~SecondMinDaysDialog()
00529 {
00530        saveFETDialogGeometry(this);
00531 }
00532 
00533 void SecondMinDaysDialog::yesPressed()
00534 {
00535        double wt;
00536        QString tmp=percText->text();
00537        weight_sscanf(tmp, "%lf", &wt);
00538        if(wt<0.0 || wt>100.0){
00539               QMessageBox::warning(this, tr("FET information"),
00540                      tr("Invalid weight (percentage) - must be >=0 and <=100.0"));
00541               return;
00542        }
00543        weight=wt;
00544        accept();
00545 }
00546 
00547 void AddActivityForm::addActivity()
00548 {
00549        double weight;
00550        QString tmp=percentageLineEdit->text();
00551        weight_sscanf(tmp, "%lf", &weight);
00552        if(percentageLineEdit->isEnabled() && (weight<0.0 || weight>100.0)){
00553               QMessageBox::warning(this, tr("FET information"),
00554                      tr("Invalid weight (percentage) for added constraint min days between activities"));
00555               return;
00556        }
00557 
00558        //teachers
00559        QStringList teachers_names;
00560        if(selectedTeachersListWidget->count()<=0){
00561               int t=QMessageBox::question(this, tr("FET question"),
00562                tr("Do you really want to add an activity without teacher(s)?"),
00563                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
00564 
00565               if(t==QMessageBox::No)
00566                      return;
00567        }
00568        else{
00569               for(int i=0; i<selectedTeachersListWidget->count(); i++){
00570                      assert(gt.rules.searchTeacher(selectedTeachersListWidget->item(i)->text())>=0);
00571                      teachers_names.append(selectedTeachersListWidget->item(i)->text());
00572               }
00573        }
00574 
00575        //subject
00576        QString subject_name=subjectsComboBox->currentText();
00577        int subject_index=gt.rules.searchSubject(subject_name);
00578        if(subject_index<0){
00579               QMessageBox::warning(this, tr("FET warning"),
00580                      tr("Invalid subject"));
00581               return;
00582        }
00583 
00584        QStringList activity_tags_names;
00585        for(int i=0; i<selectedActivityTagsListWidget->count(); i++){
00586               assert(gt.rules.searchActivityTag(selectedActivityTagsListWidget->item(i)->text())>=0);
00587               activity_tags_names.append(selectedActivityTagsListWidget->item(i)->text());
00588        }
00589 
00590        //students
00591        QStringList students_names;
00592        if(selectedStudentsListWidget->count()<=0){
00593               int t=QMessageBox::question(this, tr("FET question"),
00594                tr("Do you really want to add an activity without student set(s)?"),
00595                QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
00596 
00597               if(t==QMessageBox::No)
00598                      return;
00599        }
00600        else{
00601               for(int i=0; i<selectedStudentsListWidget->count(); i++){
00602                      assert(gt.rules.searchStudentsSet(selectedStudentsListWidget->item(i)->text())!=NULL);
00603                      students_names.append(selectedStudentsListWidget->item(i)->text());
00604               }
00605        }
00606 
00607        if(splitSpinBox->value()==1){ //indivisible activity
00608               int duration=duration1SpinBox->value();
00609               if(duration<0){
00610                      QMessageBox::warning(this, tr("FET information"),
00611                             tr("Invalid duration"));
00612                      return;
00613               }
00614 
00615               bool active=false;
00616               if(active1CheckBox->isChecked())
00617                      active=true;
00618 
00619               int activityid=0; //We set the id of this newly added activity = (the largest existing id + 1)
00620               for(int i=0; i<gt.rules.activitiesList.size(); i++){
00621                      Activity* act=gt.rules.activitiesList[i];
00622                      if(act->id > activityid)
00623                             activityid = act->id;
00624               }
00625               activityid++;
00626               Activity a(gt.rules, activityid, 0, teachers_names, subject_name, activity_tags_names, students_names,
00627                      duration, duration, /*parity,*/ active, (nStudentsSpinBox->value()==-1), nStudentsSpinBox->value());
00628 
00629               bool already_existing=false;
00630               for(int i=0; i<gt.rules.activitiesList.size(); i++){
00631                      Activity* act=gt.rules.activitiesList[i];
00632                      if((*act)==a)
00633                             already_existing=true;
00634               }
00635 
00636               if(already_existing){
00637                      int t=QMessageBox::question(this, tr("FET question"), 
00638                             //tr("This activity already exists. Insert it again?"),
00639                             tr("A similar activity already exists. Do you want to insert current activity?"),
00640                             tr("Yes"),tr("No"));
00641                      assert(t==0 || t==1 ||t==-1);
00642                      if(t==1) //no pressed
00643                             return;
00644                      if(t==-1) //Esc pressed
00645                             return;
00646               }
00647 
00648               bool tmp=gt.rules.addSimpleActivity(this, activityid, 0, teachers_names, subject_name, activity_tags_names,
00649                      students_names, duration, duration, active,
00650                      (nStudentsSpinBox->value()==-1), nStudentsSpinBox->value());
00651               if(tmp)
00652                      QMessageBox::information(this, tr("FET information"), tr("Activity added"));
00653               else
00654                      QMessageBox::critical(this, tr("FET information"), tr("Activity NOT added - please report error"));
00655        }
00656        else{ //split activity
00657               if(minDayDistanceSpinBox->value()>0 && splitSpinBox->value()>gt.rules.nDaysPerWeek){
00658                      int t=LongTextMessageBox::largeConfirmation(this, tr("FET confirmation"),
00659                       tr("Possible incorrect setting. Are you sure you want to add current activity? See details below:")+"\n\n"+
00660                       tr("You want to add a container activity split into more than the number of days per week and also add a constraint min days between activities."
00661                        " This is a very bad practice from the way the algorithm of generation works (it slows down the generation and makes it harder to find a solution).")+
00662                       "\n\n"+
00663                       tr("The best way to add the activities would be:")+
00664                       "\n\n"+
00665                       tr("1. If you add 'force consecutive if same day', then couple extra activities in pairs to obtain a number of activities equal to the number of days per week"
00666                        ". Example: 7 activities with duration 1 in a 5 days week, then transform into 5 activities with durations: 2,2,1,1,1 and add a single container activity with these 5 components"
00667                        " (possibly raising the weight of added constraint min days between activities up to 100%)")+
00668                        "\n\n"+
00669                       tr("2. If you don't add 'force consecutive if same day', then add a larger activity splitted into a number of"
00670                        " activities equal with the number of days per week and the remaining components into other larger splitted activity."
00671                        " For example, suppose you need to add 7 activities with duration 1 in a 5 days week. Add 2 larger container activities,"
00672                        " first one splitted into 5 activities with duration 1 and second one splitted into 2 activities with duration 1"
00673                        " (possibly raising the weight of added constraints min days between activities for each of the 2 containers up to 100%)")+
00674                       "\n\n"+
00675                       tr("Do you want to add current activities as they are now (not recommended) or cancel and edit them as instructed?")
00676                        ,
00677                       tr("Yes"), tr("No"), QString(), 0, 1);
00678 
00679                      if(t==1)
00680                             return;
00681               }
00682 
00683               int totalduration;
00684               int durations[MAX_SPLIT_OF_AN_ACTIVITY];
00685               bool active[MAX_SPLIT_OF_AN_ACTIVITY];
00686               int nsplit=splitSpinBox->value();
00687 
00688               totalduration=0;
00689               for(int i=0; i<nsplit; i++){
00690                      durations[i]=dur(i)->value();
00691                      active[i]=false;
00692                      if(activ(i)->isChecked())
00693                             active[i]=true;
00694 
00695                      totalduration+=durations[i];
00696               }
00697 
00698               //the group id of this split activity and the id of the first partial activity
00699               //it is the maximum already existing id + 1
00700               int firstactivityid=0;
00701               for(int i=0; i<gt.rules.activitiesList.size(); i++){
00702                      Activity* act=gt.rules.activitiesList[i];
00703                      if(act->id > firstactivityid)
00704                             firstactivityid = act->id;
00705               }
00706               firstactivityid++;
00707 
00708               int minD=minDayDistanceSpinBox->value();
00709               bool tmp=gt.rules.addSplitActivity(this, firstactivityid, firstactivityid,
00710                      teachers_names, subject_name, activity_tags_names, students_names,
00711                      nsplit, totalduration, durations,
00712                      active, minD, weight, forceConsecutiveCheckBox->isChecked(),
00713                      (nStudentsSpinBox->value()==-1), nStudentsSpinBox->value());
00714               if(tmp){
00715                      if(minD>1 && weight<100.0){
00716                             SecondMinDaysDialog second(this, minD, weight);
00717                             setParentAndOtherThings(&second, this);
00718                             int code=second.exec();
00719 
00720                             if(code==QDialog::Accepted){
00721                                    assert(second.weight>=0 && second.weight<=100.0);
00722                                    QList<int> acts;
00723                                    for(int i=0; i<nsplit; i++){
00724                                           acts.append(firstactivityid+i);
00725                                    }
00726                                    TimeConstraint* c=new ConstraintMinDaysBetweenActivities(second.weight, forceConsecutiveCheckBox->isChecked(), nsplit, acts, minD-1);
00727                                    bool tmp=gt.rules.addTimeConstraint(c);
00728                                    assert(tmp);
00729                             }
00730                      }
00731               
00732                      QMessageBox::information(this, tr("FET information"), tr("Split activity added."
00733                       " Please note that FET currently cannot check for duplicates when adding split activities"
00734                       ". It is advisable to check the statistics after adding all the activities"));
00735               }
00736               else
00737                      QMessageBox::critical(this, tr("FET information"), tr("Split activity NOT added - error???"));
00738        }
00739 
00740        PlanningChanged::increasePlanningCommunicationSpinBox();
00741 }
00742 
00743 void AddActivityForm::clearTeachers()
00744 {
00745        selectedTeachersListWidget->clear();
00746 }
00747 
00748 void AddActivityForm::clearStudents()
00749 {
00750        selectedStudentsListWidget->clear();
00751 }
00752 
00753 void AddActivityForm::clearActivityTags()
00754 {
00755        selectedActivityTagsListWidget->clear();
00756 }
00757 
00758 void AddActivityForm::help()
00759 {
00760        QString s;
00761        
00762        s+=tr("Abbreviations in this dialog:");
00763        s+="\n\n";
00764        s+=tr("'Students' (the text near the spin box), means 'Number of students (-1 for automatic)'");
00765        s+="\n";
00766        s+=tr("'Split' means 'Split into ... activities per week'");
00767        s+="\n";
00768        s+=tr("'Min days' means 'The minimum required distance in days between each pair of activities'");
00769        s+="\n";
00770        s+=tr("'Weight %' means 'Percentage of added constraint (min days between activities constraint). Recommended: 95.0%-100.0%'");
00771        s+="\n";
00772        s+=tr("'Consecutive' means 'If activities on same day, force consecutive?'");
00773        s+="\n";
00774        s+=tr("The 'Duration' spin box and the 'Active' check box refer to each component of current activity, you can change "
00775         "them for each component, separately, by selecting the corresponding tab in the tab widget.");
00776        s+="\n\n";
00777        
00778        s+=tr("A first notice: "
00779         "If you use a 5 days week: "
00780         "when adding an activity split into only 2 components "
00781         "per week, the best practice is to add min days between activities to be 2. "
00782         "If you split an activity into 3 components per week - please read FAQ question Q1-5-September-2008");
00783        s+="\n\n";
00784        
00785        s+=tr("You can select a teacher from all the teachers with the mouse or with the keyboard tab/up/down, then "
00786         "double click it to add it to the selected teachers for current activity. "
00787         "You can then choose to remove a teacher from the selected teachers. You can highlight it "
00788         "with the mouse or with the keyboard, then double click it to remove this teacher from the selected teachers.");
00789         
00790        s+="\n\n";
00791        
00792        s+=tr("The same procedure (double click) applies to students sets and activity tags.");
00793        
00794        s+="\n\n";
00795        
00796        s+=tr("You can check/uncheck show years, show groups or show subgroups.");
00797        s+="\n\n";
00798        
00799         s+=tr("If you split a larger activity into more activities per week, you have a multitude of choices:\n"
00800         "You can choose the minimum distance in days between each pair of activities."
00801         " Please note that a minimum distance of 1 means that the activities must not be in the same day, "
00802         "a minimum distance of 2 means that the activities must be separated by one day (distance from Monday"
00803         " to Wednesday for instance is 2 days), etc.");
00804 
00805        s+="\n\n";
00806         
00807         s+=tr("If you have for instance an activity with 2 lessons per week and you want to spread them to at "
00808         "least 2 days distance, you can add a constraint min days with min days = 2 and weight 95% "
00809         "(or higher). If you want also to ensure that activities will "
00810         "be separated by at least one day, you can use this feature: "
00811         "add a constraint min days with minimum days 2 and weight 95% or lower, and after that you'll get "
00812         "the possibility to add another constraint with min 1 days and weight 95% or higher. "
00813         "It works if you first select in the dialog the min days >= 2 and click Add activities. Or you can add manually the constraints "
00814         "(difficult this way). "
00815         "Important: it is best practice to consider both constraints to have 95% weight. The combination assures that "
00816         "the resultant is 99.75% weight");
00817 
00818        s+="\n\n";
00819         
00820        s+=tr("Please note that the min days distance is a time constraint and you can only see/modify it in the "
00821         "time constraints dialogs, not in the modify activity dialog. Additionally, you can see the constraints "
00822         "for each activity in the details text box of each activity");
00823 
00824        s+="\n\n";
00825         
00826         s+=tr("If you choose a value greater or equal with 1 for min days, a time constraint min days between activities will be added automatically "
00827         "(you can see this constraint in the time constraints list or you can see this constraint in the "
00828         "detailed description of the activity). You can select a weight percentage for this constraint. "
00829         "If you select 100%, the constraint must be respected all the time. If you select 95%, there is a small chance "
00830         "that the timetable will not respect this constraint. Recommended values are 95.0%-100.0% (maybe you could try "
00831         "with 95%, then 99.75%, or even 100.0%, but the generation time might be larger). Generally, 99.75% might be a good value. "
00832         "Note: if you put a value less than 100% and the constraint is too tough, FET is able to find that this constraint "
00833         "is impossible and will break it. 99.75% might be better than 95% but possibly slower. The percentage is subjective "
00834         "(if you put 95% you may get 6 soft conflicts and if you put 99.75% you may get 3 soft conflicts). "
00835         "Starting with FET-5.3.6, it is possible to change this value for all constraints in one click, in constraint min days"
00836         " between activities dialog.");
00837 
00838        s+="\n\n";
00839 
00840        s+=tr("There is another option, if the activities are in the same day, force consecutive activities. You can select "
00841         "this option for instance if you have 5 lessons of math in 5 days, and there is no timetable which respects "
00842         "fully the days separation. Then, you can set the weight percent of the min days constraint to 95% and "
00843         "add consecutive if same day. You will have as results say 3 lessons with duration 1 and a 2 hours lesson in another day. "
00844         "Please be careful: if the activities are on the same day, even if the constraint has 0% weight, then the activities are forced to be "
00845         "consecutive.");
00846 
00847        s+="\n\n";
00848 
00849        s+=tr("Current algorithm cannot schedule 3 activities in the same day if consecutive is checked, so "
00850         "you will get no solution in such extreme cases (for instance, if you have 3 lessons and a teacher which works only 1 day per week, "
00851         "and select 'force consecutive if same day', you will get an imposssible timetable. But these are extremely unlikely cases).");
00852 
00853        s+="\n\n";
00854        
00855        s+=tr("Note: You cannot add 'consecutive if same day' with min days=0. If you want this, you have to add "
00856         "min days at least 1 (and any weight percentage).");
00857 
00858        s+="\n\n";
00859        
00860        s+=tr("Starting with version 5.0.0, it is possible to add activities with no students or no teachers");
00861 
00862        s+="\n\n";
00863        
00864        s+=tr("If you select a number of min days above 1, you will get the possibility "
00865         "to add a second constraint min days between activities, with min days 1 and a percentage of your choice. Just click "
00866         "Add activities");
00867        
00868        //show the message in a dialog
00869        QDialog dialog(this);
00870        
00871        dialog.setWindowTitle(tr("FET - help on adding activity(ies)"));
00872 
00873        QVBoxLayout* vl=new QVBoxLayout(&dialog);
00874        QPlainTextEdit* te=new QPlainTextEdit();
00875        te->setPlainText(s);
00876        te->setReadOnly(true);
00877        QPushButton* pb=new QPushButton(tr("OK"));
00878 
00879        QHBoxLayout* hl=new QHBoxLayout(0);
00880        hl->addStretch(1);
00881        hl->addWidget(pb);
00882 
00883        vl->addWidget(te);
00884        vl->addLayout(hl);
00885        connect(pb, SIGNAL(clicked()), &dialog, SLOT(close()));
00886 
00887        dialog.resize(700,500);
00888        centerWidgetOnScreen(&dialog);
00889 
00890        setParentAndOtherThings(&dialog, this);
00891        dialog.exec();
00892 }
00893 
00894 void AddActivityForm::minDaysChanged()
00895 {
00896        percentageTextLabel->setEnabled(splitSpinBox->value()>=2 && minDayDistanceSpinBox->value()>0);
00897        percentageLineEdit->setEnabled(splitSpinBox->value()>=2 && minDayDistanceSpinBox->value()>0);
00898        forceConsecutiveCheckBox->setEnabled(splitSpinBox->value()>=2 && minDayDistanceSpinBox->value()>0);
00899 }