Back to index

fet  5.18.0
spreadmindaysconstraintsfivedaysform.cpp
Go to the documentation of this file.
00001 //
00002 //
00003 // Description: This file is part of FET
00004 //
00005 //
00006 // Author: Lalescu Liviu <Please see http://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)>
00007 // Copyright (C) 2003 Liviu Lalescu <http://lalescu.ro/liviu/>
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 <QHash>
00019 #include <QList>
00020 
00021 #include <QMessageBox>
00022 
00023 #include <QPushButton>
00024 #include <QCheckBox>
00025 #include <QPlainTextEdit>
00026 #include <QLineEdit>
00027 #include <QHBoxLayout>
00028 #include <QVBoxLayout>
00029 
00030 #include "matrix.h"
00031 
00032 #include "spreadmindaysconstraintsfivedaysform.h"
00033 
00034 #include "longtextmessagebox.h"
00035 
00036 #include "timetable.h"
00037 
00038 extern Timetable gt;
00039 
00040 SpreadMinDaysConstraintsFiveDaysForm::SpreadMinDaysConstraintsFiveDaysForm(QWidget* parent): QDialog(parent)
00041 {
00042        setupUi(this);
00043 
00044        centerWidgetOnScreen(this);
00045        restoreFETDialogGeometry(this);
00046        
00047        connect(buttonBox, SIGNAL(accepted()), this, SLOT(wasAccepted()));
00048        connect(buttonBox, SIGNAL(rejected()), this, SLOT(wasCanceled()));
00049        connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(help()));
00050        
00051        spread2CheckBox->setChecked(false);
00052        spread3CheckBox->setChecked(false);
00053 }
00054 
00055 SpreadMinDaysConstraintsFiveDaysForm::~SpreadMinDaysConstraintsFiveDaysForm()
00056 {
00057        saveFETDialogGeometry(this);
00058 
00059 }
00060 
00061 void SpreadMinDaysConstraintsFiveDaysForm::wasAccepted()
00062 {
00063        double weight4;
00064        QString tmp=weight4LineEdit->text();
00065        weight_sscanf(tmp, "%lf", &weight4);
00066        if(weight4<0.0 || weight4>100.0){
00067               QMessageBox::warning(this, tr("FET information"),
00068                tr("Invalid weight (percentage) for all split activities - must be real number >=0.0 and <=100.0"));
00069               return;
00070        }
00071 
00072        double weight2;
00073        tmp=weight2LineEdit->text();
00074        weight_sscanf(tmp, "%lf", &weight2);
00075        if(spread2CheckBox->isChecked() && (weight2<0.0 || weight2>100.0)){
00076               QMessageBox::warning(this, tr("FET information"),
00077                tr("Invalid weight (percentage) for activities split into 2 components - must be real number >=0.0 and <=100.0"));
00078               return;
00079        }
00080 
00081        double weight3;
00082        tmp=weight3LineEdit->text();
00083        weight_sscanf(tmp, "%lf", &weight3);
00084        if(spread3CheckBox->isChecked() && (weight3<0.0 || weight3>100.0)){
00085               QMessageBox::warning(this, tr("FET information"),
00086                tr("Invalid weight (percentage) for activities split into 3 components - must be real number >=0.0 and <=100.0"));
00087               return;
00088        }
00089 
00090 
00091        bool spread2=spread2CheckBox->isChecked();
00092        bool spread3=spread3CheckBox->isChecked();
00093        bool spread4OrMore=spread4OrMoreCheckBox->isChecked();
00094        
00095        if(!spread4OrMore){
00096               QMessageBox::critical(this, tr("FET bug"), tr("You found a probable bug in FET - min 1 day should be selected automatically for "
00097                "all split activities. Please report error. FET will now abort current operation"));
00098               return;
00099        }
00100        assert(spread4OrMore);
00101        
00102        QHash<int, int> activitiesRepresentantIds; //first integer is the id, second is the index in the lists
00103 
00104        //QList<int> activitiesForRepresentant[MAX_ACTIVITIES];
00105        Matrix1D<QList<int> > activitiesForRepresentant;
00106        activitiesForRepresentant.resize(gt.rules.activitiesList.count());
00107        
00108        int nActs=0;
00109        
00110        foreach(Activity* act, gt.rules.activitiesList){
00111               if(act->activityGroupId==0){
00112                      assert(!activitiesRepresentantIds.contains(act->id));
00113                      activitiesRepresentantIds.insert(act->id, nActs);
00114                      activitiesForRepresentant[nActs].clear();
00115                      activitiesForRepresentant[nActs].append(act->id);
00116                      
00117                      nActs++;
00118               }
00119               else{
00120                      if(activitiesRepresentantIds.contains(act->activityGroupId)){
00121                             int k=activitiesRepresentantIds.value(act->activityGroupId);
00122                             assert(!activitiesForRepresentant[k].contains(act->id));
00123                             activitiesForRepresentant[k].append(act->id);
00124                      }
00125                      else{
00126                             activitiesRepresentantIds.insert(act->activityGroupId, nActs);
00127                             activitiesForRepresentant[nActs].clear();
00128                             activitiesForRepresentant[nActs].append(act->id);
00129                             
00130                             nActs++;
00131                      }
00132               }
00133        }
00134        
00135        QHash<int, int> activityGroupIdHash;
00136        
00137        foreach(Activity* act, gt.rules.activitiesList)
00138               activityGroupIdHash.insert(act->id, act->activityGroupId);
00139        
00140        for(int i=0; i<nActs; i++){
00141               qSort(activitiesForRepresentant[i]);
00142               int fid=activitiesForRepresentant[i].at(0);
00143               assert(activityGroupIdHash.contains(fid));
00144               int gid=activityGroupIdHash.value(fid);
00145               if(gid>0){
00146                      assert(activitiesRepresentantIds.contains(gid));
00147                      assert(activitiesRepresentantIds.value(gid)==i);
00148               }
00149               else
00150                      assert(activitiesForRepresentant[i].count()==1);
00151        }
00152        
00153        QList<ConstraintMinDaysBetweenActivities*> constraintsToBeRemoved;
00154        
00155        foreach(TimeConstraint* tc, gt.rules.timeConstraintsList){
00156               if(tc->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
00157                      ConstraintMinDaysBetweenActivities* mdc=(ConstraintMinDaysBetweenActivities*) tc;
00158                      
00159                      //find representant
00160                      int reprIndex=-1;
00161                      
00162                      bool toBeRemoved=true;
00163                      
00164                      for(int i=0; i<mdc->n_activities; i++){
00165                             if(!activityGroupIdHash.contains(mdc->activitiesId[i])){
00166                                    QMessageBox::critical(this, tr("FET bug"), tr("You found a probable bug in FET - constraint %1\ncontains invalid activity id %2\n"
00167                                     "\nPlease report error. FET will now abort current operation").arg(mdc->getDetailedDescription(gt.rules)).arg(mdc->activitiesId[i]));
00168                                    return;
00169                             }
00170                             assert(activityGroupIdHash.contains(mdc->activitiesId[i]));
00171                             if(reprIndex==-1)
00172                                    reprIndex=activityGroupIdHash.value(mdc->activitiesId[i]);
00173                             else if(reprIndex!=activityGroupIdHash.value(mdc->activitiesId[i])){
00174                                    toBeRemoved=false;
00175                                    break;
00176                             }
00177                      }
00178                      
00179                      if(reprIndex==0)
00180                             toBeRemoved=false;
00181                      
00182                      if(toBeRemoved)
00183                             constraintsToBeRemoved.append(mdc);
00184               }
00185        }
00186        
00187        bool consecutiveIfSameDay=consecutiveIfSameDayCheckBox->isChecked();
00188        
00189        QList<ConstraintMinDaysBetweenActivities*> addedConstraints;
00190        
00191        for(int i=0; i<nActs; i++){
00192               ConstraintMinDaysBetweenActivities* c1;
00193               ConstraintMinDaysBetweenActivities* c2;
00194               ConstraintMinDaysBetweenActivities* c3;
00195               c1=NULL;
00196               c2=NULL;
00197               c3=NULL;
00198               
00199               QList<int> cl=activitiesForRepresentant[i];
00200               assert(cl.count()>=1);
00201               
00202               if(cl.count()>=2){
00203                      assert(spread4OrMore);
00204 
00205                      int n_acts;
00206                      QList<int> acts;
00207                      //int acts[MAX_CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES];
00208                      
00209                      n_acts=cl.count();
00210                      acts.clear();
00211                      for(int k=0; k<cl.count(); k++){
00212                             //acts[k]=cl.at(k);
00213                             acts.append(cl.at(k));
00214                      }
00215                      c1=new ConstraintMinDaysBetweenActivities(weight4, consecutiveIfSameDay, n_acts, acts, 1);
00216               }
00217               if(cl.count()==3 && spread3){
00218                      int aloneComponent=-1, notAloneComp1=-1, notAloneComp2=-1;
00219                      if(type123RadioButton->isChecked()){
00220                             aloneComponent=1;
00221                             notAloneComp1=2;
00222                             notAloneComp2=3;
00223                      }
00224                      else if(type213RadioButton->isChecked()){
00225                             aloneComponent=2;
00226                             notAloneComp1=1;
00227                             notAloneComp2=3;
00228                      }
00229                      else if(type312RadioButton->isChecked()){
00230                             aloneComponent=3;
00231                             notAloneComp1=1;
00232                             notAloneComp2=2;
00233                      }
00234                      else{
00235                             QMessageBox::information(this, tr("FET information"), tr("Please select the isolated component"));
00236                             return;
00237                      }
00238                             
00239                      aloneComponent--;
00240                      notAloneComp1--;
00241                      notAloneComp2--;
00242               
00243                      int n_acts;
00244                      //int acts[10];
00245                      QList<int> acts;
00246                      
00247                      n_acts=2;                   
00248                      acts.clear();
00249                      //acts[0]=cl.at(aloneComponent);
00250                      acts.append(cl.at(aloneComponent));
00251                      //acts[1]=cl.at(notAloneComp1);
00252                      acts.append(cl.at(notAloneComp1));
00253                             
00254                      c2=new ConstraintMinDaysBetweenActivities(weight3, consecutiveIfSameDay, n_acts, acts, 2);
00255 
00257 
00258                      n_acts=2;                   
00259                      acts.clear();
00260                      //acts[0]=cl.at(aloneComponent);
00261                      acts.append(cl.at(aloneComponent));
00262                      //acts[1]=cl.at(notAloneComp2);
00263                      acts.append(cl.at(notAloneComp2));
00264                             
00265                      c3=new ConstraintMinDaysBetweenActivities(weight3, consecutiveIfSameDay, n_acts, acts, 2);
00266               }
00267               if(cl.count()==2 && spread2){
00268                      int n_acts;
00269                      
00270                      QList<int> acts;
00271                      //int acts[10];
00272                      
00273                      n_acts=2;
00274                      acts.clear();
00275                      //acts[0]=cl.at(0);
00276                      acts.append(cl.at(0));
00277                      //acts[1]=cl.at(1);
00278                      acts.append(cl.at(1));
00279                      
00280                      c2=new ConstraintMinDaysBetweenActivities(weight2, consecutiveIfSameDay, n_acts, acts, 2);
00281               }
00282        
00283               if(c1!=NULL)
00284                      addedConstraints.append(c1);
00285               if(c2!=NULL)
00286                      addedConstraints.append(c2);
00287               if(c3!=NULL)
00288                      addedConstraints.append(c3);
00289        }
00290        
00292        QDialog dialog(this);
00293        dialog.setWindowTitle(tr("Last confirmation needed"));
00294        
00295        QVBoxLayout* top=new QVBoxLayout(&dialog);
00296        QLabel* topLabel=new QLabel();
00297        topLabel->setText(tr("Operations that will be done:"));
00298        top->addWidget(topLabel);
00299        
00300        QPushButton* acceptPB=new QPushButton(tr("Accept"));
00301        QPushButton* cancelPB=new QPushButton(tr("Cancel"));
00302        QHBoxLayout* hl=new QHBoxLayout();
00303        hl->addStretch();
00304        hl->addWidget(acceptPB);
00305        hl->addWidget(cancelPB);
00306        
00307        QObject::connect(acceptPB, SIGNAL(clicked()), &dialog, SLOT(accept()));
00308        QObject::connect(cancelPB, SIGNAL(clicked()), &dialog, SLOT(reject()));
00309        
00310        QPlainTextEdit* removedText=new QPlainTextEdit();
00311        QPlainTextEdit* addedText=new QPlainTextEdit();
00312        
00313        QString s=tr("The following time constraints will be removed:");
00314        s+="\n\n";
00315        foreach(ConstraintMinDaysBetweenActivities* ctr, constraintsToBeRemoved){
00316               s+=ctr->getDetailedDescription(gt.rules);
00317               s+="\n";
00318        }
00319        
00320        removedText->setPlainText(s);
00321        removedText->setReadOnly(true);
00322        
00323        s=tr("The following time constraints will be added:");
00324        s+="\n\n";
00325        foreach(ConstraintMinDaysBetweenActivities* ctr, addedConstraints){
00326               s+=ctr->getDetailedDescription(gt.rules);
00327               s+="\n";
00328        }
00329        
00330        addedText->setPlainText(s);
00331        addedText->setReadOnly(true);
00332        
00333        top->addWidget(removedText);
00334        top->addWidget(addedText);
00335        
00336        top->addLayout(hl);
00337        
00338        //dialog.addLayout(top);
00339        
00340        const QString settingsName=QString("SpreadMinDaysBetweenActivitiesConstraintsLastConfirmationForm");
00341 
00342        dialog.resize(600, 500);
00343        centerWidgetOnScreen(&dialog);
00344        restoreFETDialogGeometry(&dialog, settingsName);
00345        
00346        acceptPB->setFocus();
00347        acceptPB->setDefault(true);
00348        
00349        setParentAndOtherThings(&dialog, this);
00350        int res=dialog.exec();
00351        saveFETDialogGeometry(&dialog, settingsName);
00352        
00353        if(res==QDialog::Rejected){
00354               constraintsToBeRemoved.clear();
00355 
00356               foreach(ConstraintMinDaysBetweenActivities* ctr, addedConstraints){
00357                      delete ctr;
00358               }
00359               addedConstraints.clear();
00360               
00361               return;
00362        }
00363 
00364        assert(res==QDialog::Accepted);
00365        
00366        foreach(ConstraintMinDaysBetweenActivities* mdc, constraintsToBeRemoved){
00367               int t=gt.rules.timeConstraintsList.removeAll(mdc);
00368               assert(t==1);
00369        }
00370        gt.rules.internalStructureComputed=false;
00371        setRulesModifiedAndOtherThings(&gt.rules);
00372        
00373        foreach(ConstraintMinDaysBetweenActivities* mdc, constraintsToBeRemoved)
00374               delete mdc;
00375               
00376        constraintsToBeRemoved.clear();
00377               
00378        foreach(ConstraintMinDaysBetweenActivities* tc, addedConstraints){
00379               bool t=gt.rules.addTimeConstraint(tc);
00380               if(!t){
00381                      QMessageBox::critical(this, tr("FET bug"), tr("You found a probable bug in FET - trying to add constraint %1, "
00382                       "but it is already existing. Please report error. FET will now continue operation").arg(tc->getDetailedDescription(gt.rules)));
00383               }
00384        }
00385               
00386        addedConstraints.clear();
00387        
00388        QString s2=tr("Spreading of activities operation completed successfully");
00389        s2+="\n\n";
00390        s2+=tr("NOTE: If you are using constraints of type activities same starting time or activities same starting day, it is important"
00391         " (after current operation) to apply the operation of removing redundant constraints.")
00392         +" "+tr("Read Help/Important tips - tip 2) for details.");
00393        QMessageBox::information(this, tr("FET information"), s2);
00394        
00395        this->accept();
00396 }
00397 
00398 void SpreadMinDaysConstraintsFiveDaysForm::wasCanceled()
00399 {
00400        this->reject();
00401 }
00402 
00403 void SpreadMinDaysConstraintsFiveDaysForm::help()
00404 {
00405        QString s;
00406        
00407        s+=tr("Help on spreading the activities over the week:");
00408        
00409        s+="\n\n";
00410        
00411        s+=tr("How to choose the weights in this dialog:");
00412        
00413        s+="\n\n";
00414 
00415        s+=tr("Weights (percentages) of newly added constraints min days between activities - recommended between 95.0%-100.0% "
00416        "(maybe lower on those split into 3). Make weights 100.0% if the constraints need to be respected all the time."
00417        " It is recommended to enable the check boxes for activities split into 2 or 3 components (not to be in consecutive days), "
00418        "if your data is still possible to solve. You may use a progressive approach. Example of weights: 90.0%, 95.0%, 99.0%, 99.75%, 100.0%.");
00419 
00420        LongTextMessageBox::largeInformation(this, tr("FET help"), s);
00421 }
00422 
00423 void SpreadMinDaysConstraintsFiveDaysForm::on_spread2CheckBox_toggled()
00424 {
00425        weight2LineEdit->setEnabled(spread2CheckBox->isChecked());
00426        weight2Label->setEnabled(spread2CheckBox->isChecked());
00427 }
00428 
00429 void SpreadMinDaysConstraintsFiveDaysForm::on_spread3CheckBox_toggled()
00430 {
00431        weight3LineEdit->setEnabled(spread3CheckBox->isChecked());
00432        weight3Label->setEnabled(spread3CheckBox->isChecked());
00433        aloneGroupBox->setEnabled(spread3CheckBox->isChecked());
00434 }
00435 
00436 void SpreadMinDaysConstraintsFiveDaysForm::on_spread4OrMoreCheckBox_toggled()
00437 {
00438        int k=spread4OrMoreCheckBox->isChecked();
00439        if(!k){
00440               spread4OrMoreCheckBox->setChecked(true);
00441               QMessageBox::information(this, tr("FET information"), tr("This box must remain checked, so that split activities"
00442                " are not in the same day (with the probability you write below)"));
00443        }
00444 }