baseexperiment.h
1 /********************************************************************************
2  * FARSA *
3  * Copyright (C) 2007-2012 *
4  * Gianluca Massera <emmegian@yahoo.it> *
5  * Stefano Nolfi <stefano.nolfi@istc.cnr.it> *
6  * Tomassino Ferrauto <tomassino.ferrauto@istc.cnr.it> *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
21  ********************************************************************************/
22 
23 #ifndef BASEEXPERIMENT_H
24 #define BASEEXPERIMENT_H
25 
26 #include "experimentsconfig.h"
27 #include "dataexchange.h"
28 #include "component.h"
29 #include "workerthread.h"
30 #include "parametersettable.h"
31 #include "parametersettableui.h"
32 #include "baseexception.h"
33 #include "configurationhelper.h"
34 #include "logger.h"
35 #include <QMutex>
36 #include <QMutexLocker>
37 #include <QWaitCondition>
38 #include <QSignalMapper>
39 #include <QList>
40 #include <QVector>
41 #include <QAction>
42 #include <QMenu>
43 #include <QMenuBar>
44 #include <memory>
45 #include <QtGlobal>
46 
47 namespace farsa {
48 
49 class BaseExperimentGUI;
50 
56 namespace __BaseExperiment_internal {
57  class BaseExperimentUIManager;
58 
63  struct FARSA_EXPERIMENTS_TEMPLATE OperationStatus {
67  enum Status {
72  OperationResumed,
74  OperationStepDelayChanged
76  };
77 
82 
89  unsigned int operationID;
90 
97  unsigned long delay;
98  };
99 
104  struct FARSA_EXPERIMENTS_TEMPLATE OperationControl {
108  enum Action {
110  StartOperationPaused,
117  StepOperation,
119  ResumeOperation,
121  ChangeInterval
123  };
124 
129 
135  unsigned int operationID;
136 
142  unsigned long interval;
143  };
144 }
145 
253 class FARSA_EXPERIMENTS_API BaseExperiment : public Component, public ParameterSettableUI, public ThreadOperation
254 {
255  Q_OBJECT
256 
257 private:
267  class Notifee : public NewDatumNotifiable<__BaseExperiment_internal::OperationControl>
268  {
269  public:
275  Notifee(BaseExperiment& experiment);
276 
280  virtual ~Notifee();
281 
288  virtual void newDatumAvailable(DataDownloader<__BaseExperiment_internal::OperationControl>* downloader);
289 
290  private:
294  BaseExperiment& m_experiment;
295  };
296 
301  friend class Notifee;
302 
303 public:
311  {
312  public:
316  QString getName() const
317  {
318  return name;
319  }
320 
325  bool getUseSeparateThread() const
326  {
327  return useSeparateThread;
328  }
329 
333  bool getSteppable() const
334  {
335  return steppable;
336  }
337 
338  private:
345  virtual ~AbstractOperationWrapper()
346  {
347  }
348 
355  virtual void executeOperation() = 0;
356 
360  QString name;
361 
366  bool useSeparateThread;
367 
371  bool steppable;
372 
377  friend class BaseExperiment;
378 
382  template <class T>
383  friend class std::auto_ptr;
384  };
385 
392  template <class T>
394  {
395  public:
403  OperationWrapper(T* experiment, void (T::*operation)()) :
405  m_experiment(experiment),
406  m_operation(operation)
407  {
408  }
409 
410  private:
414  virtual ~OperationWrapper()
415  {
416  }
417 
421  virtual void executeOperation()
422  {
423  (m_experiment->*m_operation)();
424  }
425 
429  T* const m_experiment;
430 
435  void (T::*m_operation)();
436  };
437 
438 public:
442  BaseExperiment();
443 
451  virtual ~BaseExperiment();
452 
463  virtual void configure(ConfigurationParameters& params, QString prefix);
464 
474  virtual void save(ConfigurationParameters& params, QString prefix);
475 
491  static void describe(QString type);
492 
500  virtual void postConfigureInitialization();
501 
510  virtual ParameterSettableUI* getUIManager();
511 
521  virtual void fillActionsMenu(QMenu* actionsMenu);
522 
535  virtual QList<ParameterSettableUIViewer> getViewers(QWidget* parent, Qt::WindowFlags flags);
536 
542  virtual void addAdditionalMenus(QMenuBar* menuBar);
543 
550  virtual void run();
551 
559  virtual void stop();
560 
567  void pause();
568 
576  void step();
577 
584  void resume();
585 
595  void changeInterval(unsigned long interval);
596 
602  unsigned long currentInterval() const;
603 
609  const QVector<AbstractOperationWrapper*>& getOperations() const;
610 
619  DataUploaderDownloader<__BaseExperiment_internal::OperationStatus, __BaseExperiment_internal::OperationControl>* getUploaderDownloader();
620 
621 public slots:
629  virtual void stopCurrentOperation(bool wait);
630 
636  virtual void stopCurrentOperation();
637 
638 private slots:
646  void exceptionDuringOperation(farsa::BaseException *e);
647 
656  void runOperation(int operationID);
657 
658 protected:
670  QList<QAction*> getActionsForOperations(QObject* actionsParent) const;
671 
696  template <class T>
697  void addOperation(QString name, void (T::*func)(), bool useSeparateThread, bool steppable = false)
698  {
699  std::auto_ptr<AbstractOperationWrapper> newOp(new OperationWrapper<T>(static_cast<T*>(this), func));
700  newOp->name = name;
701  newOp->useSeparateThread = useSeparateThread;
702  newOp->steppable = steppable;
703 
704  m_operationsVector.push_back(newOp.release());
705 
706  // Signalling a new operation has been added
707  uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::NewOperation, m_operationsVector.size() - 1);
708  }
709 
715  bool batchRunning() const;
716 
723  bool stopSimulation();
724 
733  void checkPause();
734 
735 private:
739  void resetStop();
740 
750  void uploadNewOperationStatus(__BaseExperiment_internal::OperationStatus::Status status, unsigned int operationID, unsigned long newDelay = 0);
751 
763  void changeInterval(unsigned long interval, bool sendNotificationToGUI);
764 
768  QVector<AbstractOperationWrapper*> m_operationsVector;
769 
776  std::auto_ptr<QSignalMapper> m_actionSignalsMapper;
777 
781  std::auto_ptr<WorkerThread> const m_workerThread;
782 
789  int m_runningOperationID;
790 
794  bool m_batchRunning;
795 
799  bool m_stop;
800 
805  QMutex m_mutex;
806 
811  QWaitCondition m_waitCondition;
812 
816  bool m_pause;
817 
823  bool m_previousPauseStatus;
824 
828  unsigned long m_delay;
829 
833  Notifee m_notifee;
834 
847 };
848 
849 } // End namespace farsa
850 
859 #define DECLARE_THREAD_OPERATION(classname, op) addOperation(#op, &classname::op, true, false);
860 
869 #define DECLARE_STEPPABLE_THREAD_OPERATION(classname, op) addOperation(#op, &classname::op, true, true);
870 
879 #define DECLARE_IMMEDIATE_OPERATION(classname, op) addOperation(#op, &classname::op, false);
880 
881 #endif