evorobotviewer.cpp
1 /********************************************************************************
2  * FARSA Experiments Library *
3  * Copyright (C) 2007-2012 *
4  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
5  * Onofrio Gigliotta <onofrio.gigliotta@istc.cnr.it> *
6  * Gianluca Massera <emmegian@yahoo.it> *
7  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the Free Software *
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
22  ********************************************************************************/
23 
24 #include "evorobotviewer.h"
25 #include "renderworldwrapperwidget.h"
26 #include "abstracttest.h"
27 #include "tests.h"
28 #include "total99resources.h"
29 #include <QGridLayout>
30 #include <QPushButton>
31 #include <QCheckBox>
32 #include <QFileDialog>
33 #include <QVBoxLayout>
34 #include <QDir>
35 #include <QFileInfo>
36 #include <QFile>
37 #include <QEvent>
38 #include <QCoreApplication>
39 #include <QTimer>
40 #include <QSlider>
41 #include <cmath>
42 
43 using namespace qglviewer;
44 
45 // All the suff below is to avoid warnings on Windows about the use of unsafe
46 // functions. This should be only a temporary workaround, the solution is stop
47 // using C string and file functions...
48 #if defined(_MSC_VER)
49  #pragma warning(push)
50  #pragma warning(disable:4996)
51 #endif
52 
53 namespace farsa {
54 
55 EvoRobotViewer::EvoRobotViewer( EvoRobotComponent* component )
56  : QObject()
59  , evorobot(component)
60  , ga(evorobot->getGA())
61  , statViewer(NULL)
62  , ftv(NULL)
63  , renderworldwrapper(NULL)
64  , infoEvoga(NULL)
65  , simulationThrottle(NULL)
66  , simulationSpeed(NULL)
67  , timer(NULL)
68 {
70 
71  // Declaring which resources we will need to use
72  usableResources(QStringList() << "world" << "experiment");
73 
74  timer = new QTimer(this);
75  timer->setInterval( 40 );
76  timer->setSingleShot( false );
77  timer->start();
78 
79  // !! DO NOT CONNECT TO THE advanced SIGNAL to update the renderworld becuase that signals may be
80  // emitted so fast that the GUI will freeze !!
81  //connect( world, SIGNAL(advanced()), this, SLOT(onWorldAdvance()), Qt::QueuedConnection );
82  connect( timer, SIGNAL(timeout()), this, SLOT(onWorldAdvance()) );
83 
84  // Global connections
85  ResourcesLocker locker(this);
86  connect( evorobot, SIGNAL(actionFinished()), this, SLOT(onActionFinished()) );
87 }
88 
90 {
91  // Nothing to do
92  // --- All objects are destroyed in others parts because none of them are owend by this object
93 }
94 
95 void EvoRobotViewer::fillActionsMenu( QMenu* actionsMenu ) {
96  actionsMenu->addAction( "Evolve", evorobot, SLOT(evolve()) );
97  actionsMenu->addAction( "Stop", evorobot, SLOT(stop()) );
98 }
99 
100 QList<ParameterSettableUIViewer> EvoRobotViewer::getViewers( QWidget* parent, Qt::WindowFlags flags ) {
101  QList<ParameterSettableUIViewer> viewsList;
102  viewsList.append( evogaControls( parent, flags ) );
103 // viewsList.append( icubview( parent, flags ) );
104  viewsList.append( fitview( parent, flags ) );
105  viewsList.append( statview( parent, flags ) );
106  viewsList.append( renderWorld( parent, flags ) );
107  //--- check if there are some special view for the testing actions
108  QStringList testsList = AvailableTestList::getList();
109  for (int i = 0; i < testsList.size(); i++) {
110  TestIndividual* testIndividual = dynamic_cast<TestIndividual*>(AvailableTestList::getTest(testsList[i]));
111  if ( testIndividual ) {
112  viewsList.append( testIndividualUI( testIndividual, parent, flags ) );
113  }
114  }
115  return viewsList;
116 }
117 
118 void EvoRobotViewer::addAdditionalMenus( QMenuBar* menuBar ) {
119  QMenu* testMenu = menuBar->addMenu( "Tests" );
120  QStringList testsList = AvailableTestList::getList();
121  for (int i = 0; i < testsList.size(); i++) {
122  AbstractTest* test = AvailableTestList::getTest(testsList[i]);
123  QAction* action = testMenu->addAction( test->menuText(), evorobot, SLOT(runTestFromQAction()) );
124  action->setData( QVariant(testsList[i]) );
125  action->setToolTip( test->tooltip() );
126  action->setIcon( QIcon( test->iconFilename() ) );
127  }
128 }
129 
130 ParameterSettableUIViewer EvoRobotViewer::renderWorld( QWidget* parent, Qt::WindowFlags flags )
131 {
132  // Creating the wrapper class for RenderWorld and sharing resources
133  renderworldwrapper = new RenderWorldWrapperWidget(parent, flags);
134  renderworldwrapper->shareResourcesWith(this);
135 
136  return ParameterSettableUIViewer(renderworldwrapper, "RenderWorld");
137 }
138 
139 ParameterSettableUIViewer EvoRobotViewer::evogaControls( QWidget* parent, Qt::WindowFlags flags ) {
140  QWidget* widget = new QWidget( parent, flags );
141  QGridLayout* lay = new QGridLayout( widget );
142  //lay->setContentsMargins(0,0,0,0);
143 
144  // --- visualizzaione del trial corrente, e step corrente
145  infoEvoga = new QLabel( "Information", widget );
146  infoEvoga->setStyleSheet( "QLabel { font: bold normal large \"Courier\" }" );
147  lay->addWidget( infoEvoga, 0, 0, 1, 2 );
148 
149  QPushButton* bt = new QPushButton( "Do Step", widget );
150  bt->setAutoRepeat(true);
151  bt->setEnabled( false );
152  connect( bt, SIGNAL(clicked(bool)), ga, SLOT(doNextStep()) );
153 
154  QCheckBox* cb = new QCheckBox( "Step by Step Mode", widget );
155  connect( cb, SIGNAL(clicked(bool)), ga, SLOT(enableStepByStep(bool)) );
156  connect( cb, SIGNAL(clicked(bool)), bt, SLOT(setEnabled(bool)) );
157 
158  lay->addWidget( cb, 1, 0 );
159  lay->addWidget( bt, 1, 1 );
160 
161  bt = new QPushButton( "Next Trial", widget );
162  connect( bt, SIGNAL(clicked()), this, SLOT(evogaNextTrial()) );
163  lay->addWidget( bt, 2, 0, 1, 2 );
164 
165  //----- Skip Trial... Go to Trial number N
166 
167  // slider to setup the delay for slowing down the simulation
168  QLabel* lb = new QLabel( "Simulation Throttle - speed regulator", widget );
169  lay->addWidget( lb, 3, 0, 1, 2 );
170  simulationThrottle = new QSlider( widget );
171  simulationThrottle->setMinimum( 0 );
172  simulationThrottle->setMaximum( 100 );
173  simulationThrottle->setMinimumHeight( 200 );
174  simulationThrottle->setOrientation( Qt::Vertical );
175  int currDelay = ga->getEvoRobotExperiment()->getStepDelay();
176  simulationThrottle->setValue( floor(13.0*std::log((float)currDelay)) );
177  connect( simulationThrottle, SIGNAL(valueChanged(int)), this, SLOT(onSimulationThrottleChanges(int)) );
178  lay->addWidget( simulationThrottle, 4, 0, 3, 1 );
179  lb = new QLabel( "slow", widget );
180  lay->addWidget( lb, 4, 1 );
181 
182  QString str = "Running as fast as possible";
183  if ( currDelay > 0 ) {
184  QString extra;
185  if ( fabs( currDelay/1000.0 - ga->getEvoRobotExperiment()->getWorldTimeStep() ) < 0.01 ) {
186  extra = "Running approximately at real time";
187  }
188  str = QString("Speed: %1 frames/second [%2 ms]\n%3")
189  .arg(1000.0/currDelay)
190  .arg(currDelay)
191  .arg(extra);
192  }
193  simulationSpeed = new QLabel( str, widget );
194  lay->addWidget( simulationSpeed, 5, 1 );
195  lb = new QLabel( "fast", widget );
196  lay->addWidget( lb, 6, 1 );
197 
198  return ParameterSettableUIViewer( widget, "Evoga Controls" );
199 }
200 
201 void EvoRobotViewer::evogaNextTrial() {
203 }
204 
205 void EvoRobotViewer::onSimulationThrottleChanges( int newvalue ) {
206  // mapping with an exponential in order to get more sensitivity for small values
207  int delay = ceil(std::exp( newvalue/13.0 )-1.0);
208  ga->getEvoRobotExperiment()->setStepDelay( delay );
209  if ( delay > 0 ) {
210  QString extra;
211  if ( fabs( delay/1000.0 - ga->getEvoRobotExperiment()->getWorldTimeStep() ) < 0.01 ) {
212  extra = "Running approximately at real time";
213  }
214  simulationSpeed->setText( QString("Speed: %1 frames/second [%2 ms]\n%3")
215  .arg(1000.0/delay)
216  .arg(delay)
217  .arg(extra) );
218  } else {
219  simulationSpeed->setText( "Running as fast as possible" );
220  }
221 }
222 
223 ParameterSettableUIViewer EvoRobotViewer::fitview( QWidget* parent, Qt::WindowFlags flags )
224 {
225  // Here we also create the fitness viewer
226  ftv = new FitViewer(3,4000,parent,flags);
227  ftv->setChunkProperties(0, "MaxFit", Qt::red, true);
228  ftv->setChunkProperties(1, "AverageFit", Qt::green, true);
229  ftv->setChunkProperties(2, "MinFit", Qt::blue, true);
230  ftv->setLabels(QString("EvoICub Fitness Monitor"), QString("Generations"), QString("Fitness"));
231  ftv->setGeometry(50, 50, 500, 500);
232  ftv->setWindowTitle( "Fitness Curves" );
233  connect( ga, SIGNAL(startingReplication(int)),
234  this, SLOT(onEvogaStartingReplication(int)), Qt::QueuedConnection );
235  connect( ga, SIGNAL(recoveredInterruptedEvolution(QString)),
236  this, SLOT(onEvogaRecoveredInterruptedEvolution(QString)), Qt::QueuedConnection );
237  connect( ga, SIGNAL(endGeneration(int,double,double,double)),
238  this, SLOT(onEvogaEndGeneration(int,double,double,double)), Qt::QueuedConnection );
239  return ParameterSettableUIViewer( ftv, "Fitness monitor" );
240 }
241 
242 // ParameterSettableUIViewer EvoRobotViewer::icubview( QWidget* parent, Qt::WindowFlags flags )
243 // {
244 // m_icubview = new VisionMapSensorGui(parent,flags);
245 // m_icubview->setWindowTitle( "iCub Camera" );
246 // m_icubview->resize( 200, 200 );
247 // m_icubview->hide();
248 // return ParameterSettableUIViewer( m_icubview, "iCub camera" );
249 // }
250 
251 ParameterSettableUIViewer EvoRobotViewer::statview( QWidget* parent, Qt::WindowFlags flags )
252 {
253  statViewer = new QWidget( parent, flags );
254  statViewer->setWindowTitle( "Statistics Viewer" );
255  QGridLayout* lay = new QGridLayout( statViewer );
256  QPushButton* but = new QPushButton( "Load a Stat File", statViewer );
257  connect( but, SIGNAL(clicked()), this, SLOT(loadStat()) );
258  lay->addWidget( but, 0, 0 );
259  but = new QPushButton( "Load All Stat", statViewer );
260  connect( but, SIGNAL(clicked()), this, SLOT(loadAllStat()) );
261  lay->addWidget( but, 0, 1 );
262  return ParameterSettableUIViewer( statViewer, "Statistic Viewer" );
263 }
264 
265 void EvoRobotViewer::loadStat() {
266  QString filename = QFileDialog::getOpenFileName(statViewer, tr("Open Stat File"), ".", tr("Files with statistics (*.fit *.ini)"));
267  if (filename.isEmpty()) {
268  return;
269  }
270  FitViewer* fitViewer = statViewer->findChild<FitViewer*>( "statFitViewer" );
271  if ( fitViewer ) {
272  delete fitViewer;
273  }
274  fitViewer = new FitViewer(3, 4000, statViewer);
275  fitViewer->setObjectName( "statFitViewer" );
276  fitViewer->setLabels(QString("Stat monitor. File: ").append(filename), QString("Generation"), QString("Fitnes"));
277  fitViewer->setChunkProperties(0, "MaxFit", Qt::red,true);
278  fitViewer->setChunkProperties(1, "Average", Qt::green,true);
279  fitViewer->setChunkProperties(2, "Minimum", Qt::blue,true);
280  fitViewer->loadRawData(0, filename, 0);
281  fitViewer->loadRawData(1, filename, 1);
282  fitViewer->loadRawData(2, filename, 2);
283  QGridLayout* lay = qobject_cast<QGridLayout*>( statViewer->layout() );
284  lay->addWidget( fitViewer, 1, 0, 1, 2 );
285  lay->setRowStretch( 1, 2 );
286  fitViewer->show();
287 }
288 
289 void EvoRobotViewer::loadAllStat()
290 {
291  FitViewer* fitViewer = statViewer->findChild<FitViewer*>( "statFitViewer" );
292  if ( fitViewer ) {
293  delete fitViewer;
294  }
295 
296  QDir currentDir;
297  QFileInfoList statFiles = currentDir.entryInfoList( QStringList() << "statS*.fit", QDir::Files, QDir::Name );
298 
299  fitViewer = new FitViewer(statFiles.size(), ga->getNumOfGenerations(), statViewer);
300  fitViewer->setObjectName( "statFitViewer" );
301  QString title = QString("Stat monitor");
302  fitViewer->setLabels(title, QString("Generation"), QString("Fitness"));
303 
304  QColor colors[10] = { QColor(Qt::red), QColor(Qt::green), QColor(Qt::blue), QColor(Qt::cyan),
305  QColor(Qt::magenta), QColor(Qt::darkYellow), QColor(Qt::gray), QColor(255, 140, 0, 255),
306  QColor(153, 50, 204, 255), QColor(Qt::black) };
307  for(int i=0; i<statFiles.size(); i++ ) {
308  QFileInfo statFile = statFiles[i];
309  QColor col = colors[i%10];
310  fitViewer->setChunkProperties( i, QString("Seed:").append(statFile.baseName().split("S").last()), col, true );
311  fitViewer->loadRawData( i, statFile.fileName(), 0 );
312  }
313  fitViewer->sortchunks();
314  QGridLayout* lay = qobject_cast<QGridLayout*>( statViewer->layout() );
315  lay->addWidget( fitViewer, 1, 0, 1, 2 );
316  lay->setRowStretch( 1, 2 );
317  fitViewer->show();
318 }
319 
320 ParameterSettableUIViewer EvoRobotViewer::testIndividualUI( TestIndividual* test, QWidget* parent, Qt::WindowFlags flags ) {
321  TestIndividualGUI* testIndUI = new TestIndividualGUI( test, parent, flags );
322  testIndUI->setWindowTitle( "Select the Individual to Test" );
323  return ParameterSettableUIViewer( testIndUI, "Individual to Test", QString(), "From this view you can select an individual to test using the \"TestIndividual\" from the \"Tests\" menu" );
324 }
325 
326 void EvoRobotViewer::onWorldAdvance() {
327  if (renderworldwrapper) {
328  renderworldwrapper->updateRenderWorld();
329  }
330 
331  if (infoEvoga) {
332  ResourcesLocker locker(this);
333 
334  EvoRobotExperiment* exp = getResource<EvoRobotExperiment>("experiment");
335 
336  // visualizza su EvoGa Controls informazioni su step e trial
337  infoEvoga->setText( QString( "Step %1 of %2 --- Trial %3 of %4" )
338  .arg( exp->getCurStep(), 5 ).arg( exp->getNSteps() )
339  .arg( exp->getCurTrial() + 1, 5 ).arg( exp->getNTrials() ) );
340  }
341 
342 // if ( exp->getActivityPhase() == EvoRobotExperiment::INTEST ) {
343 // // if (m_icubview != NULL) {
344 // // m_icubview->setImage( exp->getResource<PhyiCub>( "robot" ) ); // update the iCub camera widget
345 // // }
346 // }
347 }
348 
349 void EvoRobotViewer::onEvogaStartingReplication( int /*replication*/ ) {
350  ftv->reset();
351 }
352 
353 void EvoRobotViewer::onEvogaRecoveredInterruptedEvolution( QString statfile ) {
354  ftv->loadRawData(0,statfile,0);
355  ftv->loadRawData(1,statfile,1);
356  ftv->loadRawData(2,statfile,2);
357 }
358 
359 void EvoRobotViewer::onEvogaEndGeneration( int generation, double fmax, double faverage, double fmin ) {
360  ftv->setChunkValue(0,generation,fmax);
361  ftv->setChunkValue(1,generation,faverage);
362  ftv->setChunkValue(2,generation,fmin);
363  ftv->diplayUntilStep(generation);
364  ftv->update();
365 }
366 
367 void EvoRobotViewer::onActionFinished() {
368  infoEvoga->setText( evorobot->status() );
369 }
370 
371 // #include <QPainter>
372 // #include <QPen>
373 // #include <QBrush>
374 // #include <QTransform>
375 // #include <QVBoxLayout>
376 //
377 // namespace VisionMapSensorGuiInternal {
378 // /**
379 // * \brief An helper class to display an image
380 // *
381 // * This takes a pointer to the image to show and also resizes itself to
382 // * match the image dimension
383 // */
384 // class ImageDisplayer : public QWidget
385 // {
386 // public:
387 // ImageDisplayer(QWidget* parent = NULL) :
388 // QWidget(parent),
389 // m_image(NULL)
390 // {
391 // }
392 //
393 // ~ImageDisplayer()
394 // {
395 // }
396 //
397 // void setImage(QImage* image)
398 // {
399 // // Saving image
400 // m_image = image;
401 //
402 // // Also resetting widget dimensions
403 // setMinimumSize(m_image->width(), m_image->height());
404 // setMaximumSize(m_image->width(), m_image->height());
405 //
406 // // Updating the widget
407 // update();
408 // }
409 //
410 // private:
411 // void paintEvent(QPaintEvent *)
412 // {
413 // if (m_image == NULL) {
414 // return;
415 // }
416 //
417 // QPainter painter(this);
418 //
419 // // Drawing image. Also flipping image (perhaps yarp doesn't consider top left to be 0, 0)
420 // painter.drawImage(0, 0, m_image->mirrored(false, true));
421 // }
422 //
423 // QImage* m_image;
424 // };
425 // }
426 //
427 // VisionMapSensorGui::VisionMapSensorGui(QWidget* parent, Qt::WindowFlags flags) :
428 // QWidget(parent,flags),
429 // m_image(),
430 // m_imageDisplayer(new VisionMapSensorGuiInternal::ImageDisplayer(this))
431 // {
432 // // Creating a layout and adding the image displayer widget and the table with map activations
433 // QVBoxLayout* layout = new QVBoxLayout(this);
434 // layout->addWidget(m_imageDisplayer);
435 //
436 //
437 // }
438 //
439 // VisionMapSensorGui::~VisionMapSensorGui()
440 // {
441 // // Nothing to do here
442 // }
443 //
444 // void VisionMapSensorGui::setImage(PhyiCub *icub, bool useRightCamera)
445 // {
446 //
447 // // Taking the image in yarp format
448 // yarp::sig::ImageOf<yarp::sig::PixelRgb> yarpImage;
449 // // yarp::dev::IFrameGrabberImage* frameGrabber = useRightCamera ? icub->rightEyeFrameGrabber() : icub->leftEyeFrameGrabber();
450 // yarp::dev::IFrameGrabberImage* frameGrabber = NULL; // The line above crashes with multithread
451 // if (frameGrabber == NULL) {
452 // return;
453 // }
454 // // frameGrabber->getImage(yarpImage); // Crashes with multithread
455 //
456 // // Converting to QImage
457 // m_image = QImage(yarpImage.width(), yarpImage.height(), QImage::Format_RGB32);
458 // for (int i = 0; i < yarpImage.width(); i++) {
459 // for (int j = 0; j < yarpImage.height(); j++) {
460 // // Converting pixel and writing it into the QImage
461 // yarp::sig::PixelRgb& yarpPixel = yarpImage.pixel(i, j);
462 // m_image.setPixel(i, j, qRgb(yarpPixel.r, yarpPixel.g, yarpPixel.b));
463 // }
464 // }
465 //
466 //
467 // // Drawing an X at the image center
468 // QPainter painter(&m_image);
469 // const int cX = m_image.width() / 2;
470 // const int cY = m_image.height() / 2;
471 //
472 // // Drawing the X
473 // painter.setPen(QPen(Qt::white, 3));
474 // painter.drawLine(cX - 5, cY - 5, cX + 5, cY + 5);
475 // painter.drawLine(cX + 5, cY - 5, cX - 5, cY + 5);
476 // painter.setPen(QPen(Qt::black, 1));
477 // painter.drawLine(cX - 5, cY - 5, cX + 5, cY + 5);
478 // painter.drawLine(cX + 5, cY - 5, cX - 5, cY + 5);
479 //
480 // // Setting the image for the image displayer
481 // m_imageDisplayer->setImage(&m_image);
482 // m_imageDisplayer->update();
483 // }
484 //
485 // void VisionMapSensorGui::addMark(double x, double y, QColor markCenter, QColor markSurrounding)
486 // {
487 // // Drawing a mark directly on the image
488 // QPainter painter(&m_image);
489 //
490 // // Computing the mark position in image coordinates
491 // const int imageX = int(x * double(m_image.width()));
492 // const int imageY = int(y * double(m_image.height()));
493 //
494 // // Drawing the mark
495 // painter.setPen(QPen(markSurrounding, 5));
496 // painter.drawPoint(imageX, imageY);
497 // painter.setPen(QPen(markCenter, 3));
498 // painter.drawPoint(imageX, imageY);
499 //
500 // // Updating the image displayer widget
501 // m_imageDisplayer->update();
502 // }
503 
504 TestIndividualGUI::TestIndividualGUI(TestIndividual* tb, QWidget *parent, Qt::WindowFlags flags) :
505  QWidget(parent, flags)
506 {
507  test = tb;
508 
509  //set layout
510  QGridLayout* mainLay = new QGridLayout( this );
511 
512  // buttons
513  QPushButton* bt = new QPushButton( "Refresh", this );
514  connect( bt, SIGNAL(clicked()), this, SLOT(populateCombo()) );
515  mainLay->addWidget(bt, 0, 0, 1, 2);
516  //creating comboBox and list
517  combo = new QComboBox( this );
518  list = new QListWidget( this );
519  mainLay->addWidget(new QLabel("Select File to load:"), 1, 0);
520  mainLay->addWidget(combo, 1, 1);
521  mainLay->addWidget(list, 2, 0, 1, 2);
522 
523  //checking available best and gen files
524  populateCombo();
525 
526  // Connecting signals and slots
527  connect(combo, SIGNAL(activated(QString)), this, SLOT(seedWasChosen()));
528  connect(list, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(agentClicked()));
529  connect(list, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(agentClicked()));
530 }
531 
532 void TestIndividualGUI::populateCombo()
533 {
534  combo->clear();
535  list->clear();
536  //ask abstractGA the template name for the files (i.e. "*P*S*G*.gen")
537  QString bestF = test->component()->getGA()->bestsFilename();
538  QString genF = test->component()->getGA()->generationFilename();
539 
540  //search current folder for files
541  QDir* dir = new QDir();
542  QStringList expression = (QStringList() << bestF << genF);
543  fileList = dir->entryList(expression);
544 
545  //insert their name into the combo boxes
546  combo->addItems(fileList);
547 }
548 
549 void TestIndividualGUI::seedWasChosen()
550 {
551  //load the chosen file
552  test->setPopulationToTest( combo->currentText(), false );
553  //refresh individuals list on the GUI
554  list->clear();
555  int loadindi = test->component()->getGA()->numLoadedGenotypes();
556  for(int i=1; i<=loadindi; i++)
557  {
558  list->addItem(QString::number(i));
559  }
560 }
561 
562 void TestIndividualGUI::agentClicked()
563 {
564  //take index of the chosen individual
565  test->setIndividualToTest( list->currentRow() );
566 }
567 
568 } //end namespace farsa
569 
570 // All the suff below is to restore the warning state on Windows
571 #if defined(_MSC_VER)
572  #pragma warning(pop)
573 #endif