class CalTreeItemModel(BaseTreeItemModel): def __init__(self, parent=None): super().__init__(parent) self.root_item = TreeItem(['key', 'value', 'refinable']) self.cfg = HexrdConfig() self.rebuild_tree() def data(self, index, role): if not index.isValid(): return None if role != Qt.DisplayRole and role != Qt.EditRole: return None item = self.get_item(index) value = item.data(index.column()) if index.column() == STATUS_COL: if role == Qt.EditRole: return value if role == Qt.DisplayRole: return None if isinstance(value, np.generic): # Get a native python type for display. Otherwise, # it won't display anything... value = value.item() return value def setData(self, index, value, role): item = self.get_item(index) path = self.path_to_value(item, index.column()) # If they are identical, don't do anything # (we exclude np.ndarray's from this) is_numpy = isinstance(value, np.ndarray) or \ isinstance(item.data(index.column()), np.ndarray) if not is_numpy and value == item.data(index.column()): return True key = item.data(KEY_COL) # Note: We don't want todo this check for panel buffers as they # can be a list or numpy.ndarray if index.column() == VALUE_COL and key != constants.BUFFER_KEY: old_value = self.cfg.get_instrument_config_val(path) # As a validation step, ensure that the new value can be # converted to the old value's type try: value = type(old_value)(value) except ValueError: msg = ('Could not convert ' + str(value) + ' to type ' + str(type(old_value).__name__)) QMessageBox.warning(None, 'HEXRD', msg) return False item.set_data(index.column(), value) if item.child_count() == 0: parent = item.parent_item.data(KEY_COL) if (parent == 'tilt' and HexrdConfig().rotation_matrix_euler() is not None and len(path) > 1 and path[-2] == 'value'): # Convert tilt values to radians before saving value = np.radians(value).item() self.cfg.set_instrument_config_val(path, value) dist_func_path = ['distortion', 'function_name', 'value'] if len(path) > 4 and path[2:5] == dist_func_path: # Rebuild the tree if the distortion function changed QObject.parent(self).rebuild_tree() return True def flags(self, index): if not index.isValid(): return Qt.NoItemFlags flags = super(CalTreeItemModel, self).flags(index) item = self.get_item(index) if ((index.column() == VALUE_COL and item.child_count() == 0) or index.column() == STATUS_COL): # The second and third columns with no children are editable flags = flags | Qt.ItemIsEditable return flags def add_tree_item(self, key, value, status, parent): # In the case of the panel buffer we don't want to added children # The editor will take care of this. if parent.data(KEY_COL) == constants.BUFFER_KEY: return data = [key, value, status] tree_item = TreeItem(data, parent) return tree_item def rebuild_tree(self): # Rebuild the tree from scratch self.clear() for key in self.cfg.internal_instrument_config.keys(): tree_item = self.add_tree_item(key, None, REFINABLE, self.root_item) self.recursive_add_tree_items( self.cfg.internal_instrument_config[key], tree_item) self.update_parent_status(tree_item) def recursive_add_tree_items(self, cur_config, cur_tree_item): if isinstance(cur_config, dict): keys = cur_config.keys() elif isinstance(cur_config, list): keys = range(len(cur_config)) else: # This must be a value. Set it. cur_tree_item.set_data(STATUS_COL, cur_config) return for key in keys: if key == 'value': data = cur_config[key] if (cur_tree_item.data(KEY_COL) == 'tilt' and HexrdConfig().rotation_matrix_euler() is not None): data = [np.degrees(rad).item() for rad in cur_config[key]] self.set_value(key, data, cur_tree_item) continue elif key == 'status': tree_item = cur_tree_item else: tree_item = self.add_tree_item(key, None, REFINABLE, cur_tree_item) if tree_item is not None: self.recursive_add_tree_items(cur_config[key], tree_item) def update_parent_status(self, parent): children = parent.child_items for child in children: if child.child_count() > 0: self.update_parent_status(child) if child.data(STATUS_COL): parent.set_data(STATUS_COL, FIXED) def path_to_value(self, tree_item, column): path = ['value'] if column == VALUE_COL else ['status'] cur_tree_item = tree_item while True: text = cur_tree_item.data(KEY_COL) if is_int(text): path.append(int(text)) else: path.insert(0, text) cur_tree_item = cur_tree_item.parent_item if cur_tree_item is self.root_item: break return path def set_value(self, key, cur_config, cur_tree_item): if isinstance(cur_config, list): children = cur_tree_item.child_items for child in children: value = cur_config[child.data(KEY_COL)] child.set_data(VALUE_COL, value) else: cur_tree_item.set_data(VALUE_COL, cur_config) return
class CalTreeItemModel(QAbstractItemModel): def __init__(self, parent=None): super(CalTreeItemModel, self).__init__(parent) self.root_item = TreeItem(['key', 'value', 'fixed']) self.cfg = HexrdConfig() self.rebuild_tree() def columnCount(self, parent): return self.root_item.column_count() def data(self, index, role): if not index.isValid(): return None if role != Qt.DisplayRole and role != Qt.EditRole: return None item = self.get_item(index) value = item.data(index.column()) if index.column() == STATUS_COL: if role == Qt.EditRole: return value if role == Qt.DisplayRole: return None return value def setData(self, index, value, role): item = self.get_item(index) path = self.get_path_from_root(item, index.column()) # If they are identical, don't do anything if value == item.data(index.column()): return True if index.column() == VALUE_COL: old_value = self.cfg.get_instrument_config_val(path) # As a validation step, ensure that the new value can be # converted to the old value's type try: value = type(old_value)(value) except ValueError: msg = ('Could not convert ' + str(value) + ' to type ' + str(type(old_value).__name__)) QMessageBox.warning(None, 'HEXRD', msg) return False item.set_data(index.column(), value) if item.child_count() == 0: self.cfg.set_instrument_config_val(path, value) return True def flags(self, index): if not index.isValid(): return Qt.NoItemFlags flags = super(CalTreeItemModel, self).flags(index) item = self.get_item(index) if ((index.column() == VALUE_COL and item.child_count() == 0) or index.column() == STATUS_COL): # The second and third columns with no children are editable flags = flags | Qt.ItemIsEditable return flags def headerData(self, section, orientation, role): if orientation == Qt.Horizontal and role == Qt.DisplayRole: return self.root_item.data(section) return None def index(self, row, column, parent): if not self.hasIndex(row, column, parent): return QModelIndex() parent_item = self.get_item(parent) child_item = parent_item.child(row) if not child_item: return QModelIndex() return self.createIndex(row, column, child_item) def parent(self, index): if not index.isValid(): return QModelIndex() child_item = self.get_item(index) parent_item = child_item.parent_item if not parent_item or parent_item is self.root_item: return QModelIndex() return self.createIndex(parent_item.row(), KEY_COL, parent_item) def rowCount(self, parent=QModelIndex()): parent_item = self.get_item(parent) return parent_item.child_count() def get_item(self, index): # If the index is valid and the internal pointer is valid, # return the item. Otherwise, return the root item. if index.isValid(): item = index.internalPointer() if item: return item return self.root_item def clear(self): # Remove all of the root item children. That clears it. root = self.root_item self.beginRemoveRows(QModelIndex(), KEY_COL, root.child_count() - 1) root.clear_children() self.endRemoveRows() def rebuild_tree(self): # Rebuild the tree from scratch self.clear() for key in self.cfg.internal_instrument_config.keys(): tree_item = self.add_tree_item(key, None, REFINED, self.root_item) self.recursive_add_tree_items( self.cfg.internal_instrument_config[key], tree_item) self.update_parent_status(tree_item) def add_tree_item(self, key, value, status, parent): data = [key, value, status] tree_item = TreeItem(data, parent) return tree_item def set_value(self, key, cur_config, cur_tree_item): if isinstance(cur_config, list): children = cur_tree_item.child_items for child in children: value = cur_config[child.data(KEY_COL)] child.set_data(VALUE_COL, value) else: cur_tree_item.set_data(VALUE_COL, cur_config) return def recursive_add_tree_items(self, cur_config, cur_tree_item): if isinstance(cur_config, dict): keys = cur_config.keys() elif isinstance(cur_config, list): keys = range(len(cur_config)) else: # This must be a value. Set it. cur_tree_item.set_data(STATUS_COL, cur_config) return for key in keys: if key == 'value': self.set_value(key, cur_config[key], cur_tree_item) continue elif key == 'status': tree_item = cur_tree_item else: tree_item = self.add_tree_item(key, None, REFINED, cur_tree_item) self.recursive_add_tree_items(cur_config[key], tree_item) def update_parent_status(self, parent): children = parent.child_items for child in children: if child.child_count() > 0: self.update_parent_status(child) if child.data(STATUS_COL): parent.set_data(STATUS_COL, FIXED) def get_path_from_root(self, tree_item, column): path = ['value'] if column == VALUE_COL else ['status'] cur_tree_item = tree_item while True: text = cur_tree_item.data(KEY_COL) if _is_int(text): path.append(int(text)) else: path.insert(0, text) cur_tree_item = cur_tree_item.parent_item if cur_tree_item is self.root_item: break return path