Example #1
0
def cleanup_scenarios(rangefind_rep, scenIds):
    """Remove scenarios from the database that were rangefinders, i.e.: low replication scenarios"""
    settings = RaseSettings()
    session = Session()

    scenarios = []
    for scen in scenIds:
        scenarios.append(session.query(Scenario).filter_by(id=scen).first())

    scens_to_delete = []
    for scen in scenarios:
        if scen.replication == rangefind_rep:
            scens_to_delete.append(scen.id)

    delete_scenario(scens_to_delete, settings.getSampleDirectory())

    session.commit()
Example #2
0
def delete_scenario(scenario_ids, sample_root_dir):
    """
    Delete scenarios from database and cleanup sample folders
    """
    session = Session()
    for id in scenario_ids:
        scenDelete = session.query(Scenario).filter(Scenario.id == id)
        matDelete = session.query(ScenarioMaterial).filter(ScenarioMaterial.scenario_id == id)
        backgMatDelete = session.query(ScenarioBackgroundMaterial).filter(ScenarioBackgroundMaterial.scenario_id == id)

        # folders
        folders = [name for name in glob.glob(os.path.join(sample_root_dir, "*" + id + "*"))]
        for folder in folders:
            shutil.rmtree(folder)

        # database
        scenObj = scenDelete.first()
        scenObj.scenario_groups.clear()
        matDelete.delete()
        backgMatDelete.delete()
        scenDelete.delete()
        session.commit()

    session.close()
Example #3
0
class ScenarioDialog(ui_create_scenario_dialog.Ui_ScenarioDialog, QDialog):
    def __init__(self, rase_gui, id=None, duplicate=[], auto_s=False):
        QDialog.__init__(self)
        self.setupUi(self)
        self.rase_gui = rase_gui
        self.tblMaterial.setContextMenuPolicy(Qt.CustomContextMenu)
        self.tblBackground.setContextMenuPolicy(Qt.CustomContextMenu)
        self.id = id
        self.auto_s = auto_s
        self.settings = RaseSettings()
        self.scenarioHasChanged = False
        self.groupHasChanged = False
        self.duplicate = duplicate
        self.session = Session()

        self.txtAcqTime.setText('30')
        self.txtAcqTime.setToolTip(
            "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
        )
        self.txtReplication_2.setText('100')
        int_validator = QIntValidator()
        self.txtAcqTime.setValidator(RegExpSetValidator())
        self.txtReplication_2.setValidator(int_validator)

        self.tblMaterial.setHorizontalHeaderItem(INTENSITY,
                                                 QTableWidgetItem('Intensity'))
        self.tblBackground.setHorizontalHeaderItem(
            INTENSITY, QTableWidgetItem('Intensity'))

        self.tblMaterial.customContextMenuRequested.connect(
            lambda x, table=self.tblMaterial: self.context_auto_range(
                x, self.tblMaterial))
        self.tblBackground.customContextMenuRequested.connect(
            lambda x, table=self.tblBackground: self.context_auto_range(
                x, self.tblBackground))

        # set material table
        self.tblMaterial.setItemDelegate(
            MaterialDoseDelegate(self.tblMaterial,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY))
        self.tblMaterial.setRowCount(10)
        for row in range(self.tblMaterial.rowCount()):
            self.tblMaterial.setItem(row, UNITS, QTableWidgetItem())
            self.tblMaterial.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblMaterial.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblMaterial.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblMaterial.setRowHeight(row, 22)

        # set background table
        self.tblBackground.setItemDelegate(
            MaterialDoseDelegate(self.tblBackground,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 auto_s=self.auto_s))
        self.tblBackground.setRowCount(10)
        for row in range(self.tblBackground.rowCount()):
            self.tblBackground.setItem(row, UNITS, QTableWidgetItem())
            self.tblBackground.setItem(row, INTENSITY, QTableWidgetItem())
            self.tblBackground.setItem(row, MATERIAL, QTableWidgetItem())
            self.tblBackground.item(row, INTENSITY).setToolTip(
                "Enter comma-separated values OR range as min-max:step OR range followed by comma-separated values"
            )
            self.tblBackground.setRowHeight(row, 22)

        # fill influence list
        for influence in self.session.query(Influence):
            self.lstInfluences.addItem(QListWidgetItem(influence.name))

        self.comboDetectorSelect.addItems(
            ["all detectors"] +
            [s.name for s in self.session.query(Detector).all()])
        self.comboDetectorSelect.currentIndexChanged.connect(
            self.updateTableDelegate)

        # display a previous scenario if defined
        if self.id:
            if not self.duplicate:
                self.setWindowTitle("Scenario Edit")
                scenario = self.session.query(Scenario).get(id)
                materials = scenario.scen_materials
                bckg_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                for table, mat_list in zip(
                    (self.tblMaterial, self.tblBackground),
                    (materials, bckg_materials)):
                    for rowCount, mat in enumerate(mat_list):
                        item = QTableWidgetItem(units_labels[mat.fd_mode])
                        item.setData(Qt.UserRole, mat.fd_mode)
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(mat.material_name))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(mat.dose)))
                self.txtAcqTime.setText(str(scenario.acq_time))
                self.txtReplication_2.setText(str(scenario.replication))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

            else:
                self.setWindowTitle("Build Scenario from Other Scenario")
                scens = [
                    self.session.query(Scenario).filter_by(id=scen).first()
                    for scen in self.duplicate
                ]
                scenario = scens[0]
                materials = scenario.scen_materials
                back_materials = scenario.scen_bckg_materials
                influences = scenario.influences
                mat_dict = {}
                back_dict = {}
                mat_fd = []
                back_fd = []
                for mat in materials:
                    mat_fd.append((mat.material_name, mat.fd_mode))
                    mat_dict[mat.material_name] = set([mat.dose])
                for back in back_materials:
                    back_fd.append((back.material_name, back.fd_mode))
                    back_dict[back.material_name] = set([back.dose])

                if len(scens) > 1:
                    for scen in scens[1:]:
                        mat_dict = self.make_matDict(scen.scen_materials,
                                                     mat_dict)
                        back_dict = self.make_matDict(scen.scen_bckg_materials,
                                                      back_dict)
                        if influences:
                            influences.append[scen.influences]
                        else:
                            influences = scen.influences

                for table, material_dictionary, fd_list in \
                        zip((self.tblMaterial, self.tblBackground), (mat_dict, back_dict), (mat_fd, back_fd)):
                    mat_list_tup = [(k, v)
                                    for k, v in material_dictionary.items()]
                    for rowCount, (mat, fd_mode) in enumerate(
                            zip(mat_list_tup, fd_list)):
                        doses = [str(d) for d in sorted(mat[1])]
                        item = QTableWidgetItem(units_labels[fd_mode[1]])
                        item.setData(Qt.UserRole, fd_mode[1])
                        table.setItem(rowCount, 0, item)
                        table.setItem(rowCount, 1,
                                      QTableWidgetItem(str(mat[0])))
                        table.setItem(rowCount, 2,
                                      QTableWidgetItem(str(','.join(doses))))
                self.txtAcqTime.setText(str(scenario.acq_time))
                for influence in influences:
                    lst = self.lstInfluences.findItems(influence.name,
                                                       Qt.MatchExactly)[0]
                    lst.setSelected(True)
                self.groups = self.getGroups()

        else:
            self.groups = []

        if self.auto_s and self.rase_gui.static_background:
            for rowCount, mat in enumerate(self.rase_gui.static_background):
                mat = mat[0]
                item = QTableWidgetItem(units_labels[mat[0]])
                item.setData(Qt.UserRole, mat[0])
                self.tblBackground.setItem(rowCount, 0, item)
                self.tblBackground.setItem(rowCount, 1,
                                           QTableWidgetItem(mat[1].name))
                self.tblBackground.setItem(rowCount, 2,
                                           QTableWidgetItem(str(mat[2])))

        # signal/slot connections (this has to be done after_ the previous scenario is loaded)
        self.tblMaterial.cellChanged.connect(self.scenarioChanged)
        self.tblBackground.cellChanged.connect(self.scenarioChanged)
        self.tblMaterial.cellChanged.connect(self.updateScenariosList)
        self.tblBackground.cellChanged.connect(self.updateScenariosList)
        self.lstInfluences.itemSelectionChanged.connect(self.scenarioChanged)
        self.txtAcqTime.textChanged.connect(self.scenarioChanged)
        self.txtReplication_2.textChanged.connect(self.scenarioChanged)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

    def make_matDict(self, mats, m_dict):
        for mat in mats:
            m_dict[mat.material_name].update([mat.dose])
        return m_dict

    def getGroups(self):
        if self.id:
            if not self.duplicate:
                scen_edit = self.session.query(Scenario).filter_by(
                    id=self.id).first()
                return [grp.name for grp in scen_edit.scenario_groups]
            else:
                scens = [
                    self.session.query(Scenario).filter_by(id=scen).first()
                    for scen in self.duplicate
                ]
                grps = set()
                for scen in scens:
                    grps.update([grp.name for grp in scen.scenario_groups])
                return grps
        else:
            return []

    @pyqtSlot()
    def scenarioChanged(self):
        """
        Listens for Scenario changed
        """
        self.scenarioHasChanged = True

    @pyqtSlot()
    def groupChanged(self):
        """
        Listens for group changed
        """
        self.groupHasChanged = True

    @pyqtSlot(int)
    def updateTableDelegate(self, index):
        if index == 0:
            selected_detname = None
        else:
            selected_detname = self.comboDetectorSelect.currentText()
        self.tblMaterial.setItemDelegate(
            MaterialDoseDelegate(self.tblMaterial,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 selected_detname=selected_detname))
        self.tblBackground.setItemDelegate(
            MaterialDoseDelegate(self.tblBackground,
                                 unitsCol=UNITS,
                                 materialCol=MATERIAL,
                                 intensityCol=INTENSITY,
                                 selected_detname=selected_detname,
                                 auto_s=self.auto_s))

    @pyqtSlot(QPoint)
    def context_auto_range(self, point, table):
        current_cell = table.itemAt(point)
        # show the context menu only if on an a valid part of the table
        if current_cell:
            column = current_cell.column()
            if column == 2:
                autorangeAction = QAction('Auto-Define Range', self)
                menu = QMenu(table)
                menu.addAction(autorangeAction)
                action = menu.exec_(table.mapToGlobal(point))
                if action == autorangeAction:
                    auto_list = self.auto_range()
                    if auto_list:
                        current_cell.setText(','.join(auto_list))

    @pyqtSlot(bool)
    def auto_range(self):
        dialog = ScenarioRange(self)
        dialog.setWindowModality(Qt.WindowModal)
        if dialog.exec_():
            if dialog.points:
                return dialog.points

    @pyqtSlot()
    def updateScenariosList(self):
        materialStr = ""
        for row in range(self.tblMaterial.rowCount()):
            untStr = self.tblMaterial.item(row, UNITS).text()
            matStr = self.tblMaterial.item(row, MATERIAL).text()
            intStr = self.tblMaterial.item(row, INTENSITY).text()
            if matStr and untStr and intStr:
                if (len(materialStr) > 0):
                    materialStr = materialStr + "\n "
                materialStr = materialStr + '{}({})'.format(matStr, ', '.join("{:.5f}".format(float(dose)) for
                                  dose in self.getSet(self.tblMaterial.item(row, INTENSITY)))) + \
                                  ', Units: ' + self.tblMaterial.item(row, UNITS).data(Qt.UserRole).title()

        backgroundStr = ""
        for row in range(self.tblBackground.rowCount()):
            untStr = self.tblBackground.item(row, UNITS).text()
            matStr = self.tblBackground.item(row, MATERIAL).text()
            intStr = self.tblBackground.item(row, INTENSITY).text()
            if matStr and untStr and intStr:
                if (len(backgroundStr) > 0):
                    backgroundStr = backgroundStr + "\n "
                backgroundStr = backgroundStr + '{}({})'.format(matStr, ', '.join("{:.5f}".format(float(dose)) for
                                  dose in self.getSet(self.tblBackground.item(row, INTENSITY)))) + \
                                  ', Units: ' + self.tblBackground.item(row, UNITS).data(Qt.UserRole).title()
        self.txtScenariosList_2.setText(
            f"Source materials:\n {materialStr} \n\nBackground materials:\n {backgroundStr}"
        )

    @pyqtSlot(bool)
    def on_btnGroups_clicked(self, checked):
        dialog = GroupSettings(self, groups=self.groups)
        dialog.setWindowModality(Qt.WindowModal)
        if dialog.exec_():
            self.groups = dialog.n_groups

    @pyqtSlot()
    def accept(self):
        if self.auto_s:
            materials_doses = []
            for matsT in [self.tblBackground]:
                for row in range(matsT.rowCount()):
                    matName = matsT.item(row, MATERIAL).text()
                    if matName:
                        matArr = []
                        for dose in self.getSet(matsT.item(row, 2)):
                            mat = self.session.query(Material).filter_by(
                                name=matName).first()
                            fd_mat = matsT.item(row, UNITS).data(Qt.UserRole)
                            matArr.append((fd_mat, mat, dose))
                        materials_doses.append(matArr)

            self.rase_gui.static_background = materials_doses
            return QDialog.accept(self)

        self.tblMaterial.setCurrentIndex(QModelIndex(
        ))  # so that if table item is being edited it will commit the data

        # if this is edit rather than create, need to treat differently:
        if self.id and not self.duplicate:
            # check if the scenario has been changed by the user
            # Note that this approach considers a change even if
            # the user rewrites the previous entry identically
            if not self.scenarioHasChanged:
                # update just the group for the same scenario
                # so as not to change the scenario ID
                scen = self.session.query(Scenario).get(self.id)
                self.provide_message_new_groups = False
                self.add_groups_to_scen(scen, self.groups, add_groups=True)
                self.session.commit()
                return QDialog.accept(self)
            else:
                # clear the existing scenario first
                self.scenario_delete()

        # replication and influences
        replication = int(self.txtReplication_2.text())
        influences = []  # element type: Influence
        for index in self.lstInfluences.selectedIndexes():
            influences.append(
                self.session.query(Influence).filter_by(
                    name=self.lstInfluences.itemFromIndex(
                        index).text()).first())

        materials_doses = [[], []]
        for i, matsT in enumerate([self.tblMaterial, self.tblBackground]):
            for row in range(matsT.rowCount()):
                matName = matsT.item(row, MATERIAL).text()
                if matName:
                    matArr = []
                    for dose in self.getSet(matsT.item(row, 2)):
                        mat = self.session.query(Material).filter_by(
                            name=matName).first()
                        fd_mat = matsT.item(row, UNITS).data(Qt.UserRole)
                        matArr.append((fd_mat, mat, dose))
                    materials_doses[i].append(matArr)

        # cartesian product to break out scenarios from scenario group
        integrity_fail = False
        duplicate = False
        self.provide_message_new_groups = True
        for acqTime in self.getSet(self.txtAcqTime):
            mm = product(*materials_doses[0])
            bb = product(*materials_doses[1])
            for mat_dose_arr, bckg_mat_dose_arr in product(mm, bb):
                scenMaterials = [
                    ScenarioMaterial(material=m, dose=float(d), fd_mode=u)
                    for u, m, d in mat_dose_arr
                ]
                bcgkScenMaterials = [
                    ScenarioBackgroundMaterial(material=m,
                                               dose=float(d),
                                               fd_mode=u)
                    for u, m, d in bckg_mat_dose_arr
                ]
                scen_groups = []
                try:
                    for groupname in self.groups:
                        scen_groups.append(
                            self.session.query(ScenarioGroup).filter_by(
                                name=groupname).first())
                    if not scen_groups:
                        scen_groups.append(
                            self.session.query(ScenarioGroup).filter_by(
                                name='default_group').first())
                    # if just changing groups, add to new group without creating a new scenario
                    scen_hash = Scenario.scenario_hash(float(acqTime),
                                                       scenMaterials,
                                                       bcgkScenMaterials,
                                                       influences)
                    scen_exists = self.session.query(Scenario).filter_by(
                        id=scen_hash).first()
                    add_groups = False
                    if scen_exists:
                        # and (sorted([g.name for g in scen_exists.scenario_groups]) !=
                        #                 sorted([g.name for g in scen_groups])):
                        for group in scen_groups:
                            if group not in scen_exists.scenario_groups:
                                add_groups = True
                                break
                        all_groups = set(g.name
                                         for g in scen_exists.scenario_groups +
                                         scen_groups)
                        all_groups.update(self.groups)
                        # don't allow duplicate scenarios, unless there are other scenarios in the group that are
                        # simply having their group changed. In which case, pass by those groups without impact.
                        duplicate = self.add_groups_to_scen(
                            scen_exists, all_groups, add_groups=add_groups)
                    else:
                        Scenario(float(acqTime), replication, scenMaterials,
                                 bcgkScenMaterials, influences, scen_groups)
                # if inputting multiple scenarios with at least one preexisting scenario (i.e.: this only happens when
                # the loop traverses more than once and the database is accessed again)
                except (IntegrityError, FlushError):
                    self.integrity_message(materials_doses)
                    integrity_fail = True
                    break

        # if inputting a single scenario that already exists
        if not integrity_fail:
            if duplicate:
                self.integrity_message(materials_doses)
            else:
                try:
                    self.session.commit()
                    return QDialog.accept(self)
                except (IntegrityError, FlushError):
                    self.integrity_message(materials_doses)

    def add_groups_to_scen(self, scen, all_groups, add_groups=False):
        """
        Clear groups associated with a scenario and append new ones
        """
        if add_groups:
            scen.scenario_groups.clear()
            for groupname in all_groups:
                scen.scenario_groups.append(
                    self.session.query(ScenarioGroup).filter_by(
                        name=groupname).first())
                if self.provide_message_new_groups:
                    QMessageBox.information(
                        self, 'Record Exists',
                        'At least one defined scenario is already in the database; '
                        'adding scenario to additional groups.')
                    self.provide_message_new_groups = False
        elif self.provide_message_new_groups:
            return True
        return False

    def scenario_delete(self):
        """
        Clear existing scenario before adding the modified version
        """
        scenDelete = self.session.query(Scenario).filter(
            Scenario.id == self.id)
        matDelete = self.session.query(ScenarioMaterial).filter(
            ScenarioMaterial.scenario_id == self.id)
        bckgMatDelete = self.session.query(ScenarioBackgroundMaterial).filter(
            ScenarioBackgroundMaterial.scenario_id == self.id)
        scenTableAssocDelete = scenDelete.first()
        scenTableAssocDelete.scenario_groups.clear()
        scenTableAssocDelete.influences.clear()
        matDelete.delete()
        bckgMatDelete.delete()
        scenDelete.delete()

    def integrity_message(self, materials_doses):
        if (materials_doses[0] and len(list(product(*materials_doses[0]))) > 1) or \
                (materials_doses[1] and len(list(product(*materials_doses[1]))) > 1):
            QMessageBox.critical(
                self, 'Record Exists',
                'At least one defined scenario is already in the database! '
                'Please change scenarios.')
        else:
            QMessageBox.critical(
                self, 'Record Exists',
                'This scenario is already in the database! Please change scenario.'
            )
        self.session.rollback()

    # TODO: combine these two methods using a cellChanged.connect()
    @pyqtSlot(int, int)
    def on_tblMaterial_cellChanged(self, row, col):
        """
        Listens for Material table cell changed
        """
        if col == UNITS:
            if self.tblMaterial.item(row, MATERIAL) and self.tblMaterial.item(
                    row, INTENSITY):
                if not self.tblMaterial.item(row, UNITS).data(Qt.UserRole):
                    self.tblMaterial.item(row, MATERIAL).setText('')
                    self.tblMaterial.item(row, INTENSITY).setText('')
                elif self.tblMaterial.item(row, MATERIAL):
                    units = self.tblMaterial.item(row, UNITS)
                    matName = self.tblMaterial.item(row, MATERIAL)
                    doseItem = self.tblMaterial.item(row, INTENSITY)
                    self.set_otherCols_fromUnit(units, matName, doseItem)

        if col == MATERIAL:
            units = self.tblMaterial.item(row, UNITS)
            matName = self.tblMaterial.item(row, MATERIAL).text()
            doseItem = self.tblMaterial.item(row, INTENSITY)
            self.set_otherCols_fromMat(units, matName, doseItem)

    @pyqtSlot(int, int)
    def on_tblBackground_cellChanged(self, row, col):
        """
        Listens for Material table cell changed
        """
        if col == UNITS:
            if self.tblBackground.item(
                    row, MATERIAL) and self.tblBackground.item(row, INTENSITY):
                if not self.tblBackground.item(row, UNITS).data(Qt.UserRole):
                    self.tblBackground.item(row, MATERIAL).setText('')
                    self.tblBackground.item(row, INTENSITY).setText('')
                elif self.tblBackground.item(row, MATERIAL):
                    units = self.tblBackground.item(row, UNITS)
                    matName = self.tblBackground.item(row, MATERIAL)
                    doseItem = self.tblBackground.item(row, INTENSITY)
                    self.set_otherCols_fromUnit(units, matName, doseItem)
        if col == MATERIAL:
            units = self.tblBackground.item(row, UNITS)
            matName = self.tblBackground.item(row, MATERIAL).text()
            doseItem = self.tblBackground.item(row, INTENSITY)
            self.set_otherCols_fromMat(units, matName, doseItem)

    def set_otherCols_fromUnit(self, units, matName, doseItem):
        textKeep = False
        if self.comboDetectorSelect.currentIndex() == 0:
            detector_list = [
                detector for detector in Session().query(Detector)
            ]
        else:
            detector_list = [
                Session().query(Detector).filter_by(
                    name=self.comboDetectorSelect.currentText()).first()
            ]
        for detector in detector_list:
            for baseSpectrum in detector.base_spectra:
                if baseSpectrum.material.name == matName.text(
                ) and not textKeep:
                    if (units.data(Qt.UserRole) == 'DOSE' and isinstance(baseSpectrum.rase_sensitivity, float)) or \
                       (units.data(Qt.UserRole) == 'FLUX' and isinstance(baseSpectrum.flux_sensitivity, float)):
                        textKeep = True
        if not textKeep:
            matName.setText('')

    def set_otherCols_fromMat(self, units, matName, doseItem):
        if matName:
            if not doseItem.text():
                doseItem.setText('0.1')
            if not units.text():
                textSet = False
                if self.comboDetectorSelect.currentIndex() == 0:
                    detector_list = [
                        detector for detector in Session().query(Detector)
                    ]
                else:
                    detector_list = [
                        Session().query(Detector).filter_by(
                            name=self.comboDetectorSelect.currentText()).first(
                            )
                    ]
                for detector in detector_list:
                    for baseSpectrum in detector.base_spectra:
                        if baseSpectrum.material.name == matName and not textSet:
                            units.tableWidget().blockSignals(True)
                            if isinstance(baseSpectrum.rase_sensitivity,
                                          float):
                                units.setText(units_labels['DOSE'])
                                units.setData(Qt.UserRole, 'DOSE')
                                textSet = True
                            else:
                                units.setText(units_labels['FLUX'])
                                units.setData(Qt.UserRole, 'FLUX')
                            units.tableWidget().blockSignals(False)

    def getSet(self, dialogField):
        values = []
        groups = dialogField.text().split(',')
        for group in groups:
            group = group.strip()
            if '-' in group and ':' in group:
                start, stop, step = [
                    float(x)
                    for x in re.match(r'([^-]+)-([^:]+):(.*)', group).groups()
                ]
                if step == 0:
                    values.append(start)
                    values.append(stop)
                else:
                    while start <= stop:
                        values.append(start)
                        start += step
            else:
                values.append(group)
        return values
Example #4
0
class GroupSettings(QDialog):
    """Simple Dialog to allow the user to select which groups a scenario is in.
    This information is stored in the scenario_groups table value for each scenario.

    :param parent: the parent dialog
    """
    def __init__(self, parent=None, groups=[], scens=None, del_groups=False):
        QDialog.__init__(self, parent)
        self.groups = groups
        self.scens = scens
        self.del_groups = del_groups
        self.session = Session()

        self.makeLayout()

    def makeLayout(self):
        cols_list = [grp.name for grp in self.session.query(ScenarioGroup)]
        cols_list.insert(0, cols_list.pop(cols_list.index('default_group')))
        cb_list = [QCheckBox(v.replace('&', '&&')) for v in cols_list]

        self.layout = QVBoxLayout()
        self.checklayout = QVBoxLayout()
        self.buttonlayout = QVBoxLayout()

        for cb in cb_list:
            self.checklayout.addWidget(cb)
            if cb.text() in self.groups:
                cb.setChecked(True)
            if cb.text() == 'default_group' and self.del_groups:
                cb.setEnabled(False)

        self.btn_newgroup = QPushButton('Add New Group')
        self.buttonlayout.addWidget(self.btn_newgroup)
        self.btn_newgroup.clicked.connect(self.addCheckbox)
        self.buttonBox = QDialogButtonBox(self)

        if self.del_groups:
            self.btn_deletegroup = QPushButton('Remove Group(s)')
            self.buttonlayout.addWidget(self.btn_deletegroup)
            self.btn_deletegroup.clicked.connect(self.delGroup)
            self.buttonBox.setStandardButtons(QDialogButtonBox.Close)
            self.buttonBox.rejected.connect(self.reject)
        else:
            self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                              | QDialogButtonBox.Ok)
            self.buttonBox.accepted.connect(self.accept)
            self.buttonBox.rejected.connect(self.reject)
        self.buttonlayout.addWidget(self.buttonBox)

        self.layout.addLayout(self.checklayout)
        self.layout.addLayout(self.buttonlayout)
        if not self.del_groups and self.scens and len(self.scens) > 1:
            self.info = QLabel(
                'NOTE: A group box is checked if\nany one of the selected scenarios\nis in that '
                'group. Pressing OK will\nadd all selected scenarios to the\nselected groups.'
            )
            self.layout.addWidget(self.info)
        self.setLayout(self.layout)

    def _cb_list(self):
        return [
            self.checklayout.itemAt(i).widget()
            for i in range(self.checklayout.count())
        ]

    def addCheckbox(self):
        newgroup, okPressed = QInputDialog.getText(self,
                                                   "Add New Scenario Group",
                                                   "Scenario Group name:",
                                                   QLineEdit.Normal, "")
        collist = [grp.name for grp in self.session.query(ScenarioGroup)]
        if okPressed and (newgroup != '' and newgroup not in collist):
            self.checklayout.addWidget(QCheckBox(newgroup))
            self.setLayout(self.layout)
            self.add_groups(self.session, newgroup)

    def delGroup(self):
        del_groups = [cb.text() for cb in self._cb_list() if cb.isChecked()]
        if len(del_groups) > 1:
            answer = QMessageBox(
                QMessageBox.Question, 'Delete Scenario Groups',
                'Are you sure you want to delete these scenario groups? '
                'Scenarios in these groups will not be deleted')
        else:
            answer = QMessageBox(
                QMessageBox.Question, 'Delete Scenario Group',
                'Are you sure you want to delete this scenario group? '
                'Scenarios in this group will not be deleted')
        answer.addButton(QMessageBox.Yes)
        answer.addButton(QMessageBox.No)
        ans_hold = answer.exec()
        if ans_hold == QMessageBox.Yes:
            for group in del_groups:
                self.delete_groups(self.session, group)
            for cb in self._cb_list():
                if cb.text() in del_groups:
                    self.checklayout.removeWidget(cb)
                    cb.deleteLater()

    @staticmethod
    def delete_groups(session, group):
        group_delete = session.query(ScenarioGroup).filter(
            ScenarioGroup.name == group)
        group_delete.delete()
        session.commit()

    @staticmethod
    def add_groups(session, group):
        session.add(ScenarioGroup(name=group))
        session.commit()

    @pyqtSlot()
    def accept(self):
        """
        Adds the scenario to the checked groups
        """
        self.n_groups = [cb.text() for cb in self._cb_list() if cb.isChecked()]
        if self.scens:
            for scen in self.scens:
                scen.scenario_groups.clear()
                for groupname in self.n_groups:
                    scen.scenario_groups.append(
                        self.session.query(ScenarioGroup).filter_by(
                            name=groupname).first())
            self.session.commit()
        return QDialog.accept(self)