Completed
Push — pulsed_with_queued_connections ( 6b1460...30fbbf )
by
unknown
02:58
created

BlockEditor   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 366
Duplicated Lines 13.39 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 49
loc 366
rs 5.5555
c 1
b 0
f 0
wmc 56

13 Methods

Rating   Name   Duplication   Size   Complexity  
A _get_list() 0 2 1
B initialize_cells() 33 33 6
F load_pulse_block() 0 63 12
F _set_columns() 0 98 14
A delete_row() 0 7 1
A clear_table() 0 9 1
A set_element() 0 20 2
A set_configs() 0 12 2
C generate_block_object() 0 54 9
A insert_rows() 0 9 2
A get_element() 0 17 1
A __init__() 0 13 1
A _set_cfg_param() 16 16 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like BlockEditor often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
from qtpy import QtCore
2
from qtpy import QtWidgets
3
import numpy as np
4
from collections import OrderedDict
5
6
from logic.pulse_objects import PulseBlockElement
7
from logic.pulse_objects import PulseBlock
8
from logic.pulse_objects import PulseBlockEnsemble
9
from logic.pulse_objects import PulseSequence
10
from logic.sampling_functions import SamplingFunctions
11
12
from .spinbox_delegate import SpinBoxDelegate
13
from .doublespinbox_delegate import DoubleSpinBoxDelegate
14
from .combobox_delegate import ComboBoxDelegate
15
from .checkbox_delegate import CheckBoxDelegate
16
17
18
class BlockEditor:
19
    def __init__(self, block_editor_widget):
20
        self.be_widget = block_editor_widget
21
        self.parameter_dict = OrderedDict()
22
        self.parameter_dict['length'] = {'unit': 's', 'init_val': 0.0, 'min': 0.0, 'max': np.inf,
23
                                         'view_stepsize': 1e-9, 'dec': 8, 'unit_prefix': 'n', 'type': float}
24
        self.parameter_dict['increment'] = {'unit': 's', 'init_val': 0.0, 'min': 0.0, 'max': np.inf,
25
                                            'view_stepsize': 1e-9, 'dec': 8, 'unit_prefix': 'n', 'type': float}
26
        self.parameter_dict['use as tick?'] = {'unit': '', 'init_val': 0, 'min': 0, 'max': 1, 'view_stepsize': 1,
27
                                               'dec': 0, 'unit_prefix': '', 'type': bool}
28
        self.activation_config = None
29
        self.function_config = SamplingFunctions().func_config
30
        self._cfg_param_pbe = None
31
        return
32
33 View Code Duplication
    def initialize_cells(self, start_row, stop_row=None, start_col=None, stop_col=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
34
        """ Initialize the desired cells in the block editor table.
35
36
        @param start_row: int, index of the row, where the initialization
37
                          should start
38
        @param stop_row: int, optional, index of the row, where the
39
                         initalization should end.
40
        @param start_col: int, optional, index of the column where the
41
                          initialization should start
42
        @param stop_col: int, optional, index of the column, where the
43
                         initalization should end.
44
45
        With this function it is possible to reinitialize specific elements or
46
        part of a row or even the whole row. If start_row is set to 0 the whole
47
        row is going to be initialzed to the default value.
48
        """
49
        if stop_row is None:
50
            stop_row = start_row + 1
51
        if start_col is None:
52
            start_col = 0
53
        if stop_col is None:
54
            stop_col = self.be_widget.columnCount()
55
        for col_num in range(start_col, stop_col):
56
            for row_num in range(start_row, stop_row):
57
                # get the model, here are the data stored:
58
                model = self.be_widget.model()
59
                # get the corresponding index of the current element:
60
                index = model.index(row_num, col_num)
61
                # get the initial values of the delegate class which was uses for this column:
62
                ini_values = self.be_widget.itemDelegateForColumn(col_num).get_initial_value()
63
                # set initial values:
64
                model.setData(index, ini_values[0], ini_values[1])
65
        return
66
67
    def _get_list(self):
68
        return list(self.function_config)
69
70
    def _set_columns(self):
71
        self.be_widget.blockSignals(True)
72
        # Determine the function with the most parameters. Use also that function as a construction plan to create all
73
        # the needed columns for the parameters.
74
        num_max_param = 0
75
        for func in self.function_config:
76
            if num_max_param < len(self.function_config[func]):
77
                num_max_param = len(self.function_config[func])
78
                biggest_func = func
79
80
        # Erase the delegate from the column, pass a None reference:
81
        for column in range(self.be_widget.columnCount()):
82
            self.be_widget.setItemDelegateForColumn(column, None)
83
        # clear the number of columns:
84
        self.be_widget.setColumnCount(0)
85
        # total number of analog and digital channels:
86
        num_of_columns = 0
87
        for channel in self.activation_config:
88
            if 'd_ch' in channel:
89
                num_of_columns += 1
90
            elif 'a_ch' in channel:
91
                num_of_columns += num_max_param + 1
92
        self.be_widget.setColumnCount(num_of_columns)
93
94
        column_count = 0
95
        for channel in self.activation_config:
96
            if 'a_ch' in channel:
97
                self.be_widget.setHorizontalHeaderItem(column_count, QtWidgets.QTableWidgetItem())
98
                self.be_widget.horizontalHeaderItem(column_count).setText('ACh{0}\nfunction'
99
                                                                          ''.format(channel.split('ch')[-1]))
100
                self.be_widget.setColumnWidth(column_count, 70)
101
102
                item_dict = {'get_list_method': self._get_list}
103
                delegate = ComboBoxDelegate(self.be_widget, item_dict)
104
                self.be_widget.setItemDelegateForColumn(column_count, delegate)
105
106
                column_count += 1
107
                # fill here all parameter columns for the current analogue channel
108
                for parameter in self.function_config[biggest_func]:
109
                    # initial block:
110
                    item_dict = self.function_config[biggest_func][parameter]
111
                    self.be_widget.setHorizontalHeaderItem(column_count, QtWidgets.QTableWidgetItem())
112
                    self.be_widget.horizontalHeaderItem(column_count).setText('ACh{0}\n{1} ({2})'
113
                                                                              ''.format(channel.split('ch')[-1],
114
                                                                                        parameter, item_dict['unit']))
115
                    self.be_widget.setColumnWidth(column_count, 100)
116
117
                    # extract the classname from the _param_a_ch list to be able to deligate:
118
                    delegate = DoubleSpinBoxDelegate(self.be_widget, item_dict)
119
                    self.be_widget.setItemDelegateForColumn(column_count, delegate)
120
                    column_count += 1
121
122
            elif 'd_ch' in channel:
123
                self.be_widget.setHorizontalHeaderItem(column_count, QtWidgets.QTableWidgetItem())
124
                self.be_widget.horizontalHeaderItem(column_count).setText('DCh{0}'.format(channel.split('ch')[-1]))
125
                self.be_widget.setColumnWidth(column_count, 40)
126
127
                # itemlist for checkbox
128
                item_dict = {'init_val': QtCore.Qt.Unchecked}
129
                checkDelegate = CheckBoxDelegate(self.be_widget, item_dict)
130
                self.be_widget.setItemDelegateForColumn(column_count, checkDelegate)
131
132
                column_count += 1
133
134
        # Insert the additional parameters (length etc.)
135
136
        for column, parameter in enumerate(self.parameter_dict):
137
            # add the new properties to the whole column through delegate:
138
            item_dict = self.parameter_dict[parameter]
139
140
            self.be_widget.insertColumn(num_of_columns + column)
141
            self.be_widget.setHorizontalHeaderItem(num_of_columns + column, QtWidgets.QTableWidgetItem())
142
            self.be_widget.horizontalHeaderItem(num_of_columns + column).setText('{0} ({1})'.format(parameter,
143
                                                                                                    item_dict['unit']))
144
            self.be_widget.setColumnWidth(num_of_columns + column, 90)
145
146
            # Use only DoubleSpinBox as delegate:
147
            if item_dict['type'] is bool:
148
                delegate = CheckBoxDelegate(self.be_widget, item_dict)
149
            else:
150
                delegate = DoubleSpinBoxDelegate(self.be_widget, item_dict)
151
            self.be_widget.setItemDelegateForColumn(num_of_columns + column, delegate)
152
153
            # initialize the whole row with default values:
154
            for row_num in range(self.be_widget.rowCount()):
155
                # get the model, here are the data stored:
156
                model = self.be_widget.model()
157
                # get the corresponding index of the current element:
158
                index = model.index(row_num, num_of_columns + column)
159
                # get the initial values of the delegate class which was uses for this column:
160
                ini_values = delegate.get_initial_value()
161
                # set initial values:
162
                model.setData(index, ini_values[0], ini_values[1])
163
164
        self.initialize_cells(0, self.be_widget.rowCount())
165
        self._set_cfg_param()
166
        self.be_widget.blockSignals(False)
167
        return
168
169 View Code Duplication
    def _set_cfg_param(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
170
        """ Set the parameter configuration of the Pulse_Block according to the
171
        current table configuration and updates the dict.
172
        """
173
        cfg_param_pbe = OrderedDict()
174
        for column in range(self.be_widget.columnCount()):
175
            text = self.be_widget.horizontalHeaderItem(column).text()
176
            split_text = text.split()
177
            if 'DCh' in split_text[0]:
178
                cfg_param_pbe['digital_' + split_text[0][3]] = column
179
            elif 'ACh' in split_text[0]:
180
                cfg_param_pbe[split_text[1] + '_' + split_text[0][3]] = column
181
            else:
182
                cfg_param_pbe[split_text[0]] = column
183
        self._cfg_param_pbe = cfg_param_pbe
184
        return
185
186
    def set_configs(self, activation_config, function_config=None):
187
        """
188
189
        @param activation_config:
190
        @param function_config:
191
        @return:
192
        """
193
        self.activation_config = activation_config
194
        if function_config is not None:
195
            self.function_config = function_config
196
        self._set_columns()
197
        return
198
199
    def clear_table(self):
200
        """ Delete all rows in the block editor table. """
201
        self.be_widget.blockSignals(True)
202
        self.be_widget.setRowCount(1)
203
        self.be_widget.clearContents()
204
        self.initialize_cells(start_row=0)
205
        self.be_widget.blockSignals(False)
206
        # FIXME: Implement a proper way to update the current block ensemble parameters
207
        return
208
209
    def delete_row(self, index):
210
        """ Delete row number 'index' """
211
        self.be_widget.blockSignals(True)
212
        self.be_widget.removeRow(index)
213
        self.be_widget.blockSignals(False)
214
        # FIXME: Implement a proper way to update the current block ensemble parameters
215
        return
216
217
    def insert_rows(self, index, number_to_add=1):
218
        """ Add 'number_to_add' rows after row number 'index' """
219
        self.be_widget.blockSignals(True)
220
        for i in range(number_to_add):
221
            self.be_widget.insertRow(index)
222
        self.initialize_cells(start_row=index, stop_row=index + number_to_add)
223
        self.be_widget.blockSignals(False)
224
        # FIXME: Implement a proper way to update the current block ensemble parameters
225
        return
226
227
    def set_element(self, row, column, value):
228
        """ Simplified wrapper function to set the data to a specific cell in the table.
229
230
        @param int row: row index
231
        @param int column: column index
232
233
        Note that the order of the arguments in this function (first row index
234
        and then column index) was taken from the Qt convention.
235
        A type check will be performed for the passed value argument. If the
236
        type does not correspond to the delegate, then the value will not be
237
        changed. You have to ensure that
238
        """
239
        model = self.be_widget.model()
240
        access = self.be_widget.itemDelegateForColumn(column).model_data_access
241
        data = model.index(row, column).data(access)
242
        if type(data) == type(value):
243
            model.setData(model.index(row, column), value, access)
244
            return value
245
        else:
246
            return data
247
248
    def get_element(self, row, column):
249
        """ Simplified wrapper function to get the data from a specific cell in the table.
250
251
        @param int row: row index
252
        @param int column: column index
253
        @return: the value of the corresponding cell, which can be a string, a
254
                 float or an integer. Remember that the checkbox state
255
                 unchecked corresponds to 0 and check to 2. That is Qt
256
                 convention.
257
258
        Note that the order of the arguments in this function (first row index
259
        and then column index) was taken from the Qt convention.
260
        """
261
        # Get from the corresponding delegate the data access model
262
        access = self.be_widget.itemDelegateForColumn(column).model_data_access
263
        data = self.be_widget.model().index(row, column).data(access)
264
        return data
265
266
    def load_pulse_block(self, block):
267
        """
268
269
        @param block:
270
        @return:
271
        """
272
        if block is None:
273
            return
274
        # seperate active analog and digital channels in lists
275
        active_analog = [chnl for chnl in self.activation_config if 'a_ch' in chnl]
276
        active_digital = [chnl for chnl in self.activation_config if 'd_ch' in chnl]
277
278
        # clear table
279
        self.clear_table()
280
        # get amout of rows needed for display
281
        rows = len(block.element_list)
282
        # since one is already present
283
        self.insert_rows(1, rows - 1)
284
285
        for row_index, elem in enumerate(block.element_list):
286
            # set at first all digital channels:
287
            for digital_ch in range(elem.digital_channels):
288
                column = self._cfg_param_pbe['digital_' + active_digital[digital_ch].split('ch')[-1]]
289
                value = elem.digital_high[digital_ch]
290
                if value:
291
                    value = 2
292
                else:
293
                    value = 0
294
                self.set_element(row_index, column, value)
295
296
            # now set all parameters for the analog channels:
297
            for analog_ch in range(elem.analog_channels):
298
                # the function text:
299
                column = self._cfg_param_pbe['function_' + active_analog[analog_ch].split('ch')[-1]]
300
                func_text = elem.pulse_function[analog_ch]
301
                self.set_element(row_index, column, func_text)
302
                # then the parameter dictionary:
303
                parameter_dict = elem.parameters[analog_ch]
304
                for parameter in parameter_dict:
305
                    column = self._cfg_param_pbe[parameter + '_' + active_analog[analog_ch].split('ch')[-1]]
306
                    value = np.float(parameter_dict[parameter])
307
                    self.set_element(row_index, column, value)
308
309
            # now set use as tick parameter:
310
            column = self._cfg_param_pbe['use']
311
            value = elem.use_as_tick
312
            # the ckeckbox has a special input value, it is 0, 1 or 2. (tri-state)
313
            if value:
314
                value = 2
315
            else:
316
                value = 0
317
            self.set_element(row_index, column, value)
318
319
            # and set the init_length:
320
            column = self._cfg_param_pbe['length']
321
            value = elem.init_length_s
322
            self.set_element(row_index, column, value)
323
324
            # and set the increment parameter
325
            column = self._cfg_param_pbe['increment']
326
            value = elem.increment_s
327
            self.set_element(row_index, column, value)
328
        return
329
330
    def generate_block_object(self, pb_name):
331
        """ Generates from an given table block_matrix a block_object.
332
333
        @param pb_name: string, Name of the created Pulse_Block Object
334
        """
335
336
        # list of all the pulse block element objects
337
        pbe_obj_list = [None] * self.be_widget.rowCount()
338
339
        # seperate digital and analogue channels
340
        analog_chnl_names = [chnl for chnl in self.activation_config if 'a_ch' in chnl]
341
        digital_chnl_names = [chnl for chnl in self.activation_config if 'd_ch' in chnl]
342
343
        for row_index in range(self.be_widget.rowCount()):
344
            # get length:
345
            init_length_s = self.get_element(row_index, self._cfg_param_pbe['length'])
346
            # get increment:
347
            increment_s = self.get_element(row_index, self._cfg_param_pbe['increment'])
348
349
            # get the proper pulse_functions and its parameters:
350
            pulse_function = [None] * len(analog_chnl_names)
351
            parameter_list = [None] * len(analog_chnl_names)
352
            for chnl_index, chnl in enumerate(analog_chnl_names):
353
                # get the number of the analogue channel according to the channel activation_config
354
                a_chnl_number = chnl.split('ch')[-1]
355
                pulse_function[chnl_index] = self.get_element(row_index, self._cfg_param_pbe['function_' + a_chnl_number])
356
357
                # search for this function in the dictionary and get all the parameter with their names in list:
358
                param_dict = self.function_config[pulse_function[chnl_index]]
359
                parameters = {}
360
                for entry in list(param_dict):
361
                    # Obtain how the value is displayed in the table:
362
                    param_value = self.get_element(row_index,
363
                                                   self._cfg_param_pbe[entry + '_' + a_chnl_number])
364
                    parameters[entry] = param_value
365
                parameter_list[chnl_index] = parameters
366
367
            digital_high = [None] * len(digital_chnl_names)
368
            for chnl_index, chnl in enumerate(digital_chnl_names):
369
                # get the number of the digital channel according to the channel activation_config
370
                d_chnl_number = chnl.split('ch')[-1]
371
                digital_high[chnl_index] = bool(self.get_element(row_index, self._cfg_param_pbe['digital_' + d_chnl_number]))
372
373
            use_as_tick = bool(self.get_element(row_index, self._cfg_param_pbe['use']))
374
375
            # create here actually the object with all the obtained information:
376
            pbe_obj_list[row_index] = PulseBlockElement(init_length_s=init_length_s,
377
                                                          increment_s=increment_s,
378
                                                          pulse_function=pulse_function,
379
                                                          digital_high=digital_high,
380
                                                          parameters=parameter_list,
381
                                                          use_as_tick=use_as_tick)
382
        pb_obj = PulseBlock(pb_name, pbe_obj_list)
383
        return pb_obj
384
385
386
class BlockOrganizer:
387
    def __init__(self, block_organizer_widget):
388
        self.bo_widget = block_organizer_widget
389
        self.parameter_dict = OrderedDict()
390
        self.parameter_dict['repetitions'] = {'unit': '#', 'init_val': 0, 'min': 0,
391
                                              'max': (2 ** 31 - 1), 'view_stepsize': 1, 'dec': 0,
392
                                              'unit_prefix': '', 'type': int}
393
        self._cfg_param_pb = None
394
        self.block_dict = None
395
        return
396
397
    def set_block_dict(self, block_dict):
398
        if self.block_dict is None:
399
            self.block_dict = block_dict
400
            self._set_columns()
401
        else:
402
            self.block_dict = block_dict
403
404
        for row in range(self.bo_widget.rowCount()):
405
            data = self.get_element(row, 0)
406
            if data not in list(self.block_dict):
407
                self.initialize_cells(start_row=row, stop_row=row+1, start_col=0, stop_col=1)
408
        return
409
410
    def _get_list(self):
411
        return list(self.block_dict)
412
413 View Code Duplication
    def initialize_cells(self, start_row, stop_row=None, start_col=None, stop_col=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
414
        """ Initialize the desired cells in the block organizer table.
415
416
        @param start_row: int, index of the row, where the initialization
417
                          should start
418
        @param stop_row: int, optional, index of the row, where the
419
                         initalization should end.
420
        @param start_col: int, optional, index of the column where the
421
                          initialization should start
422
        @param stop_col: int, optional, index of the column, where the
423
                         initalization should end.
424
425
        With this function it is possible to reinitialize specific elements or
426
        part of a row or even the whole row. If start_row is set to 0 the whole
427
        row is going to be initialzed to the default value.
428
        """
429
        if stop_row is None:
430
            stop_row = start_row +1
431
        if start_col is None:
432
            start_col = 0
433
        if stop_col is None:
434
            stop_col = self.bo_widget.columnCount()
435
        for col_num in range(start_col, stop_col):
436
            for row_num in range(start_row,stop_row):
437
                # get the model, here are the data stored:
438
                model = self.bo_widget.model()
439
                # get the corresponding index of the current element:
440
                index = model.index(row_num, col_num)
441
                # get the initial values of the delegate class which was uses for this column:
442
                ini_values = self.bo_widget.itemDelegateForColumn(col_num).get_initial_value()
443
                # set initial values:
444
                model.setData(index, ini_values[0], ini_values[1])
445
        return
446
447
    def _set_columns(self):
448
        # Erase the delegate from the column, i.e. pass a None reference:
449
        for column in range(self.bo_widget.columnCount()):
450
            self.bo_widget.setItemDelegateForColumn(column, None)
451
        # clear the number of columns and set them to 1:
452
        self.bo_widget.setColumnCount(1)
453
        self.bo_widget.setHorizontalHeaderItem(0, QtWidgets.QTableWidgetItem())
454
        self.bo_widget.horizontalHeaderItem(0).setText('Pulse Block')
455
        self.bo_widget.setColumnWidth(0, 100)
456
457
        item_dict = {}
458
        item_dict['get_list_method'] = self._get_list
459
        comboDelegate = ComboBoxDelegate(self.bo_widget, item_dict)
460
        self.bo_widget.setItemDelegateForColumn(0, comboDelegate)
461
462
        for column, parameter in enumerate(self.parameter_dict):
463
            # add the new properties to the whole column through delegate:
464
            item_dict = self.parameter_dict[parameter]
465
            unit_text = item_dict['unit_prefix'] + item_dict['unit']
466
            self.bo_widget.insertColumn(1+column)
467
            self.bo_widget.setHorizontalHeaderItem(1+column, QtWidgets.QTableWidgetItem())
468
            self.bo_widget.horizontalHeaderItem(1+column).setText('{0} ({1})'.format(parameter,unit_text))
469
            self.bo_widget.setColumnWidth(1+column, 80)
470
            # Use only DoubleSpinBox as delegate:
471
            if item_dict['unit'] == 'bool':
472
                delegate = CheckBoxDelegate(self.bo_widget, item_dict)
473
            elif parameter == 'repetitions':
474
                delegate = SpinBoxDelegate(self.bo_widget, item_dict)
475
            else:
476
                delegate = DoubleSpinBoxDelegate(self.bo_widget, item_dict)
477
            self.bo_widget.setItemDelegateForColumn(1+column, delegate)
478
479
        self.initialize_cells(start_row=0, stop_row=self.bo_widget.rowCount())
480
        self._set_cfg_param()
481
        # FIXME: Implement a proper way to update the current block ensemble parameters
482
        return
483
484 View Code Duplication
    def _set_cfg_param(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
485
        """ Set the parameter configuration of the Pulse_Block according to the
486
        current table configuration and updates the dict.
487
        """
488
        cfg_param_pb = OrderedDict()
489
        for column in range(self.bo_widget.columnCount()):
490
            text = self.bo_widget.horizontalHeaderItem(column).text()
491
            if 'Pulse Block' in text:
492
                cfg_param_pb['pulse_block'] = column
493
            elif 'repetitions' in text:
494
                cfg_param_pb['repetitions'] = column
495
            else:
496
                print('text:', text)
497
                raise NotImplementedError
498
        self._cfg_param_pb = cfg_param_pb
499
        return
500
501
    def clear_table(self):
502
        """ Delete all rows in the block editor table. """
503
        self.bo_widget.blockSignals(True)
504
        self.bo_widget.setRowCount(1)
505
        self.bo_widget.clearContents()
506
        self.initialize_cells(start_row=0)
507
        self.bo_widget.blockSignals(False)
508
        # FIXME: Implement a proper way to update the current block ensemble parameters
509
        return
510
511
    def delete_row(self, index):
512
        """ Delete row number 'index' """
513
        self.bo_widget.removeRow(index)
514
        # FIXME: Implement a proper way to update the current block ensemble parameters
515
        return
516
517
    def insert_rows(self, index, number_to_add=1):
518
        """ Add 'number_to_add' rows after row number 'index' """
519
        self.bo_widget.blockSignals(True)
520
        for i in range(number_to_add):
521
            self.bo_widget.insertRow(index)
522
        self.initialize_cells(start_row=index, stop_row=index + number_to_add)
523
        self.bo_widget.blockSignals(False)
524
        # FIXME: Implement a proper way to update the current block ensemble parameters
525
        return
526
527
    def set_element(self, row, column, value):
528
        """ Simplified wrapper function to set the data to a specific cell in the table.
529
530
        @param int row: row index
531
        @param int column: column index
532
533
        Note that the order of the arguments in this function (first row index and then column
534
        index) was taken from the Qt convention. A type check will be performed for the passed
535
        value argument. If the type does not correspond to the delegate, then the value will not be
536
        changed. You have to ensure that.
537
        """
538
        model = self.bo_widget.model()
539
        access = self.bo_widget.itemDelegateForColumn(column).model_data_access
540
        data = self.bo_widget.model().index(row, column).data(access)
541
        if type(data) == type(value):
542
            model.setData(model.index(row, column), value, access)
543
            return value
544
        else:
545
            return data
546
547
    def get_element(self, row, column):
548
        """ Simplified wrapper function to get the data from a specific cell in the table.
549
550
        @param int row: row index
551
        @param int column: column index
552
        @return: the value of the corresponding cell, which can be a string, a
553
                 float or an integer. Remember that the checkbox state
554
                 unchecked corresponds to 0 and check to 2. That is Qt
555
                 convention.
556
557
        Note that the order of the arguments in this function (first row index
558
        and then column index) was taken from the Qt convention.
559
        """
560
        # Get from the corresponding delegate the data access model
561
        access = self.bo_widget.itemDelegateForColumn(column).model_data_access
562
        data = self.bo_widget.model().index(row, column).data(access)
563
        return data
564
565
    def load_pulse_block_ensemble(self, ensemble):
566
        """
567
568
        @param ensemble:
569
        """
570
        # Sanity checks:
571
        if ensemble is None:
572
            return
573
        # clear the block organizer table
574
        self.clear_table()
575
        # get amout of rows needed for display
576
        rows = len(ensemble.block_list)
577
        # add as many rows as there are blocks in the ensemble minus 1 because a single row is
578
        # already present after clear
579
        self.insert_rows(1, rows - 1)
580
        # run through all blocks in the block_elements block_list to fill in the row informations
581
        for row_index, (pulse_block, repetitions) in enumerate(ensemble.block_list):
582
            column = self._cfg_param_pb['pulse_block']
583
            self.set_element(row_index, column, pulse_block.name)
584
            column = self._cfg_param_pb['repetitions']
585
            self.set_element(row_index, column, int(repetitions))
586
        return
587
588
    def generate_ensemble_object(self, ensemble_name, rotating_frame=True):
589
        """
590
        Generates from an given table ensemble_matrix a ensemble object.
591
592
        @param str ensemble_name: Name of the created PulseBlockEnsemble object
593
        @param bool rotating_frame: optional, whether the phase preservation is mentained
594
                                    throughout the sequence.
595
        """
596
        # list of all the pulse block element objects
597
        pb_obj_list = [None] * self.bo_widget.rowCount()
598
599
        for row_index in range(self.bo_widget.rowCount()):
600
            pulse_block_name = self.get_element(row_index, self._cfg_param_pb['pulse_block'])
601
            pulse_block_reps = self.get_element(row_index, self._cfg_param_pb['repetitions'])
602
            # Fetch previously saved block object
603
            block = self.block_dict[pulse_block_name]
604
            # Append block object along with repetitions to the block list
605
            pb_obj_list[row_index] = (block, pulse_block_reps)
606
607
        # Create the Pulse_Block_Ensemble object
608
        pulse_block_ensemble = PulseBlockEnsemble(name=ensemble_name, block_list=pb_obj_list,
609
                                                    rotating_frame=rotating_frame)
610
        return pulse_block_ensemble
611