def reset_model(self, index): """Setup model according to current relationship_class selected in combobox. """ self.class_name, self.object_class_name_list = self.relationship_class_keys[ index] object_class_name_list = self.object_class_name_list.split(",") self.model.set_horizontal_header_labels(object_class_name_list) self.existing_items_model.set_horizontal_header_labels( object_class_name_list) self.new_items_model.set_horizontal_header_labels( object_class_name_list) self.relationship_ids.clear() for db_map in self.db_maps: relationship_classes = self.db_map_rel_cls_lookup[db_map] rel_cls = relationship_classes.get( (self.class_name, self.object_class_name_list), None) if rel_cls is None: continue for relationship in self.db_mngr.get_items_by_field( db_map, "relationship", "class_id", rel_cls["id"]): key = tuple(relationship["object_name_list"].split(",")) self.relationship_ids[key] = relationship["id"] existing_items = list(self.relationship_ids) self.existing_items_model.reset_model(existing_items) self.model.refresh() self.model.modelReset.emit() for wg in self.splitter_widgets(): wg.deleteLater() for name in object_class_name_list: tree_widget = QTreeWidget(self) tree_widget.setSelectionMode(QAbstractItemView.ExtendedSelection) tree_widget.setColumnCount(1) tree_widget.setIndentation(0) header_item = QTreeWidgetItem([name]) header_item.setTextAlignment(0, Qt.AlignHCenter) tree_widget.setHeaderItem(header_item) objects = self.db_mngr.get_items_by_field(self.db_map, "object", "class_name", name) items = [QTreeWidgetItem([obj["name"]]) for obj in objects] tree_widget.addTopLevelItems(items) tree_widget.resizeColumnToContents(0) self.splitter.addWidget(tree_widget) sizes = [wg.columnWidth(0) for wg in self.splitter_widgets()] self.splitter.setSizes(sizes) for widget in self.hidable_widgets: widget.show()
class TallyDock(PlotterDock): def __init__(self, model, font_metric, parent=None): super().__init__(model, font_metric, parent) self.setAllowedAreas(QtCore.Qt.RightDockWidgetArea) # Dock maps for tally information self.tally_map = {} self.filter_map = {} self.score_map = {} self.nuclide_map = {} # Tally selector self.tallySelectorLayout = QFormLayout() self.tallySelector = QComboBox(self) self.tallySelector.currentTextChanged[str].connect( self.main_window.editSelectedTally) self.tallySelectorLayout.addRow(self.tallySelector) self.tallySelectorLayout.setLabelAlignment(QtCore.Qt.AlignLeft) self.tallySelectorLayout.setFieldGrowthPolicy( QFormLayout.AllNonFixedFieldsGrow) # Add selector to its own box self.tallyGroupBox = QGroupBox('Selected Tally') self.tallyGroupBox.setLayout(self.tallySelectorLayout) # Create submit button self.applyButton = QPushButton("Apply Changes") self.applyButton.setMinimumHeight(self.font_metric.height() * 1.6) self.applyButton.clicked.connect(self.main_window.applyChanges) # Color options section self.tallyColorForm = ColorForm(self.model, self.main_window, 'tally') self.scoresGroupBox = Expander(title="Scores:") self.scoresListWidget = QListWidget() self.nuclidesListWidget = QListWidget() # Main layout self.dockLayout = QVBoxLayout() self.dockLayout.addWidget(QLabel("Tallies")) self.dockLayout.addWidget(HorizontalLine()) self.dockLayout.addWidget(self.tallyGroupBox) self.dockLayout.addStretch() self.dockLayout.addWidget(HorizontalLine()) self.dockLayout.addWidget(self.tallyColorForm) self.dockLayout.addWidget(HorizontalLine()) self.dockLayout.addWidget(self.applyButton) # Create widget for dock and apply main layout self.scroll = QScrollArea() self.scroll.setWidgetResizable(True) self.widget = QWidget() self.widget.setLayout(self.dockLayout) self.scroll.setWidget(self.widget) self.setWidget(self.scroll) def _createFilterTree(self, spatial_filters): av = self.model.activeView tally = self.model.statepoint.tallies[av.selectedTally] filters = tally.filters # create a tree for the filters self.treeLayout = QVBoxLayout() self.filterTree = QTreeWidget() self.treeLayout.addWidget(self.filterTree) self.treeExpander = Expander("Filters:", layout=self.treeLayout) self.treeExpander.expand() # start with filters expanded header = QTreeWidgetItem(["Filters"]) self.filterTree.setHeaderItem(header) self.filterTree.setItemHidden(header, True) self.filterTree.setColumnCount(1) self.filterTree.itemChanged.connect(self.updateFilters) self.filter_map = {} self.bin_map = {} for tally_filter in filters: filter_label = str(type(tally_filter)).split(".")[-1][:-2] filter_item = QTreeWidgetItem(self.filterTree, (filter_label,)) self.filter_map[tally_filter] = filter_item # make checkable if not spatial_filters: filter_item.setFlags(QtCore.Qt.ItemIsUserCheckable) filter_item.setToolTip(0, "Only tallies with spatial filters are viewable.") else: filter_item.setFlags(filter_item.flags() | QtCore.Qt.ItemIsTristate | QtCore.Qt.ItemIsUserCheckable) filter_item.setCheckState(0, QtCore.Qt.Unchecked) # all mesh bins are selected by default and not shown in the dock if isinstance(tally_filter, openmc.MeshFilter): filter_item.setCheckState(0, QtCore.Qt.Checked) filter_item.setFlags(QtCore.Qt.ItemIsUserCheckable) filter_item.setToolTip(0, "All Mesh bins are selected automatically") continue def _bin_sort_val(bin): if isinstance(bin, Iterable) and all([isinstance(val, float) for val in bin]): return np.sum(bin) else: return bin for bin in sorted(tally_filter.bins, key=_bin_sort_val): item = QTreeWidgetItem(filter_item, [str(bin),]) if not spatial_filters: item.setFlags(QtCore.Qt.ItemIsUserCheckable) item.setToolTip(0, "Only tallies with spatial filters are viewable.") else: item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(0, QtCore.Qt.Unchecked) bin = bin if not isinstance(bin, Iterable) else tuple(bin) self.bin_map[tally_filter, bin] = item # start with all filters selected if spatial filters are present if spatial_filters: filter_item.setCheckState(0, QtCore.Qt.Checked) def selectFromModel(self): cv = self.model.currentView self.selectedTally(cv.selectedTally) def selectTally(self, tally_label=None): # using active view to populate tally options live av = self.model.activeView # reset form layout for i in reversed(range(self.tallySelectorLayout.count())): self.tallySelectorLayout.itemAt(i).widget().setParent(None) # always re-add the tally selector to the layout self.tallySelectorLayout.addRow(self.tallySelector) self.tallySelectorLayout.addRow(HorizontalLine()) if tally_label is None or tally_label == "None" or tally_label == "": av.selectedTally = None self.score_map = None self.nuclide_map = None self.filter_map = None av.tallyValue = "Mean" else: # get the tally tally = self.model.statepoint.tallies[av.selectedTally] # populate filters filter_types = {type(f) for f in tally.filters} spatial_filters = bool(filter_types.intersection(_SPATIAL_FILTERS)) if not spatial_filters: self.filter_description = QLabel("(No Spatial Filters)") self.tallySelectorLayout.addRow(self.filter_description) self._createFilterTree(spatial_filters) self.tallySelectorLayout.addRow(self.treeExpander) self.tallySelectorLayout.addRow(HorizontalLine()) # value selection self.tallySelectorLayout.addRow(QLabel("Value:")) self.valueBox = QComboBox(self) self.values = tuple(_TALLY_VALUES.keys()) for value in self.values: self.valueBox.addItem(value) self.tallySelectorLayout.addRow(self.valueBox) self.valueBox.currentTextChanged[str].connect( self.main_window.editTallyValue) self.updateTallyValue() if not spatial_filters: self.valueBox.setEnabled(False) self.valueBox.setToolTip("Only tallies with spatial filters are viewable.") # scores self.score_map = {} self.scoresListWidget.itemClicked.connect( self.main_window.updateScores) self.score_map.clear() self.scoresListWidget.clear() sorted_scores = sorted(tally.scores) # always put total first if present if 'total' in sorted_scores: idx = sorted_scores.index('total') sorted_scores.insert(0, sorted_scores.pop(idx)) for score in sorted_scores: ql = QListWidgetItem() ql.setText(score.capitalize()) ql.setCheckState(QtCore.Qt.Unchecked) if not spatial_filters: ql.setFlags(QtCore.Qt.ItemIsUserCheckable) else: ql.setFlags(ql.flags() | QtCore.Qt.ItemIsUserCheckable) ql.setFlags(ql.flags() & ~QtCore.Qt.ItemIsSelectable) self.score_map[score] = ql self.scoresListWidget.addItem(ql) # select the first score item by default for item in self.score_map.values(): item.setCheckState(QtCore.Qt.Checked) break self.updateScores() self.scoresGroupBoxLayout = QVBoxLayout() self.scoresGroupBoxLayout.addWidget(self.scoresListWidget) self.scoresGroupBox = Expander("Scores:", layout=self.scoresGroupBoxLayout) self.tallySelectorLayout.addRow(self.scoresGroupBox) # nuclides self.nuclide_map = {} self.nuclidesListWidget.itemClicked.connect(self.main_window.updateNuclides) self.nuclide_map.clear() self.nuclidesListWidget.clear() sorted_nuclides = sorted(tally.nuclides) # always put total at the top if 'total' in sorted_nuclides: idx = sorted_nuclides.index('total') sorted_nuclides.insert(0, sorted_nuclides.pop(idx)) for nuclide in sorted_nuclides: ql = QListWidgetItem() ql.setText(nuclide.capitalize()) ql.setCheckState(QtCore.Qt.Unchecked) if not spatial_filters: ql.setFlags(QtCore.Qt.ItemIsUserCheckable) else: ql.setFlags(ql.flags() | QtCore.Qt.ItemIsUserCheckable) ql.setFlags(ql.flags() & ~QtCore.Qt.ItemIsSelectable) self.nuclide_map[nuclide] = ql self.nuclidesListWidget.addItem(ql) # select the first nuclide item by default for item in self.nuclide_map.values(): item.setCheckState(QtCore.Qt.Checked) break self.updateNuclides() self.nuclidesGroupBoxLayout = QVBoxLayout() self.nuclidesGroupBoxLayout.addWidget(self.nuclidesListWidget) self.nuclidesGroupBox = Expander("Nuclides:", layout=self.nuclidesGroupBoxLayout) self.tallySelectorLayout.addRow(self.nuclidesGroupBox) def updateMinMax(self): self.tallyColorForm.updateMinMax() def updateTallyValue(self): cv = self.model.currentView idx = self.valueBox.findText(cv.tallyValue) self.valueBox.setCurrentIndex(idx) def updateSelectedTally(self): cv = self.model.currentView idx = 0 if cv.selectedTally: idx = self.tallySelector.findData(cv.selectedTally) self.tallySelector.setCurrentIndex(idx) def updateFilters(self): applied_filters = defaultdict(tuple) for f, f_item in self.filter_map.items(): if type(f) == openmc.MeshFilter: continue filter_checked = f_item.checkState(0) if filter_checked != QtCore.Qt.Unchecked: selected_bins = [] for idx, b in enumerate(f.bins): b = b if not isinstance(b, Iterable) else tuple(b) bin_checked = self.bin_map[(f, b)].checkState(0) if bin_checked == QtCore.Qt.Checked: selected_bins.append(idx) applied_filters[f] = tuple(selected_bins) self.model.appliedFilters = applied_filters def updateScores(self): applied_scores = [] for score, score_box in self.score_map.items(): if score_box.checkState() == QtCore.Qt.CheckState.Checked: applied_scores.append(score) self.model.appliedScores = tuple(applied_scores) if not applied_scores: # if no scores are selected, enable all scores again for score, score_box in self.score_map.items(): sunits = _SCORE_UNITS.get(score, _REACTION_UNITS) empty_item = QListWidgetItem() score_box.setFlags(empty_item.flags() | QtCore.Qt.ItemIsUserCheckable) score_box.setFlags(empty_item.flags() & ~QtCore.Qt.ItemIsSelectable) elif 'total' in applied_scores: self.model.appliedScores = ('total',) # if total is selected, disable all other scores for score, score_box in self.score_map.items(): if score != 'total': score_box.setFlags(QtCore.Qt.ItemIsUserCheckable) score_box.setToolTip("De-select 'total' to enable other scores") else: # get units of applied scores selected_units = _SCORE_UNITS.get(applied_scores[0], _REACTION_UNITS) # disable scores with incompatible units for score, score_box in self.score_map.items(): sunits = _SCORE_UNITS.get(score, _REACTION_UNITS) if sunits != selected_units: score_box.setFlags(QtCore.Qt.ItemIsUserCheckable) score_box.setToolTip("Score is incompatible with currently selected scores") else: score_box.setFlags(score_box.flags() | QtCore.Qt.ItemIsUserCheckable) score_box.setFlags(score_box.flags() & ~QtCore.Qt.ItemIsSelectable) def updateNuclides(self): applied_nuclides = [] for nuclide, nuclide_box in self.nuclide_map.items(): if nuclide_box.checkState() == QtCore.Qt.CheckState.Checked: applied_nuclides.append(nuclide) self.model.appliedNuclides = tuple(applied_nuclides) if 'total' in applied_nuclides: self.model.appliedNuclides = ['total',] for nuclide, nuclide_box in self.nuclide_map.items(): if nuclide != 'total': nuclide_box.setFlags(QtCore.Qt.ItemIsUserCheckable) nuclide_box.setToolTip("De-select 'total' to enable other nuclides") elif not applied_nuclides: # if no nuclides are selected, enable all nuclides again for nuclide, nuclide_box in self.nuclide_map.items(): empty_item = QListWidgetItem() nuclide_box.setFlags(empty_item.flags() | QtCore.Qt.ItemIsUserCheckable) nuclide_box.setFlags(empty_item.flags() & ~QtCore.Qt.ItemIsSelectable) def update(self): # update the color form self.tallyColorForm.update() if self.model.statepoint: self.tallySelector.clear() self.tallySelector.setEnabled(True) self.tallySelector.addItem("None") for idx, tally in enumerate(self.model.statepoint.tallies.values()): if tally.name == "": self.tallySelector.addItem('Tally {}'.format(tally.id), userData=tally.id) else: self.tallySelector.addItem('Tally {} "{}"'.format(tally.id, tally.name), userData=tally.id) self.tally_map[idx] = tally self.updateSelectedTally() self.updateMinMax() else: self.tallySelector.clear() self.tallySelector.setDisabled(True)