From 78792bed6a0592623bff3ff08c51514c63169f75 Mon Sep 17 00:00:00 2001
From: Michael DM Dryden <mdryden@chem.utoronto.ca>
Date: Tue, 21 Mar 2017 16:40:35 -0400
Subject: [PATCH] Make experiment windows and running modular.

---
 dstat_interface/experiments/cal.py            |   1 +
 dstat_interface/experiments/chronoamp.py      |   2 +
 dstat_interface/experiments/cv.py             |   1 +
 .../experiments/experiment_template.py        |  20 ++-
 dstat_interface/experiments/idle.py           |   2 +
 dstat_interface/experiments/lsv.py            |   1 +
 dstat_interface/experiments/pot.py            |   1 +
 dstat_interface/experiments/swv.py            |   2 +
 .../interface/dstatinterface.glade            |  63 +------
 dstat_interface/interface/exp_int.py          | 124 +++++++++++--
 dstat_interface/interface/exp_window.py       |  73 +++++---
 dstat_interface/main.py                       | 163 ++++--------------
 dstat_interface/params.py                     |   7 +-
 13 files changed, 215 insertions(+), 245 deletions(-)

diff --git a/dstat_interface/experiments/cal.py b/dstat_interface/experiments/cal.py
index f775c29..f57c26f 100755
--- a/dstat_interface/experiments/cal.py
+++ b/dstat_interface/experiments/cal.py
@@ -49,6 +49,7 @@ def measure_offset(time):
     return gain_offset
 
 class CALExp(Experiment):
+    id = 'cal'
     """Offset calibration experiment"""
     def __init__(self, parameters):
         self.parameters = parameters
diff --git a/dstat_interface/experiments/chronoamp.py b/dstat_interface/experiments/chronoamp.py
index 980d03c..a57ae83 100644
--- a/dstat_interface/experiments/chronoamp.py
+++ b/dstat_interface/experiments/chronoamp.py
@@ -16,6 +16,7 @@ class ChronoampBox(PlotBox):
             subplot.plot([],[])
         
 class Chronoamp(Experiment):
+    id = 'cae'
     """Chronoamperometry experiment"""
     def setup(self):
         self.plots.append(ChronoampBox('current_time'))
@@ -63,6 +64,7 @@ class Chronoamp(Experiment):
                 
 class PDExp(Chronoamp):
     """Photodiode/PMT experiment"""
+    id = 'pde'
     def setup(self):
         self.plots.append(ChronoampBox('current_time'))
         
diff --git a/dstat_interface/experiments/cv.py b/dstat_interface/experiments/cv.py
index cd2bc26..fbeda56 100644
--- a/dstat_interface/experiments/cv.py
+++ b/dstat_interface/experiments/cv.py
@@ -4,6 +4,7 @@ import struct
 from experiments.experiment_template import PlotBox, Experiment
 
 class CVExp(Experiment):
+    id = 'cve'
     """Cyclic Voltammetry experiment"""
     def setup(self):
         super(CVExp, self).setup()
diff --git a/dstat_interface/experiments/experiment_template.py b/dstat_interface/experiments/experiment_template.py
index 00f35cc..ee1587e 100755
--- a/dstat_interface/experiments/experiment_template.py
+++ b/dstat_interface/experiments/experiment_template.py
@@ -36,8 +36,6 @@ import matplotlib.pyplot as plt
 
 from matplotlib.backends.backend_gtk3agg \
     import FigureCanvasGTK3Agg as FigureCanvas
-# from matplotlib.backends.backend_gtk3 \
-#     import NavigationToolbar2GTK3 as NavigationToolbar
     
 try:
     import seaborn as sns
@@ -56,9 +54,11 @@ import dstat_comm
 class Experiment(object):
     """Store and acquire a potentiostat experiment. Meant to be subclassed
     to by different experiment types and not used instanced directly. Subclass
-    must instantiate self.plotbox as the PlotBox class to use.
+    must instantiate self.plotbox as the PlotBox class to use and define id as
+    a class attribute.
     """
-
+    id = None
+    
     def __init__(self, parameters):
         """Adds commands for gain and ADC."""
         self.parameters = parameters
@@ -94,8 +94,10 @@ class Experiment(object):
             self.commands[0] += "2"
         else:
             self.commands[0] += "0"
-        self.commands[0] += " {p[adc_rate]} {p[adc_pga]} ".format(p=self.parameters)
-        self.commands[1] += "{p[gain]} {p[short_true]:d} ".format(p=self.parameters)
+        self.commands[0] += " {p[adc_rate]} {p[adc_pga]} ".format(
+            p=self.parameters)
+        self.commands[1] += "{p[gain]} {p[short_true]:d} ".format(
+            p=self.parameters)
         
         self.setup()
               
@@ -329,11 +331,17 @@ class PlotBox(object):
         """Change plot type. Set axis labels and x bounds to those stored
         in the Experiment instance. Stores class instance in Experiment.
         """
+
+        for name, subplot in self.subplots.items():
+            subplot.set_xlabel(Experiment.plot_format[name]['labels'][0])
+            subplot.set_ylabel(Experiment.plot_format[name]['labels'][1])
+            subplot.set_xlim(Experiment.plot_format[name]['xlims'])
         for name, subplot in Experiment.plot_format.items():
             self.subplots[name].set_xlabel(subplot['labels'][0])
             self.subplots[name].set_ylabel(subplot['labels'][1])
             self.subplots[name].set_xlim(subplot['xlims'])
 
+        
         self.figure.canvas.draw()
         
     def redraw(self):
diff --git a/dstat_interface/experiments/idle.py b/dstat_interface/experiments/idle.py
index 662fe68..5bf84bd 100644
--- a/dstat_interface/experiments/idle.py
+++ b/dstat_interface/experiments/idle.py
@@ -5,6 +5,7 @@ from experiments.experiment_template import Experiment
 
 class OCPExp(Experiment):
     """Open circuit potential measumement in statusbar."""
+    id = 'ocp'
     def __init__(self):
         self.databytes = 8
         
@@ -26,6 +27,7 @@ class OCPExp(Experiment):
         
 class PMTIdle(Experiment):
     """Open circuit potential measumement in statusbar."""
+    id = "pmt_idle"
     def __init__(self):
         self.databytes = 8
     
diff --git a/dstat_interface/experiments/lsv.py b/dstat_interface/experiments/lsv.py
index cdf17da..9042a5e 100644
--- a/dstat_interface/experiments/lsv.py
+++ b/dstat_interface/experiments/lsv.py
@@ -5,6 +5,7 @@ from experiments.experiment_template import PlotBox, Experiment
                                      
 class LSVExp(Experiment):
     """Linear Scan Voltammetry experiment"""
+    id = 'lsv'
     def setup(self):
         super(LSVExp, self).setup()
         
diff --git a/dstat_interface/experiments/pot.py b/dstat_interface/experiments/pot.py
index 27e26a7..b4de225 100644
--- a/dstat_interface/experiments/pot.py
+++ b/dstat_interface/experiments/pot.py
@@ -16,6 +16,7 @@ class PotBox(PlotBox):
             subplot.plot([],[])
                                      
 class PotExp(Experiment):
+    id = 'pot'
     """Potentiometry experiment"""
     def setup(self):
         self.plots.append(PotBox(['voltage_time']))
diff --git a/dstat_interface/experiments/swv.py b/dstat_interface/experiments/swv.py
index e8afb66..f4b328f 100644
--- a/dstat_interface/experiments/swv.py
+++ b/dstat_interface/experiments/swv.py
@@ -19,6 +19,7 @@ class SWVBox(PlotBox):
 
 class SWVExp(Experiment):
     """Square Wave Voltammetry experiment"""
+    id = 'swv'
     def setup(self):
         self.plots.append(SWVBox(['swv']))
         
@@ -95,6 +96,7 @@ class SWVExp(Experiment):
 
 class DPVExp(SWVExp):
     """Diffential Pulse Voltammetry experiment."""
+    id = 'dpv'
     def setup(self):
         self.plots.append(SWVBox(['swv']))
         
diff --git a/dstat_interface/interface/dstatinterface.glade b/dstat_interface/interface/dstatinterface.glade
index 33f8acf..345ab09 100644
--- a/dstat_interface/interface/dstatinterface.glade
+++ b/dstat_interface/interface/dstatinterface.glade
@@ -2,63 +2,6 @@
 <!-- Generated with glade 3.20.0 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
-  <object class="GtkListStore" id="ExpComboListStore">
-    <columns>
-      <!-- column-name index -->
-      <column type="guint"/>
-      <!-- column-name id -->
-      <column type="gchararray"/>
-      <!-- column-name name -->
-      <column type="gchararray"/>
-    </columns>
-    <data>
-      <row>
-        <col id="0">0</col>
-        <col id="1" translatable="yes">cae</col>
-        <col id="2" translatable="yes">Chronoamperometry</col>
-      </row>
-      <row>
-        <col id="0">1</col>
-        <col id="1" translatable="yes">lsv</col>
-        <col id="2" translatable="yes">Linear Sweep Voltammetry</col>
-      </row>
-      <row>
-        <col id="0">2</col>
-        <col id="1" translatable="yes">cve</col>
-        <col id="2" translatable="yes">Cyclic Voltammetry</col>
-      </row>
-      <row>
-        <col id="0">3</col>
-        <col id="1" translatable="yes">swv</col>
-        <col id="2" translatable="yes">Square Wave Voltammetry</col>
-      </row>
-      <row>
-        <col id="0">4</col>
-        <col id="1" translatable="yes">dpv</col>
-        <col id="2" translatable="yes">Differential Pulse Voltammetry</col>
-      </row>
-      <row>
-        <col id="0">5</col>
-        <col id="1" translatable="yes">acv</col>
-        <col id="2" translatable="yes">AC Voltammetry</col>
-      </row>
-      <row>
-        <col id="0">6</col>
-        <col id="1" translatable="yes">pde</col>
-        <col id="2" translatable="yes">Photodiode</col>
-      </row>
-      <row>
-        <col id="0">7</col>
-        <col id="1" translatable="yes">pot</col>
-        <col id="2" translatable="yes">Potentiometry</col>
-      </row>
-      <row>
-        <col id="0">8</col>
-        <col id="1" translatable="yes">cal</col>
-        <col id="2" translatable="yes">Offset Calibration</col>
-      </row>
-    </data>
-  </object>
   <object class="GtkAboutDialog" id="aboutdialog1">
     <property name="can_focus">False</property>
     <property name="border_width">5</property>
@@ -999,15 +942,13 @@ Thanks to Christian Fobel for help with Dropbot Plugin</property>
                       </packing>
                     </child>
                     <child>
-                      <object class="GtkComboBox" id="expcombobox">
+                      <object class="GtkComboBoxText" id="expcombobox">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
-                        <property name="model">ExpComboListStore</property>
-                        <signal name="changed" handler="on_expcombobox_changed" swapped="no"/>
                       </object>
                       <packing>
                         <property name="expand">False</property>
-                        <property name="fill">False</property>
+                        <property name="fill">True</property>
                         <property name="position">2</property>
                       </packing>
                     </child>
diff --git a/dstat_interface/interface/exp_int.py b/dstat_interface/interface/exp_int.py
index c56dc91..37e8ca9 100755
--- a/dstat_interface/interface/exp_int.py
+++ b/dstat_interface/interface/exp_int.py
@@ -30,6 +30,7 @@ except ImportError:
     sys.exit(1)
 
 import dstat_comm
+import experiments as exp
 import experiments.cal as cal
 import __main__
 from errors import InputError, VarError
@@ -37,8 +38,11 @@ logger = logging.getLogger("dstat.interface.exp_int")
 
 class ExpInterface(object):
     """Generic experiment interface class. Should be subclassed to implement
-    experiment interfaces by populating self.entry.
+    experiment interfaces by populating self.entry. Override class attributes
+    to set id and experiment class to run.
     """
+    id = None
+    experiment = None
     def __init__(self, glade_path):
         self.builder = Gtk.Builder()
         self.builder.add_from_file(glade_path)
@@ -77,6 +81,9 @@ class ExpInterface(object):
         """Updates UI with new parameters."""
         for i in self.entry:
             self.entry[i].set_text(self._params[i])
+            
+    def get_window(self):
+        return self.builder.get_object('scrolledwindow1')
         
 class Chronoamp(ExpInterface):
     """Experiment class for chronoamperometry. Extends ExpInterface class to
@@ -87,10 +94,14 @@ class Chronoamp(ExpInterface):
     on_remove_button_clicked(self, widget)
     get_params(self)
     """
+    id = 'cae'
+    experiment = exp.Chronoamp
     def __init__(self):
         """Extends superclass method to support treeview."""
         super(Chronoamp, self).__init__('interface/chronoamp.glade')
         
+        self.name = "Chronoamperometry"
+        
         self.statusbar = self.builder.get_object('statusbar')
         self.model = self.builder.get_object('ca_list')
         self.treeview = self.builder.get_object('treeview')
@@ -159,13 +170,70 @@ class Chronoamp(ExpInterface):
         
         for i in table:
             self.model.append(i)
-              
+          
+class EIS(ExpInterface):
+    """Experiment class for EIS."""
+    id = 'eis'
+    def __init__(self):
+        experiment = exp.EISExp
+        """Adds entry listings to superclass's self.entry dict"""
+        self.name = "Impedance Spectroscopy"
+        
+        self.entry = {} # to be used only for str parameters
+        self._params = None
+        
+        self.window = Gtk.ScrolledWindow()
+        self.window.set_vexpand(True)
+        
+        grid = Gtk.Grid()
+        grid.set_column_homogeneous(False)
+        
+        entries = {'start' : 'Start (Hz)',
+                   'stop' : 'Stop (Hz)',
+                   'n_increments' : 'Number of steps',
+                   'cycles' : 'Number of settling cycles'}
+        
+        for n, i in enumerate(entries.items()):
+            key, value = i
+            grid.attach(Gtk.Label(label=value), 0, n, 1, 1)
+            self.entry[key] = Gtk.Entry()
+            grid.attach(self.entry[key], 1, n, 1, 1)
+        
+        buttons = ('')
+        
+        self.window.add(grid)
+        
+    def get_window(self):
+        return self.window
+        
+    def _fill_params(self):
+        super(EIS, self)._fill_params()
+        
+        self._params['cyclic_true'] = False
+    
+    def _get_params(self):
+        """Updates self._params from UI."""
+        super(EIS, self)._get_params()
+        
+        self._params['cyclic_true'] = self.builder.get_object(    
+                           'cyclic_checkbutton').get_active()
+    
+    def _set_params(self):
+        """Updates UI with new parameters."""
+        super(EIS, self)._set_params()
+    
+        self.builder.get_object('cyclic_checkbutton').set_active(
+                                                self._params['cyclic_true'])
+    
 class LSV(ExpInterface):
     """Experiment class for LSV."""
+    id = 'lsv'
+    experiment = exp.LSVExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(LSV, self).__init__('interface/lsv.glade')
-
+        self.name = "Linear Sweep Voltammetry"
+        
         self.entry['clean_mV'] = self.builder.get_object('clean_mV')
         self.entry['clean_s'] = self.builder.get_object('clean_s')
         self.entry['dep_mV'] = self.builder.get_object('dep_mV')
@@ -176,10 +244,13 @@ class LSV(ExpInterface):
         
 class CV(ExpInterface):
     """Experiment class for CV."""
+    id = 'cve'
+    experiment = exp.CVExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(CV, self).__init__('interface/cv.glade')
-
+        self.name = "Cyclic Voltammetry"
+        
         self.entry['clean_mV'] = self.builder.get_object('clean_mV')
         self.entry['clean_s'] = self.builder.get_object('clean_s')
         self.entry['dep_mV'] = self.builder.get_object('dep_mV')
@@ -192,10 +263,13 @@ class CV(ExpInterface):
 
 class SWV(ExpInterface):
     """Experiment class for SWV."""
+    id = 'swv'
+    experiment = exp.SWVExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(SWV, self).__init__('interface/swv.glade')
-
+        self.name = "Square Wave Voltammetry"
+        
         self.entry['clean_mV'] = self.builder.get_object('clean_mV')
         self.entry['clean_s'] = self.builder.get_object('clean_s')
         self.entry['dep_mV'] = self.builder.get_object('dep_mV')
@@ -228,10 +302,14 @@ class SWV(ExpInterface):
         
 class DPV(ExpInterface):
     """Experiment class for DPV."""
+    id = 'dpv'
+    experiment = exp.DPVExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(DPV, self).__init__('interface/dpv.glade')
-
+        
+        self.name = "Differential Pulse Voltammetry"
+        
         self.entry['clean_mV'] = self.builder.get_object('clean_mV')
         self.entry['clean_s'] = self.builder.get_object('clean_s')
         self.entry['dep_mV'] = self.builder.get_object('dep_mV')
@@ -243,23 +321,29 @@ class DPV(ExpInterface):
         self.entry['period'] = self.builder.get_object('period_entry')
         self.entry['width'] = self.builder.get_object('width_entry')
         
-class ACV(ExpInterface):
-    """Experiment class for ACV."""
-    def __init__(self):
-        """Adds entry listings to superclass's self.entry dict"""
-        super(ACV, self).__init__('interface/acv.glade')
-        
-        self.entry['start'] = self.builder.get_object('start_entry')
-        self.entry['stop'] = self.builder.get_object('stop_entry')
-        self.entry['slope'] = self.builder.get_object('slope_entry')
-        self.entry['amplitude'] = self.builder.get_object('amplitude_entry')
-        self.entry['freq'] = self.builder.get_object('freq_entry')
+# class ACV(ExpInterface):
+#     """Experiment class for ACV."""
+#     id = 'acv'
+#     def __init__(self):
+#         """Adds entry listings to superclass's self.entry dict"""
+#         super(ACV, self).__init__('interface/acv.glade')
+#         self.name = "AC Voltammetry"
+#
+#         self.entry['start'] = self.builder.get_object('start_entry')
+#         self.entry['stop'] = self.builder.get_object('stop_entry')
+#         self.entry['slope'] = self.builder.get_object('slope_entry')
+#         self.entry['amplitude'] = self.builder.get_object('amplitude_entry')
+#         self.entry['freq'] = self.builder.get_object('freq_entry')
 
 class PD(ExpInterface):
     """Experiment class for PD."""
+    id = 'pde'
+    experiment = exp.PDExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(PD, self).__init__('interface/pd.glade')
+        self.name = "Photodiode/PMT"
+        
         
         self.entry['time'] = self.builder.get_object('time_entry')
         self.entry['sync_freq'] = self.builder.get_object('sync_freq')
@@ -361,17 +445,23 @@ class PD(ExpInterface):
         
 class POT(ExpInterface):
     """Experiment class for Potentiometry."""
+    id = 'pot'
+    experiment = exp.PotExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(POT, self).__init__('interface/potexp.glade')
+        self.name = "Potentiometry"
         
         self.entry['time'] = self.builder.get_object('time_entry')
         
 class CAL(ExpInterface):
     """Experiment class for Calibrating gain."""
+    id = 'cal'
+    experiment = exp.CALExp
     def __init__(self):
         """Adds entry listings to superclass's self.entry dict"""
         super(CAL, self).__init__('interface/calib.glade')
+        self.name = "Calilbration"
         
         self.entry['time'] = self.builder.get_object('time_entry')
         self.entry['R100'] = self.builder.get_object('100_entry')
diff --git a/dstat_interface/interface/exp_window.py b/dstat_interface/interface/exp_window.py
index 10fa69c..8e7c0a3 100755
--- a/dstat_interface/interface/exp_window.py
+++ b/dstat_interface/interface/exp_window.py
@@ -17,40 +17,69 @@
 #     You should have received a copy of the GNU General Public License
 #     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import inspect
+import logging
+from collections import OrderedDict
+
 import interface.exp_int as exp
 
+logger = logging.getLogger("dstat.interface.exp_window")
+
 class Experiments:
     def __init__(self, builder):
         self.builder = builder
+        self.builder.connect_signals(self)
         
         # (experiment index in UI, experiment)
-        self.classes = {}
-        self.classes['cae'] = (0, exp.Chronoamp())
-        self.classes['lsv'] = (1, exp.LSV())
-        self.classes['cve'] = (2, exp.CV())
-        self.classes['swv'] = (3, exp.SWV())
-        self.classes['dpv'] = (4, exp.DPV())
-        self.classes['acv'] = (5, exp.ACV())
-        self.classes['pde'] = (6, exp.PD())
-        self.classes['pot'] = (7, exp.POT())
-        self.classes['cal'] = (8, exp.CAL())
+            
+        classes = {c.id : c()  # Make class instances
+                        for _, c in inspect.getmembers(exp, inspect.isclass)
+                        if issubclass(c, exp.ExpInterface) 
+                            and c is not exp.ExpInterface
+                        }
         
-        # Create reverse lookup
-        self.select_to_key = {}
-        for key, value in self.classes.iteritems():
-            self.select_to_key[value[0]] = key
+        self.classes = OrderedDict(sorted(classes.items()))
  
         #fill exp_section
         exp_section = self.builder.get_object('exp_section_box')
         self.containers = {}
         
-        for key, cls in self.classes.iteritems():
-            self.containers[key] = cls[1].builder.get_object('scrolledwindow1')
+        for key, c in self.classes.items():
+            self.containers[key] = c.get_window()
 
         for key in self.containers:
-            self.containers[key].reparent(exp_section)
-            self.containers[key].hide()
+            try:
+                self.containers[key].get_parent().remove(self.containers[key])
+            except AttributeError:
+                pass
+                
+            exp_section.add(self.containers[key])
+        
+        self.expcombobox = self.builder.get_object('expcombobox')
+        self.expcombobox.connect('changed', self.on_expcombobox_changed)
         
+        for c in self.classes.values():
+            self.expcombobox.append(id=c.id, text=c.name)
+
+    def on_expcombobox_changed(self, data=None):
+        """Change the experiment window when experiment box changed."""
+        self.set_exp(self.expcombobox.get_active_id())
+    
+    def setup_exp(self, parameters):
+        exp = self.classes[self.expcombobox.get_active_id()]
+        try:
+            exp.param_test(parameters)
+        except AttributeError:
+            logger.warning(
+                "Experiment {} has no defined parameter test.".format(
+                    exp.name)
+                )
+        return exp.experiment(parameters)
+    
+    def hide_exps(self):
+        for key in self.containers:
+            self.containers[key].hide()
+    
     def set_exp(self, selection):
         """Changes parameter tab to selected experiment. Returns True if 
         successful, False if invalid selection received.
@@ -58,16 +87,14 @@ class Experiments:
         Arguments:
         selection -- id string of experiment type
         """
-        for key in self.containers:
-            self.containers[key].hide()
-
+        self.hide_exps()
         self.containers[selection].show()
         self.selected_exp = selection
         
         return True
         
     def get_params(self, experiment):
-        return self.classes[experiment][1].params
+        return self.classes[experiment].params
     
     def set_params(self, experiment, parameters):
-        self.classes[experiment][1].params = parameters
\ No newline at end of file
+        self.classes[experiment].params = parameters
\ No newline at end of file
diff --git a/dstat_interface/main.py b/dstat_interface/main.py
index 88eb552..274d2bb 100755
--- a/dstat_interface/main.py
+++ b/dstat_interface/main.py
@@ -138,12 +138,6 @@ class Main(object):
 
         self.serial_combobox.set_active(0)
 
-        #initialize experiment selection combobox
-        self.expcombobox = self.builder.get_object('expcombobox')
-        self.expcombobox.pack_start(self.cell, True)
-        self.expcombobox.add_attribute(self.cell, 'text', 2)
-        self.expcombobox.set_active(0)
-
         self.spinner = self.builder.get_object('spinner')
 
         self.mainwindow = self.builder.get_object('window1')
@@ -158,9 +152,9 @@ class Main(object):
         self.aboutdialog.set_version(ver)
 
         self.mainwindow.show_all()
-
-        self.on_expcombobox_changed()
-
+        self.exp_window.hide_exps()
+        
+        
         self.expnumber = 0
 
         self.connected = False
@@ -208,14 +202,6 @@ class Main(object):
     def on_menu_analysis_options_activate(self, menuitem, data=None):
         self.analysis_opt_window.show()
 
-    def on_expcombobox_changed(self, data=None):
-        """Change the experiment window when experiment box changed."""
-        model = self.expcombobox.get_model()
-        _, id, _ = model[self.expcombobox.get_active()]  # id is in 2nd col
-        self.statusbar.remove_all(self.error_context_id)
-        if not self.exp_window.set_exp(id):
-            self.statusbar.push(
-                self.error_context_id, "Experiment not yet implemented")
 
     def on_serial_refresh_clicked(self, data=None):
         """Refresh list of serial devices."""
@@ -441,53 +427,12 @@ class Main(object):
             self.stopbutton.set_sensitive(False)
             self.start_ocp()
 
-        def run_experiment():
-            """ Starts experiment """
-            interface.plot_ui.replace_notebook_exp(
-                self.plot_notebook, self.current_exp, self.window
-            )
-            for plots in self.current_exp.plots:
-                plots.changetype(self.current_exp)
-
-            # nb = self.plot_notebook
-            #
-            # if (parameters['sync_true'] and parameters['shutter_true']):
-            #     nb.get_nth_page(
-            #         nb.page_num(self.ft_window)).show()
-            #     # nb.get_nth_page(
-            #     #     nb.page_num(self.period_window)).show()
-            #     self.ft_plot.clearall()
-            #     self.ft_plot.changetype(self.current_exp)
-            # else:
-            #     nb.get_nth_page(nb.page_num(self.ft_window)).hide()
-            #     # nb.get_nth_page(nb.page_num(self.period_window)).hide()
-            
-            if parameters['db_enable_checkbutton']:
-                if db.current_db is None:
-                    db.start_db()
-                elif not db.current_db.connected:
-                    db.restart_db()
-            
-            comm.serial_instance.proc_pipe_p.send(self.current_exp)
-
-            # Flush data pipe
-            while comm.serial_instance.data_pipe_p.poll():
-                comm.serial_instance.data_pipe_p.recv()
-
-            self.plot_proc = GObject.timeout_add(200,
-                                                self.experiment_running_plot)
-            self.experiment_proc = (
-                    GObject.idle_add(self.experiment_running_data),
-                    GObject.idle_add(self.experiment_running_proc)
-            )
-
         self.stop_ocp()
         self.statusbar.remove_all(self.error_context_id)
 
         while comm.serial_instance.data_pipe_p.poll(): # Clear data pipe
             comm.serial_instance.data_pipe_p.recv()
 
-        selection = self.expcombobox.get_active()
         parameters = {}
         parameters['version'] = self.version
         parameters['metadata'] = self.metadata
@@ -509,84 +454,36 @@ class Main(object):
             self.startbutton.set_sensitive(False)
             self.stopbutton.set_sensitive(True)
             self.statusbar.remove_all(self.error_context_id)
+            
+            self.current_exp = self.exp_window.setup_exp(parameters)
+            
+            interface.plot_ui.replace_notebook_exp(
+                self.plot_notebook, self.current_exp, self.window
+                )
 
-            if selection == 0:  # CA
-                # Add experiment parameters to existing
-                parameters.update(self.exp_window.get_params('cae'))
-                if not parameters['potential']:
-                    raise InputError(parameters['potential'],
-                                     "Step table is empty")
-
-                self.current_exp = exp.Chronoamp(parameters)
-
-                self.rawbuffer.set_text("")
-                self.rawbuffer.place_cursor(self.rawbuffer.get_start_iter())
-
-                for i in self.current_exp.commands:
-                    self.rawbuffer.insert_at_cursor(i)
-
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 1: # LSV
-                parameter_test.lsv_test(parameters)
-
-                self.current_exp = exp.LSVExp(parameters)
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 2: # CV
-                parameter_test.cv_test(parameters)
-
-                self.current_exp = exp.CVExp(parameters)
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 3:  # SWV
-                parameter_test.swv_test(parameters)
-
-                self.current_exp = exp.SWVExp(parameters)
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 4:  # DPV
-                parameter_test.dpv_test(parameters)
-
-                self.current_exp = exp.DPVExp(parameters)
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 6:  # PD
-                parameter_test.pd_test(parameters)
-
-                self.current_exp = exp.PDExp(parameters)
-                run_experiment()
-
-                return experiment_id
-
-            elif selection == 7:  # POT
-                if not (self.version[0] >= 1 and self.version[1] >= 2):
-                    self.statusbar.push(self.error_context_id,
-                                "v1.1 board does not support potentiometry.")
-                    exceptions()
-                    return
-
-                parameter_test.pot_test(parameters)
-
-                self.current_exp = exp.PotExp(parameters)
-                run_experiment()
+            for plots in self.current_exp.plots:
+                plots.changetype(self.current_exp)
+            
+            if parameters['db_enable_checkbutton']:
+                if db.current_db is None:
+                    db.start_db()
+                elif not db.current_db.connected:
+                    db.restart_db()
+            
+            comm.serial_instance.proc_pipe_p.send(self.current_exp)
 
-                return experiment_id
+            # Flush data pipe
+            while comm.serial_instance.data_pipe_p.poll():
+                comm.serial_instance.data_pipe_p.recv()
 
-            else:
-                self.statusbar.push(self.error_context_id,
-                                    "Experiment not yet implemented.")
-                exceptions()
+            self.plot_proc = GObject.timeout_add(200,
+                                                self.experiment_running_plot)
+            self.experiment_proc = (
+                    GObject.idle_add(self.experiment_running_data),
+                    GObject.idle_add(self.experiment_running_proc)
+                    )
+                    
+            return experiment_id
 
         except ValueError as i:
             logger.info("ValueError: %s",i)
diff --git a/dstat_interface/params.py b/dstat_interface/params.py
index 6dbc720..1bf6db8 100755
--- a/dstat_interface/params.py
+++ b/dstat_interface/params.py
@@ -28,9 +28,8 @@ logger = logging.getLogger('dstat.params')
 def get_params(window):
     """Fetches and returns dict of all parameters for saving."""
 
+    selection = window.exp_window.expcombobox.get_active_id()
     parameters = {}
-
-    selection = window.exp_window.select_to_key[window.expcombobox.get_active()]
     parameters['experiment_index'] = selection
 
     try:
@@ -71,9 +70,7 @@ def load_params(window, path):
 def set_params(window, params):
     window.adc_pot.params = params
     if 'experiment_index' in params:
-        window.expcombobox.set_active(
-            window.exp_window.classes[params['experiment_index']][0]
-            )
+        window.exp_window.expcombobox.set_active_id(params['experiment_index'])
         window.exp_window.set_params(params['experiment_index'], params)
         
     window.analysis_opt_window.params = params
-- 
GitLab