class MainData(BaseObject): headers_1 = ['Data Id', 'Data Size'] headers_2 = ['Data'] def __init__(self): super(MainData, self).__init__() self.data = OrderedDict() self.data_keys = [] self.interface1 = MainDataInterface1(self) self.interface2 = MainDataInterface2(self) self.data_changed = MrSignal() def _update_keys(self): self.data_keys.clear() self.data_keys.extend(list(self.data.keys())) self.data_changed.emit(list(self.data_keys)) def rename(self, arg1, new_name_): if isinstance(arg1, int): old_name = self.data_keys[arg1] else: old_name = arg1 old_data = OrderedDict(self.data) self.data.clear() _data = self.data for key, data in iteritems(old_data): if old_name == key: key = new_name_ _data[key] = data self.data_changed.block() self._update_keys() self.data_changed.unblock() self.data_changed.emit(('rename', old_name, new_name_)) def add(self, name=None): name = new_name(self.data, name) self.data[name] = self._new_data() self._update_keys() self.interface2.set_index(len(self.data) - 1) def insert(self, index, name=None, data=None): if name in self.data: name = new_name(self.data, name) old_data = OrderedDict(self.data) print('insert', name) self.data.clear() _data = self.data if data is None: _new_data = self._new_data() else: _new_data = data found_data = False i = 0 for key, data in iteritems(old_data): if i == index: _data[name] = _new_data found_data = True _data[key] = data i += 1 if not found_data: _data[name] = _new_data self.data_changed.block() self._update_keys() self.data_changed.unblock() self.data_changed.emit(('insert', index, name)) self.interface2.set_index(index) def delete(self, index): old_data = OrderedDict(self.data) self.data.clear() _data = self.data index_ = index i = -1 for key, data in iteritems(old_data): i += 1 if i == index: continue _data[key] = data if index >= len(self.data): index -= 1 self.data_changed.block() self._update_keys() self.data_changed.unblock() self.data_changed.emit(('delete', index_)) self.interface2.set_index(index) def up(self, index): if index == 0: return False return self._move(index, index - 1) def down(self, index): if index == len(self.data) - 1: return False return self._move(index, index + 1) def _move(self, old_index, new_index): old_data = OrderedDict(self.data) old_keys = list(old_data.keys()) self.data.clear() _data = self.data key_old = old_keys[old_index] data_old = old_data[key_old] key_new = old_keys[new_index] data_new = old_data[key_new] i = -1 for key, data in iteritems(old_data): i += 1 if i == new_index: _data[key_old] = data_old continue elif i == old_index: _data[key_new] = data_new continue _data[key] = data self._update_keys() self.interface2.set_index(new_index) return True @staticmethod def columns(): return 1 def _new_data(self): return np.zeros((1, self.columns()), dtype=np.float64) def __len__(self): return len(self.data) def serialize(self): result = [] for key, data in iteritems(self.data): result.append((key, data.tostring())) return result def load(self, data): tmp = self._new_data() dtype = tmp.dtype cols = tmp.shape[1] for data_ in data: key, _data = data_ tmp = np.fromstring(_data, dtype=dtype) self.data[key] = np.array(tmp.reshape((tmp.size // cols, cols))) self._update_keys() def clear(self): self.data.clear() self._update_keys() def ids(self): return list(self.data_keys)
class TableDataModel(QtCore.QAbstractTableModel): def __init__(self, *args): super(TableDataModel, self).__init__(*args) # self._headers = None self._data = None self._editable_columns = None """:type: set""" self.set_data = MrSignal() def setup_data(self, data): try: assert isinstance(data, TableDataList) except AssertionError: print(data.__class__) raise self._data = data # self._headers = list(data.headers) self._editable_columns = self._data.editable_columns() self.update_all() def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): if self._data is not None and role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: return self._data.headers[section] else: return section + 1 return None def rowCount(self, index=QtCore.QModelIndex()): try: return len(self._data) except TypeError: return 0 def columnCount(self, index=QtCore.QModelIndex()): try: return len(self._data.headers) except (TypeError, AttributeError): return 0 def flags(self, index): if int(index.column()) in self._editable_columns: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable else: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def data(self, index, role=QtCore.Qt.DisplayRole): if self._data is None or not index.isValid(): return None if role == QtCore.Qt.EditRole: row = index.row() col = index.column() data_ = self._data[row] try: data = data_.edit_role(col) except AttributeError: data = data_[col] except TypeError: data = None if data is None: return '' return str(data) elif role == QtCore.Qt.DisplayRole: row = index.row() col = index.column() data_ = self._data[row] try: data = data_[col] except (TypeError, IndexError): data = None if data is None: return '' if isinstance(data, list) and len(data) > 0 and isinstance( data[0], float): return str([round(i, 6) for i in data]) return str(data) return None def setData(self, index, value, role=QtCore.Qt.DisplayRole): if self._data is None: return False row = index.row() col = index.column() self.set_data.emit((row, col), str(value), role) return True def update_all(self): try: self._editable_columns = self._data.editable_columns() except AttributeError: pass self.layoutChanged.emit() top_left = self.index(0, 0) bot_right = self.index(self.rowCount() - 1, self.columnCount() - 1) self.dataChanged.emit(top_left, bot_right)
class TableDataWidget(QtWidgets.QWidget): def __init__(self, *args): super(TableDataWidget, self).__init__(*args) self.ui = Ui_Form() self.ui.setupUi(self) self.tableView_list = DataTable.wrap_obj(self.ui.tableView_list) self.tableView_data = DataTable.wrap_obj(self.ui.tableView_data) self.tableView_list.set_editable_columns([0, 1]) self.tableView_data.set_editable_columns([i for i in range(100)]) self.ui.pushButton_add.clicked.connect(self._add) self.ui.pushButton_insert.clicked.connect(self._insert) self.ui.pushButton_delete.clicked.connect(self._delete) self.ui.pushButton_up.clicked.connect(self._up) self.ui.pushButton_down.clicked.connect(self._down) self.ui.pushButton_open.clicked.connect(self._open) self.main_data = MainData() """:type: fem.utilities.table_data_widget.model.MainData""" self.config = Configuration() self.tableView_list.setup_data(self.main_data.headers_1, self.main_data.interface1) self.tableView_data.setup_data(self.main_data.headers_2, self.main_data.interface2) self.tableView_list.selection_changed.connect(self._selection_changed) self.tableView_list.set_data_signal.connect(self._set_data_1) self.tableView_data.set_data_signal.connect(self._set_data_2) self.tableView_list.paste.connect(self._paste_1) self.tableView_data.paste.connect(self._paste_2) self.tableView_list.undo.connect(self._undo) self.tableView_list.redo.connect(self._redo) self.tableView_data.undo.connect(self._undo) self.tableView_data.redo.connect(self._redo) self.data_changed = MrSignal() self.main_data.data_changed.connect(self._data_changed) def _data_changed(self, *args): self.data_changed.emit(*args) def get_data(self): return self.main_data.data def clear_data(self): self.main_data.data.clear() def set_main_data(self, main_data): self.main_data.data_changed.disconnect_all() self.main_data = main_data """:type: fem.utilities.table_data_widget.model.MainData""" self.tableView_list.setup_data(self.main_data.headers_1, self.main_data.interface1) self.tableView_data.setup_data(self.main_data.headers_2, self.main_data.interface2) self.main_data.data_changed.connect(self._data_changed) def _open(self, *args): filename = getopenfilename( caption='Choose Data File', directory='', filter_=r'.txt (*.txt); .csv (*.csv)' ) if filename in ('', None): return Action = Actions.ImportAction action_data = Action.ActionDataCls(filename) action = Action(self.main_data, action_data, self.config) command = Commands.ImportCommand(self, action) self.config.dispatch((action, action_data, command)) def _undo(self, *args): self.config.dispatch('Undo') def _redo(self, *args): self.config.dispatch('Redo') def _add(self, *args): Action = Actions.AddAction action_data = Action.ActionDataCls(self.tableView_list.current_row()) action = Action(self.main_data, action_data) command = Commands.AddCommand(self, action) self.config.dispatch((action, action_data, command)) def _insert(self, *args): Action = Actions.InsertAction action_data = Action.ActionDataCls(self.tableView_list.current_row()) action = Action(self.main_data, action_data) command = Commands.InsertCommand(self, action) self.config.dispatch((action, action_data, command)) def _delete(self, *args): Action = Actions.RemoveAction action_data = Action.ActionDataCls(self.tableView_list.current_row()) action = Action(self.main_data, action_data) command = Commands.RemoveCommand(self, action) self.config.dispatch((action, action_data, command)) def _set_data_1(self, index, value, role): Action = Actions.SetDataAction table = self.tableView_list index = (table.current_row(), table.current_column()) action_data = Action.ActionDataCls(index, value) action = Action(self.main_data.interface1, action_data) command = Commands.SetDataCommand(self, action) self.config.dispatch((action, action_data, command)) return command.command_result def _set_data_2(self, index, value, role): Action = Actions.SetDataAction table = self.tableView_data index = (table.current_row(), table.current_column()) action_data = Action.ActionDataCls(index, value) action = Action(self.main_data.interface2, action_data) command = Commands.SetDataCommand(self, action) self.config.dispatch((action, action_data, command)) return command.command_result def _up(self, *args): Action = Actions.UpAction table = self.tableView_list action_data = Action.ActionDataCls(table.current_row()) action = Action(self.main_data, action_data) command = Commands.UpCommand(self, action) self.config.dispatch((action, action_data, command)) def _down(self, *args): Action = Actions.DownAction table = self.tableView_list action_data = Action.ActionDataCls(table.current_row()) action = Action(self.main_data, action_data) command = Commands.DownCommand(self, action) self.config.dispatch((action, action_data, command)) def _paste_1(self, selection, data): Action = Actions.PasteAction table = self.tableView_list action_data = Action.ActionDataCls(selection, data) action = Action(self.main_data.interface1, action_data) command = Commands.PasteCommand(self, action, table) self.config.dispatch((action, action_data, command)) def _paste_2(self, selection, data): Action = Actions.PasteAction table = self.tableView_data action_data = Action.ActionDataCls(selection, data) action = Action(self.main_data.interface2, action_data) command = Commands.PasteCommand(self, action, table) self.config.dispatch((action, action_data, command)) def update_all(self): self.tableView_list.update_all() self.tableView_data.update_all() def _selection_changed(self, row, col): self.main_data.interface2.set_index(row) self.tableView_data.update_all()
class OptionsLineEditDelegate(AbstractLineEditDelegate): def __init__(self, parent, data, options_data, dialog_title): """ :param parent: QtWidgets.QLineEdit to whom the delegate belongs to :type parent: QtWidgets.QLineEdit :param data: AbstractData to whom the delegate sends _main_data to :type data: AbstractData """ AbstractLineEditDelegate.__init__(self, parent, data) self.setObjectName(str(parent.objectName()) + "_delegate") self._dialog_title = dialog_title self._dialog = None self._options_data = options_data self.update_value = MrSignal() self._return_list = False if hasattr(self._options_data, 'return_data_list'): if self._options_data.return_data_list is True: self._return_list = True def execute(self, geometry=None): if self._enabled is False: return self._active = True self._dialog = OptionsDialog(self._dialog_title, parent=self._parent) self._dialog.skip_click = True self._dialog.finished.connect(self._update_value) options_data = self._options_data() data = options_data['_main_data']() headers = options_data['headers'] widths = options_data['widths'] initial_values = options_data['initial_values']() self._dialog.set_data(data) self._dialog.set_up_data_lists(headers, widths) self._dialog.initial_values(initial_values) self._dialog.align_to(self._parent) self._dialog.setFocus() self._dialog.exec_() def delegate(self): return self._dialog def done_editing(self, obj=None): return 0 def _update_value(self, *args): try: if not self._return_list: value = self._dialog.return_data if value is None: return self.update_value.emit(str(value)) else: self.update_value.emit(map(str, self._dialog.return_data_list)) except AttributeError: pass def hide(self): self._active = False try: self._dialog.hide() except AttributeError: pass def text(self): try: if not self._return_list: value = self._dialog.return_data if value is None: return "" return str(value) else: list_ = self._dialog.return_data_list return "/".join(map(str, list_)) except AttributeError: return "" def parent_text(self): return self._parent.text()
class TableNumpyDataList(AbstractTableDataList): CheckDataType = None DefaultDataType = None def __init__(self, data_id=None): self._data_id = data_id self.dtype = self.DefaultDataType.dtype self.blank_data = np.zeros(1, dtype=self.dtype) self.data = np.zeros(0, dtype=self.dtype) self._headers = list( self.data.dtype.names)[:self.DefaultDataType.columns()] self._ids = [] self.list_changed = MrSignal() def clear(self): self.data.resize(0) def get_data(self): return self.data.tolist() def load_data(self, data): np.copyto(self.data, data) def add(self, data=None): self.data.resize(self.data.size + 1, refcheck=False) if data is not None: self.data[-1] = data self.list_changed.emit() return self.data[-1] def remove(self, index): if isinstance(index, (list, tuple)): i1 = index[0] i2 = index[1] else: i1 = index i2 = index indices = list(range(i1, i2 + 1)) tmp = [] for i in indices: tmp.append(tuple(self.data[i])) self.data = np.delete(self.data, indices) self.list_changed.emit() return tmp def insert(self, index, data=None): if data is not None: assert isinstance(data, tuple) try: if isinstance(data[0], tuple): return self._insert_multiple(index, data) except IndexError: data = None if index < 0: index = 0 if index >= self.data.size: return None if data is None: data = tuple(self.blank_data[0]) self.data = np.insert(self.data, index, data) self.list_changed.emit() return self.data[index] def editable_columns(self): return set(range(len(self.headers))) def _insert_multiple(self, index, data): if index < 0: index = 0 if index >= len(self.data) + 1: raise IndexError('%d' % index) self.list_changed.block() for data_ in data: self.data = np.insert(self.data, index, data_) self.list_changed.unblock() self.list_changed.emit() return data def serialize(self): data_i = self.DefaultDataType(self, 0) for i in range(self.data.shape[0]): data_i.index = i data_i.serialize() return base64.b64encode(compress(self.data.tobytes())).decode() def load(self, data): try: self.data = np.fromstring(decompress( base64.b64decode(data.encode())), dtype=self.dtype) except ValueError: print('get rid of this') return data_i = self.DefaultDataType(self, 0) for i in range(self.data.shape[0]): data_i.index = i data_i.load(self.data[i]) # np.copyto(self._data, np.fromstring(base64.b64decode(data.encode()), dtype=self.dtype)) def __getitem__(self, index): if isinstance(index, str): index = self.ids().index(index) return self.DefaultDataType(self, index) def set_data(self, index, value): row, column = index _data = self.DefaultDataType(self, row) try: old_value = _data[column] _data[column] = value new_value = _data[column] if old_value != new_value: return True, old_value, new_value else: return False, None, None except (MyExceptions.IndexError, MyExceptions.ValueError): return False, None, None @show_caller def __setitem__(self, index, data): assert isinstance(data, tuple) self.data[index] = data def id_exists(self, id_): data_i = self.DefaultDataType(self, 0) for i in range(self.data.shape[0]): data_i.index = i if data_i.id == id_: return True return False def subdata(self, index): return None def has_subdata(self): return None def find_index(self, data_id): assert isinstance(data_id, str) data_i = self.DefaultDataType(self, 0) for i in range(self.data.shape[0]): data_i.index = i if data_i.id == data_id: return i return -1 def ids(self): data_i = self.DefaultDataType(self, 0) ids_ = [] for i in range(self.data.shape[0]): data_i.index = i ids_.append(data_i.id) return ids_ def _move(self, i1, i2): _data_i1 = tuple(self.data[i1]) _data_i2 = tuple(self.data[i2]) self.data[i1], self.data[i2] = _data_i2, _data_i1 del self._ids[:] self.list_changed.emit() def shape(self): return self.data.shape[0], self.DefaultDataType.columns() @property def size(self): return self.__len__() def __len__(self): return self.data.shape[0] def get_index(self, data): pass def get_id(self): pass def up(self, index): pass def down(self, index): pass def insert_multiple(self, index, data): pass def validate(self, *args): pass @property def headers(self): return self._headers def remove_multiple(self, count): pass def add_multiple(self, count, data=None): pass
class TableDictList(AbstractTableDataList): CheckDataType = DummyTableData DefaultDataType = DummyTableData def __init__(self, data_id=None): self.data = {} """:type: dict[DummyTableData]""" self._headers = list(self.DefaultDataType.headers) self._data_id = data_id self.list_changed = MrSignal() self._ids = [] def clear(self): self.data.clear() del self._ids[:] def get_id(self): return self._data_id @property def headers(self): return self._headers def get_data(self): return list(self.data.values()) def load_data(self, data): self.data.clear() for _data in data: self.data[_data.id] = data self._update_ids() def add(self, *data): tmp = self.DefaultDataType() tmp.register_model(self.model) if len(data) > 0: tmp.load(data) self.data[tmp.id] = tmp self.list_changed.emit() del self._ids[:] return tmp def remove(self, index): try: tmp = self.data[index] del self.data[index] except MyExceptions.IndexError: return None self.list_changed.emit() return tmp def add_multiple(self, count, data=None): raise NotImplementedError result = [] self.list_changed.block() if isinstance(data, (list, tuple)): assert count == len(data) for data_i in data: result.append(self.add(data_i)) else: for i in range(count): result.append(self.add()) self.list_changed.unblock() if len(result) > 0: del self._ids[:] self.list_changed.emit() return result def remove_multiple(self, count): raise NotImplementedError result = [] self.list_changed.block() data_len = self.shape()[0] last_i = data_len for i in range(count): last_i -= 1 try: result.append(self.remove(last_i)[0]) except IndexError: pass self.list_changed.unblock() if len(result) > 0: del self._ids[:] self.list_changed.emit() return result def insert(self, index, *data): if len(data) > 1: tmp = self.DefaultDataType(*data) else: tmp = self.DefaultDataType() if index < 0: index = 0 try: self.data.insert(index, tmp) del self._ids[:] self.list_changed.emit() return tmp except MyExceptions.IndexError: return None def insert_multiple(self, index, data): if index < 0: index = 0 if index >= len(self.data) + 1: raise IndexError('%d' % index) self.list_changed.block() result = [] for data_ in data: result_ = self.data.insert(index, data_) if result_ is not None: result.append(result_) self.list_changed.unblock() if len(result) > 0: del self._ids[:] self.list_changed.emit() return result def shape(self): return len(self.data), len(self.headers) def editable_columns(self): return set(range(len(self.headers))) def set_data(self, index, value): row, column = index try: old_value = self.data[row][column] self.data[row][column] = value new_value = self.data[row][column] if old_value != new_value: del self._ids[:] print('data is valid 2') return True, old_value, new_value else: print('old and new values equal') return False, None, None except (MyExceptions.IndexError, MyExceptions.ValueError): print('index or value error') print(self.data[row]) return False, None, None def validate(self, *args): raise NotImplementedError def serialize(self): data = [] for data_i in self.data: data.append(data_i.serialize()) return data def load(self, data): self.list_changed.block() for data_i in data: self.add(data_i) self.list_changed.unblock() del self._ids[:] # self._update_ids() # make sure to update other data if needed def _move(self, i1, i2): self.data[i1], self.data[i2] = self.data[i2], self.data[i1] del self._ids[:] self.list_changed.emit() def up(self, index): if index <= 0 or index >= len(self.data): return False i1 = index i2 = index - 1 self._move(i1, i2) return True def down(self, index): if index < 0 or index >= len(self.data) - 1: return False i1 = index i2 = index + 1 self._move(i1, i2) return True def __len__(self): return len(self.data) def __getitem__(self, index): if isinstance(index, str): if index == '': return None index = self.ids().index(index) return self.data[index] @show_caller def __setitem__(self, index, data): assert isinstance(data, self.CheckDataType) # TODO: what to do here? self.data[index] = data def id_exists(self, id_): for data_i in self.data: if data_i.id == id_: return True return False def subdata(self, index): row, column = index try: return self.data[row].subdata(column) except (AttributeError, IndexError): return None def has_subdata(self): try: data = self.data[0] except IndexError: return None except KeyError: raise KeyError(self._data_id) for i in range(len(data)): try: subdata = data.subdata(i) if subdata is not None: return subdata except NotImplementedError: pass return None def find_index(self, data_id): if isinstance(data_id, str): data = self.data for i in range(len(data)): if data[i].id == data_id: return i elif isinstance(data_id, self.CheckDataType): data = self.data for i in range(len(data)): if data_id is data[i]: return i return -1 def get_index(self, data): return data def ids(self): if len(self._ids) == 0: self._update_ids() return list(self._ids) def _update_ids(self): del self._ids[:] _ids = self._ids for data in self.data: _ids.append(data.id) @property def size(self): return len(self.data)
class RecursiveTable(QtWidgets.QWidget): def __init__(self, parent=None, main_data=None, *args): super(RecursiveTable, self).__init__(parent, *args) # FIXME: main_data should be renamed to table_data since it is confusing with app main_data self.main_data = main_data self.config = Configuration(self.main_data.get_id()) self.table = EmptyTable(self) self.dispatcher = self.config.dispatcher self.dispatcher.main_window = self self.dispatcher.table = self.table self.dispatcher.get_model = self.main_data self.Actions = self.config.Actions self.Commands = self.config.Commands self.Actions.set_main_data(self.main_data) self.Commands.set_main_window(self) self.table.pushButton_add.clicked.connect(self._add) self.table.pushButton_insert.clicked.connect(self._insert) self.table.pushButton_delete.clicked.connect(self._delete) self.table.pushButton_up.clicked.connect(self._up) self.table.pushButton_down.clicked.connect(self._down) self.table_model = TableDataModel() self.table.set_model(self.table_model) self.table.set_data.connect(self._set_data) self.table.paste.connect(self._paste) self.table.set_rows.connect(self._set_rows) self.table.undo.connect(self._undo) self.table.redo.connect(self._redo) self.table_model.setup_data(self.main_data) self._splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) self._splitter.addWidget(self.table) self.setLayout(QtWidgets.QHBoxLayout()) self.layout().addWidget(self._splitter) self.table.selection_changed.connect(self._selection_changed) self.table.data_changed.connect(self._data_changed) self.subtable = None """:type: RecursiveTable""" self.data_changed = MrSignal() #################################################################################################################### def finalize(self): self.main_data = None self.config = None try: self.table.setParent(None) except RuntimeError: pass self.table = None self.dispatcher = None self.Actions = None self.Commands = None try: self.table_model.setParent(None) except RuntimeError: pass self.table_model = None try: self._splitter.setParent(None) except RuntimeError: pass self._splitter = None if self.subtable is not None: self.clear_data() self.subtable = None self.data_changed.disconnect_all() def _data_changed(self, *args): self.data_changed.emit() def _hide_subtable(self): if self.subtable is not None: # self.subtable.setParent(self) self.subtable.hide() def _show_subtable(self): if self.subtable is not None: self._splitter.addWidget(self.subtable) self.subtable.show() def _subtable(self, subdata): if subdata is not None: if self.subtable is None: self.subtable = RecursiveTable(parent=self, main_data=subdata) self.subtable.layout().setContentsMargins(QtCore.QMargins(0, 0, 0, 0)) self.dispatcher.add_child(self.subtable.dispatcher) self._splitter.addWidget(self.subtable) self.subtable.hide() # noinspection PyProtectedMember self.subtable.data_changed.connect(self._data_changed) self.subtable.set_main_data(subdata) return self.subtable def force_update(self, index=None): if index is None: index = self._index() self._selection_changed(index) #################################################################################################################### def serialize(self): data = [] for i in range(len(self.main_data)): data.append(self.main_data[i].serialize()) def load(self, data): for i in range(len(data)): self.main_data.add().load(data[i]) def clear(self): self.main_data.clear() self.update_all() def set_main_data(self, main_data): self.main_data = main_data try: self.dispatcher.get_model = main_data except AttributeError: print(self) raise self.Actions.set_main_data(self.main_data) self.table_model.setup_data(self.main_data) self.table.lineEdit_rows.setText(str(self.main_data.shape()[0])) self._selection_changed() self._update_all() def _update_all(self): self.table_model.update_all() self.table.lineEdit_rows.setText(str(self.table.row_count())) def update_all(self): self._update_all() try: self.subtable.update_all() except AttributeError: pass #################################################################################################################### def _selection_changed(self, index=None): if self.subtable is None: self._subtable(self.main_data.has_subdata()) subdata = self._subdata(index) subtable = self._subtable(subdata) if None in (subtable, subdata): self._hide_subtable() else: self._show_subtable() #################################################################################################################### def _subdata(self, index=None): if index is None: index = self._index() return self.main_data.subdata(index) def _index(self): return self.table.current_index() #################################################################################################################### def _add(self): self.dispatcher.dispatch(('Add', ())) def _insert(self): self.dispatcher.dispatch(('Insert', (self._index(),))) def _delete(self): self.dispatcher.dispatch(('Remove', (self.table.selection(),))) def _up(self): self.dispatcher.dispatch(('Up', (self._index(),))) def _down(self): self.dispatcher.dispatch(('Down', (self._index(),))) def _set_data(self, enter_down, index, value, role): self.dispatcher.dispatch(('SetData', (index, value, enter_down))) def _paste(self, selection, data): self.dispatcher.dispatch(('Paste', (selection, data))) def _set_rows(self, rows): if rows < 0: self.table.lineEdit_rows.setText(str(self.table.table.model().rowCount())) return self.dispatcher.dispatch(('SetRows', (rows,))) def _undo(self, *args): self.dispatcher.dispatch('Undo') def _redo(self, *args): self.dispatcher.dispatch('Redo') #################################################################################################################### # @show_stack_trace def keyPressEvent(self, event): super(RecursiveTable, self).keyPressEvent(event) if event.isAccepted(): return if event.matches(QtGui.QKeySequence.Undo): event.accept() self._undo() elif event.matches(QtGui.QKeySequence.Redo): event.accept() self._redo() def clear_data(self): self.dispatcher.clear_children() if self.subtable is not None: self.subtable.main_data = None self.subtable.hide()
class GroupsDock(QtWidgets.QDockWidget): def __init__(self, main_window): super(GroupsDock, self).__init__(main_window) self.main_window = main_window self.ui = Ui_DockWidget() self.ui.setupUi(self) self._groups_table_model = GroupsTableModel() self.ui.tableView_groups.setModel(self._groups_table_model) self._groups_selection_model = self.ui.tableView_groups.selectionModel( ) """:type: QtGui.QItemSelectionModel""" self._groups_selection_model.selectionChanged.connect( self._groups_selection_changed) self.row_changed = MrSignal() self.column_changed = MrSignal() self.selection_changed = MrSignal() self._old_row = -1 self._old_column = -1 self.ui.pushButton_add_group.clicked.connect(self.add_group) self.ui.pushButton_remove_group.clicked.connect(self.remove_group) self.ui.pushButton_add_member.clicked.connect(self.add_members) self.ui.pushButton_remove_member.clicked.connect(self.remove_members) self._selection = PickedSelection() self._selection.data_changed.connect(self._picked_data_changed) self.setWindowTitle('Plot/Erase Groups') def add_group(self, group_name=None, group_members=None): if group_name in (False, None): group_name = fem_groups.new_name() group = fem_groups.add_group(group_name) if group_members is not None: group.set_data(group_members) self._groups_table_model.update_all() def remove_group(self, group): if isinstance(group, int): group = fem_groups.get_group_by_index(group) elif isinstance(group, str): group = fem_groups.get_group(group) else: raise TypeError( 'GroupsDock.remove_group: group is not an int or string! %s' % str(group)) fem_groups.remove_group(group.group_name) self._groups_table_model.update_all() def add_members(self): group = self._current_group() if group.group_name == 'Default': return group.add_data(str(self.ui.lineEdit_selection.text())) self._update_members_list() def remove_members(self): group = self._current_group() if group.group_name == 'Default': return group.remove_data(str(self.ui.lineEdit_selection.text())) self._update_members_list() def show_and_register(self): self.show() if self._old_row == -1: self._groups_row_changed(0) from fem.gui.vtk_widget.vtk_graphics.picking import PickingManager picking_manager = PickingManager.instance() picking_manager.register_selection(self._selection) self.main_window.show_dock(self) def _groups_selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous:QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True self._groups_row_changed(new_row) if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit(new_row, new_column) def _groups_row_changed(self, row): new_group = fem_groups.get_group_by_index(row) self.ui.plainTextEdit_members.setPlainText(new_group.to_str()) def _picked_data_changed(self, *args): self.ui.lineEdit_selection.setText(self._selection.to_str()) def _current_group(self): row = self._groups_selection_model.currentIndex().row() return fem_groups.get_group_by_index(row) def _update_members_list(self): group = self._current_group() self.ui.plainTextEdit_members.setPlainText(group.to_str()) def update_all(self): self._groups_table_model.update_all()
class TableDataList(AbstractTableDataList): CheckDataType = DummyTableData DefaultDataType = DummyTableData def __init__(self, data_id=None): self.data = [] """:type: list[DummyTableData]""" self._headers = list(self.DefaultDataType.headers) self._formats = list(self.DefaultDataType.formats) self._setters = list(self.DefaultDataType.setters) self._data_id = data_id self.list_changed = MrSignal() self._ids = [] def clear(self): try: self.data.clear() except AttributeError: del self.data[:] del self._ids[:] def get_id(self): return self._data_id @property def headers(self): return self._headers @property def formats(self): return self._formats @property def setters(self): return self._setters def get_data(self): return list(self.data) def load_data(self, data): del self.data[:] self.data.extend(list(data)) self._update_ids() def add(self, *data): tmp = self.DefaultDataType() # object needs to be added to data first for logging purposes self.data.append(tmp) if len(data) > 0: tmp.load(data) self.list_changed.emit() del self._ids[:] def remove(self, index): try: tmp = self.data[index] del self.data[index] except MyExceptions.IndexError: return None self.list_changed.emit() def remove_multiple(self, indices): offset = 1 for i in range(1, len(indices)): indices[i] -= offset offset += 1 for i in indices: self.remove(i) def insert(self, index, *data): tmp = self.DefaultDataType() if index < 0: index = 0 try: self.data.insert(index, tmp) if len(data) > 0: tmp.load(data) del self._ids[:] self.list_changed.emit() except MyExceptions.IndexError: pass def insert_multiple(self, indices): """ :param indices: :type indices: list[int] :return: """ if len(indices) == 0: return offset = 1 for i in range(1, len(indices)): indices[i] += offset offset += 1 for i in indices: self.insert(i) def shape(self): return len(self.data), len(self.headers) def editable_columns(self): return set(range(len(self.headers))) def set_data(self, index, value): row, column = index try: data = self.data[row] except MyExceptions.IndexError: print('index error') return getattr(data, self._setters[column])(value) def validate(self, *args): raise NotImplementedError def serialize(self): data = [] for data_i in self.data: data.append(data_i.serialize()) return data def load(self, data): self.list_changed.block() for data_i in data: self.add(data_i) self.list_changed.unblock() del self._ids[:] # self._update_ids() # make sure to update other data if needed def _move(self, i1, i2): self.data[i1], self.data[i2] = self.data[i2], self.data[i1] del self._ids[:] self.list_changed.emit() def up(self, index): if index <= 0 or index >= len(self.data): return False i1 = index i2 = index - 1 self._move(i1, i2) return True def down(self, index): if index < 0 or index >= len(self.data) - 1: return False i1 = index i2 = index + 1 self._move(i1, i2) return True def __len__(self): return len(self.data) def __getitem__(self, index): if isinstance(index, str): if index == '': return None index = self.ids().index(index) return self.data[index] @show_caller def __setitem__(self, index, data): assert isinstance(data, self.CheckDataType) # TODO: what to do here? self.data[index] = data def id_exists(self, id_): for data_i in self.data: if data_i.id == id_: return True return False def subdata(self, index): row, column = index try: return self.data[row].subdata(column) except (AttributeError, IndexError): return None def has_subdata(self): try: data = self.data[0] except IndexError: return None except KeyError: raise KeyError(self._data_id) for i in range(len(data)): try: subdata = data.subdata(i) if subdata is not None: return subdata except NotImplementedError: pass return None def find_index(self, data_id): if isinstance(data_id, str): data = self.data for i in range(len(data)): if data[i].id == data_id: return i elif isinstance(data_id, self.CheckDataType): data = self.data for i in range(len(data)): if data_id is data[i]: return i return -1 def get_index(self, data): return data def ids(self): if len(self._ids) == 0: self._update_ids() return list(self._ids) def _update_ids(self): del self._ids[:] _ids = self._ids for data in self.data: _ids.append(data.id) @property def size(self): return len(self.data) def get_formatted_data_by_index(self, index): row, col = index return self._formats[col] % self.data[row][col] def get_edit_data_by_index(self, index): row, col = index return str(self.data[row][col]) def resize(self, new_size): data_len = len(self.data) if data_len == new_size: return if new_size > data_len: diff = new_size - data_len for i in range(diff): self.add() else: diff = data_len - new_size last_i = data_len - 1 for i in range(diff): self.remove(last_i) last_i -= 1
class PolyPicker(vtkCameraManipulator): def __init__(self): vtkCameraManipulator.__init__(self) self._start_position = [0, 0] self._end_position = [0, 0] self._pixel_array = vtk.vtkUnsignedCharArray() self._left_button_down = False self._ctrl_left_button_down = False self._right_button_down = False self._middle_button_down = False self._down_pos = None self._up_pos = None self._point_list = [] self.renderer = None self.iren = None #self.reset_polygon() self._points = 0 self.polygon = vtk.vtkPolygon() self.poly_data = vtk.vtkPolyData() self.poly_points = vtk.vtkPoints() self.poly_data.SetPoints(self.poly_points) self.cell_array = vtk.vtkCellArray() self.cell_array.InsertNextCell(self.polygon) self.cell_array.Squeeze() self.poly_data.SetPolys(self.cell_array) self.done_picking = MrSignal() self._picking_active = False self.poly_pick_filter = PolyPickFilter() self.poly_pick_filter.set_poly_pick_data(self.poly_data) self.vtk_graphics = VTKGraphics.instance() from .picking_manager import PickingManager self.picking_manager = PickingManager.instance() def set_input_connection(self, port): self.poly_pick_filter.SetInputConnection(port) def reset_polygon(self): self._point_list = [] self._points = 0 self.poly_points.Reset() self.polygon.GetPointIds().Reset() def begin_picking(self, renderer, interactor): self.reset_polygon() self.renderer = renderer self.iren = interactor self.poly_pick_filter.set_renderer(renderer) self.ren_win = interactor.GetRenderWindow() self.ren_win_size = self.ren_win.GetSize() self._pixel_array.Reset() self._pixel_array.SetNumberOfComponents(4) self._pixel_array.SetNumberOfTuples(self.ren_win_size[0] * self.ren_win_size[1]) self.ren_win.GetRGBACharPixelData(0, 0, self.ren_win_size[0] - 1, self.ren_win_size[1] - 1, 1, self._pixel_array) pos = interactor.GetEventPosition() self._first_point = pos self._last_point = pos self._points = 0 self._picking_active = True def self_intersecting(self): def on_segment(p, r, q): max0 = max(p[0], r[0]) min0 = min(p[0], r[0]) max1 = max(p[1], r[1]) min1 = min(p[1], r[1]) if min0 <= q[0] <= max0 and min1 <= q[1] <= max1: return True else: return False def orientation(p, r, q): val = int((q[1] - p[1])*(r[0] - q[0]) - (q[0] - p[0])*(r[1] - q[1])) if val == 0: return 0 if val > 0: return 1 else: return 2 def does_intersect(p1, q1, p2, q2): if p1 == p2 or p1 == q2 or q1 == p2 or q1 == q2: return False o1 = orientation(p1, q1, p2) o2 = orientation(p1, q1, q2) o3 = orientation(p2, q2, p1) o4 = orientation(p2, q2, q1) if o1 != o2 and o3 != o4: return True if o1 == 0 and on_segment(p1, q1, p2): return True if o2 == 0 and on_segment(p1, q1, q2): return True if o3 == 0 and on_segment(p2, q2, p1): return True if o4 == 0 and on_segment(p2, q2, q1): return True return False pl = self._point_list points = len(pl) if points <= 2: return False e1 = [pl[0], pl[points-1]] e2 = [pl[points-2], pl[points-1]] for i in range(1, points-1): p1 = pl[i] p2 = pl[i-1] if does_intersect(p1, p2, e1[0], e1[1]) or does_intersect(p1, p2, e2[0], e2[1]): return True return False def add_point(self, interactor, renderer): def distance(p1, p2): sum = (p1[0] - p2[0])**2 sum += (p1[1] - p2[1])**2 return sum ** 0.5 pos = interactor.GetEventPosition() if self._points > 2 and (distance(pos, self._last_point) <= 5 or distance(pos, self._first_point) <= 5): self.end_picking(self.renderer, interactor) return True self._point_list.append(pos) if self.self_intersecting(): self._point_list.pop() return False world_point = display_to_world(pos, renderer, .001) self.poly_points.InsertNextPoint(world_point[:3]) self._last_point = pos self.polygon.GetPointIds().InsertNextId(self._points) self.polygon.Modified() self._points += 1 return False def end_picking(self, renderer, interactor): self.something_picked() self._picking_active = False self.done_picking.emit() def get_picking_frustums(self): return [] def something_picked(self): self.poly_points.Modified() self.polygon.Modified() self.poly_data.SetPoints(self.poly_points) self.cell_array.Reset() self.cell_array.InsertNextCell(self.polygon) self.cell_array.Squeeze() self.poly_data.SetPolys(self.cell_array) self.poly_data.Modified() self.poly_pick_filter.set_poly_pick_data(self.poly_data) self.poly_pick_filter.Modified() self.poly_pick_filter.Update() global_ids = self.poly_pick_filter.GetOutputDataObject(0).GetCellData().GetArray("global_ids") if global_ids is None: self.picking_manager.set_picked_data([]) return get_value = global_ids.GetValue data = [] for i in range(global_ids.GetNumberOfTuples()): data.append(get_value(i)) self.picking_manager.set_picked_data(data) def _redraw_picking_box(self, interactor): tmp_array = vtk.vtkUnsignedCharArray() tmp_array.DeepCopy(self._pixel_array) min = [0, 0] max = [0, 0] size = self.ren_win_size if self._start_position[0] <= self._end_position[0]: min[0] = self._start_position[0] else: min[0] = self._end_position[0] if min[0] < 0: min[0] = 0 if min[0] >= size[0]: min[0] = size[0] - 1 if self._start_position[1] <= self._end_position[1]: min[1] = self._start_position[1] else: min[1] = self._end_position[1] if min[1] < 0: min[1] = 0 if min[1] >= size[1]: min[1] = size[1] - 1 if self._end_position[0] > self._start_position[0]: max[0] = self._end_position[0] else: max[0] = self._start_position[0] if max[0] < 0: max[0] = 0 if max[0] >= size[0]: max[0] = size[0] - 1 if self._end_position[1] > self._start_position[1]: max[1] = self._end_position[1] else: max[1] = self._start_position[1] if max[1] < 0: max[1] = 0 if max[1] >= size[1]: max[1] = size[1] - 1 point_list = self._point_list[:] point_list.append(self._end_position) my_int = int for i in range(1, len(point_list)): p1 = point_list[i-1] p2 = point_list[i] points = get_line_pixels(p1, p2) for p in points: index1 = p[1] * size[0] + p[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) p1 = list(point_list[0]) p2 = list(point_list[-1]) points = get_line_pixels(p1, p2) for p in points: index1 = p[1] * size[0] + p[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) p1[1] += 1 p2[1] += 1 points = get_line_pixels(p1, p2) for p in points: index1 = p[1] * size[0] + p[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) p1[1] -= 2 p2[1] -= 2 points = get_line_pixels(p1, p2) for p in points: index1 = p[1] * size[0] + p[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) p1[1] += 1 point_list = [[p1[0] - 5, p1[1] + 5], [p1[0] + 5, p1[1] + 5], [p1[0] + 5, p1[1] - 5], [p1[0] - 5, p1[1] - 5]] point_list.append(point_list[0]) for i in range(1, len(point_list)): p1 = point_list[i-1] p2 = point_list[i] points = get_line_pixels(p1, p2) for p in points: index1 = p[1] * size[0] + p[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) interactor.GetRenderWindow().SetRGBACharPixelData(0, 0, size[0] - 1, size[1] - 1, tmp_array, 0) interactor.GetRenderWindow().Frame() def OnButtonDown(self, x, y, ren, iren): if self._picking_active: self.add_point(iren, ren) else: self.begin_picking(ren, iren) self.add_point(iren, ren) def OnButtonUp(self, x, y, ren, iren): #self.end_picking(ren, iren) pass def OnMouseMove(self, x, y, ren, iren): if not self._picking_active: return if not ren: return self.renderer = ren self.iren = iren pos = iren.GetEventPosition() self._end_position[0] = pos[0] self._end_position[1] = pos[1] self.ren_win_size = self.ren_win.GetSize() size = self.ren_win_size if self._end_position[0] > size[0] - 1: self._end_position[0] = size[0] - 1 if self._end_position[0] < 0: self._end_position[0] = 0 if self._end_position[1] > size[1] - 1: self._end_position[1] = size[1] - 1 if self._end_position[1] < 0: self._end_position[1] = 0 self._redraw_picking_box(iren) def PrintSelf(self): super(self, PolyPicker).PrintSelf() print("Center: %f, %f, %f" % (self.Center[0], self.Center[1], self.Center[2])) def finalize(self): self.vtk_graphics = None self.picking_manager = None
class EmptyTable(QtWidgets.QTableView): def __init__(self, *args, **kwargs): super().__init__(*args) self._scroll_factor = 1. self._enter_down = True self.undo = MrSignal() self.redo = MrSignal() def setModel(self, model): from ..table_data import TableDataModel assert isinstance(model, TableDataModel) super().setModel(model) def keyPressEvent(self, event): super().keyPressEvent(event) if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True elif event.key() == QtCore.Qt.Key_Tab: event.accept() if event.matches(QtGui.QKeySequence.Copy): self._copy() event.accept() elif event.matches(QtGui.QKeySequence.Paste): paste_data = str(QtWidgets.QApplication.clipboard().text()) self.model().set_data_range(self.selection_range(), paste_data) event.accept() elif event.matches(QtGui.QKeySequence.Undo): event.accept() self.undo.emit() elif event.matches(QtGui.QKeySequence.Redo): event.accept() self.redo.emit() def keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False super().keyReleaseEvent(event) def wheelEvent(self, event): if not QtWidgets.QApplication.keyboardModifiers( ) & QtCore.Qt.ControlModifier: return super().wheelEvent(event) font = self.font() new_size = old_size = font.pointSize() if event.angleDelta().y() > 0: new_size += 1 else: new_size -= 1 if new_size == 0: new_size = old_size self._scroll_factor = new_size / old_size font.setPointSize(new_size) self.setFont(font) self.horizontalHeader().setFont(font) self.verticalHeader().setFont(font) self.resizeRowsToContents() self.resizeColumnsToContents() self._scroll_factor = 1. def resizeRowsToContents(self): header = self.verticalHeader() for i in range(self.model().rowCount()): header.resizeSection(i, self.rowHeight(i) * self._scroll_factor) def resizeColumnsToContents(self): header = self.horizontalHeader() for i in range(self.model().columnCount()): header.resizeSection(i, self.columnWidth(i) * self._scroll_factor) def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass selection_model = self.selectionModel() selection_model.clearSelection() first_index = None model = self.model() for i in range(len(selections)): selection = selections[i] index = model.index(selection[0], selection[1]) selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.setFocus() return first_index def set_selection_and_index(self, selections): self.setCurrentIndex(self.set_selection(selections)) def select_last_row(self): data_len = self.model().rowCount() self.set_selection_and_index([[data_len - 1, 0]]) def select_and_edit(self, row, column): index = self.model().index(row, column) selection_model = self.selectionModel() selection_model.clear() selection_model.select(index, QtCore.QItemSelectionModel.Select) self.edit(index) def selection_range(self): selection = self.selectionModel().selectedIndexes() min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) return [(min_row, min_col), (max_row, max_col)] def selection(self): selection = self.selectionModel().selectedIndexes() tmp = [] for index in selection: row = index.row() col = index.column() tmp.append((row, col)) return sorted(tmp, key=itemgetter(0)) def update_all(self): try: self.model().update_all() except AttributeError: pass def current_index(self): index = self.currentIndex() return index.row(), index.column() def _copy(self): model = self.model() selection = self.selectionModel().selectedIndexes() edit_role = QtCore.Qt.EditRole try: row1 = selection[0].row() col1 = selection[0].column() except IndexError: return copy_data = [] min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) data = str(model.data(index, edit_role)) copy_data.append([row, col, data]) rows = max_row - min_row + 1 columns = max_col - min_col + 1 if rows == 0 or columns == 0: return np_data = np.zeros((rows, columns), dtype=object) for tmp in copy_data: row, col, data = tmp row -= min_row col -= min_col np_data[row, col] = data text = [] for i in range(np_data.shape[0]): _text = [] for j in range(np_data.shape[1]): _text.append(np_data[i, j]) text.append('\t'.join(_text)) text = '\n'.join(text) # noinspection PyArgumentList clipboard = QtWidgets.QApplication.clipboard() """:type: QtGui.QClipboard""" clipboard.setText(text)
class DataTable(QtWidgets.QTableView): row_changed = QtCore.Signal(int) column_changed = QtCore.Signal(int) selection_changed = QtCore.Signal(int, int) @classmethod def wrap_obj(cls, obj=None, *args, **kwargs): """ :rtype: DataTable """ if obj is None: obj = DataTable(*args, **kwargs) return obj elif isinstance(obj, DataTable): return obj assert isinstance(obj, QtWidgets.QTableView) #parent = obj.parent() obj.__class__ = DataTable DataTable.init(obj) return obj def __init__(self, *args): super(DataTable, self).__init__(*args) self.table_model = None """:type: TableModel""" self.selection_model = None """:type: QtGui.QItemSelectionModel""" #self.selection_model.selectionChanged.connect(self._selection_changed) self._old_row = -1 self._old_column = -1 self._enter_down = False self.data_changed = None """:type: MrSignal""" self.copy = None """:type: MrSignal""" self.paste = None """:type: MrSignal""" self.set_data_signal = None """:type: MrSignal""" self.row_changed = None """:type: MrSignal""" self.column_changed = None """:type: MrSignal""" self.selection_changed = None """:type: MrSignal""" self.undo = None """:type: MrSignal""" self.redo = None """:type: MrSignal""" self.init() def init(self): self.table_model = TableModel(self) self.setModel(self.table_model) self.selection_model = self.selectionModel() """:type: QtGui.QItemSelectionModel""" self.selection_model.selectionChanged.connect(self._selection_changed) self._old_row = -1 self._old_column = -1 self._enter_down = False self.data_changed = self.table_model.data_changed self.data_changed.connect(self._data_changed) self.copy = MrSignal() self.paste = MrSignal() self.row_changed = MrSignal() self.column_changed = MrSignal() self.selection_changed = MrSignal() self.undo = MrSignal() self.redo = MrSignal() self.set_data_signal = self.table_model.set_data_signal #self.table_model.dataChanged.connect(self._data_updated) def _data_changed(self, row, column): if self._enter_down: row += 1 column = column if row >= self.table_model.rowCount(): row -= 1 self.set_selection([[row, column]]) # def set_selection(self, selections): # try: # QtWidgets.QApplication.instance().focusWidget().clearFocus() # except AttributeError: # pass # # self.selection_model.clearSelection() # # first_index = None # # for i in range(len(selections)): # selection = selections[i] # index = self.table_model.index(selection[0], selection[1]) # self.selection_model.select(index, QtCore.QItemSelectionModel.Select) # # if first_index is None: # first_index = index # # self.setCurrentIndex(first_index) # #self.setFocus(True) # self.setFocus() def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass self.selection_model.clearSelection() first_index = None for i in range(len(selections)): selection = selections[i] index = self.table_model.index(selection[0], selection[1]) self.selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index #self.setCurrentIndex(first_index) self.setFocus(True) # self.setFocus() def set_selection_and_index(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass self.selection_model.clearSelection() first_index = None for i in range(len(selections)): selection = selections[i] index = self.table_model.index(selection[0], selection[1]) self.selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.setCurrentIndex(first_index) self.setFocus(True) # self.setFocus() def selection(self): selection = self.selectionModel().selectedIndexes() min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) return [(min_row, min_col), (max_row, max_col)] def keyPressEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True elif event.matches(QtGui.QKeySequence.Copy): self._copy() elif event.matches(QtGui.QKeySequence.Paste): paste_data = str(QtWidgets.QApplication.clipboard().text()) self.paste.emit(self.selection(), paste_data) elif event.matches(QtGui.QKeySequence.Undo): self.undo.emit() elif event.matches(QtGui.QKeySequence.Redo): self.redo.emit() else: super(DataTable, self).keyPressEvent(event) def keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False super(DataTable, self).keyReleaseEvent(event) def setup_data(self, headers, data): self.table_model.setup_data(headers, data) def set_headers(self, headers): self.table_model.set_headers(headers) def sizeHint(self): return QtCore.QSize(800, 500) def update_all(self): self.table_model.update_all() def current_row(self): return self._old_row def current_column(self): return self._old_column def set_editable_columns(self, int_set): self.table_model.set_editable_columns(int_set) def _selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous:QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit(new_row, new_column) def select_last_row(self): data_len = len(self.table_model._data) self.set_selection([[data_len - 1, 0]]) def select_and_edit(self, row, column): index = self.table_model.index(row, column) self.selectionModel().clear() self.selectionModel().select(index, QtCore.QItemSelectionModel.Select) self.edit(index) def _copy(self): model = self.model() selection = self.selectionModel().selectedIndexes() edit_role = QtCore.Qt.EditRole try: row1 = selection[0].row() col1 = selection[0].column() except IndexError: return copy_data = [] min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) data = str(model.data(index, edit_role)) copy_data.append([row, col, data]) rows = max_row - min_row + 1 columns = max_col - min_col + 1 if rows == 0 or columns == 0: return np_data = np.zeros((rows, columns), dtype=object) for tmp in copy_data: row, col, data = tmp row -= min_row col -= min_col np_data[row, col] = data text = [] for i in range(np_data.shape[0]): _text = [] for j in range(np_data.shape[1]): _text.append(np_data[i, j]) text.append('\t'.join(_text)) text = '\n'.join(text) # noinspection PyArgumentList clipboard = QtWidgets.QApplication.clipboard() """:type: QtGui.QClipboard""" clipboard.setText(text)
class TableModel(QtCore.QAbstractTableModel): def __init__(self, *args): super(TableModel, self).__init__(*args) self.headers = None self._data = None self._get_data = None self._set_data = None self.editable_columns = set() self.data_changed = MrSignal() self.set_data_signal = MrSignal() def set_headers(self, headers): self.headers = headers self.update_all() def setup_data(self, headers, data): if not isinstance(headers, (list, tuple)): headers = [headers] self.headers = headers self._data = data self._get_data = self._data.get_data self._set_data = self._data.set_data if headers is None or data is None: return self.update_all() def set_data(self, data): self._data = data self._get_data = self._data.get_data self._set_data = self._data.set_data if data is None: return self.update_all() def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): if self.headers is not None and role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: return self.headers[section] else: return section + 1 return None def rowCount(self, index=QtCore.QModelIndex()): if self._data is None: return 0 return len(self._data) def columnCount(self, index=QtCore.QModelIndex()): if self.headers is None: return 0 return len(self.headers) def set_editable_columns(self, int_set): self.editable_columns = int_set def flags(self, index): if int(index.column()) in self.editable_columns: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable else: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def data(self, index, role=QtCore.Qt.DisplayRole): if self._data is None or self.headers is None: return None if role == QtCore.Qt.EditRole: row = index.row() col = index.column() data = self._get_data((row, col)) if data is None: return '' return str(data) elif role == QtCore.Qt.DisplayRole: row = index.row() col = index.column() data = self._get_data((row, col)) if data is None: return '' if isinstance(data, list) and len(data) > 0 and isinstance( data[0], float): return str([round(i, 6) for i in data]) return str(data) def setData(self, index, value, role=QtCore.Qt.DisplayRole): if self._data is None or self.headers is None: return row = index.row() col = index.column() self.set_data_signal.emit((row, col), str(value), role) return self.set_data_signal.results[0] def update_all(self): self.layoutChanged.emit() top_left = self.index(0, 0) bot_right = self.index(self.rowCount() - 1, self.columnCount() - 1) self.dataChanged.emit(top_left, bot_right)
class AbstractTableView(QtWidgets.QTableView): TableModel = AbstractTableModel def __init__(self, *args, **kwargs): super().__init__(*args) self._scroll_factor = 1. self._enter_down = False self._shift_down = False self._ctrl_down = False self.undo = MrSignal() self.redo = MrSignal() self._model = self.TableModel() self.setModel(self._model) self.selection_model = self.selectionModel() """:type: QtGui.QItemSelectionModel""" self.selection_model.selectionChanged.connect(self._selection_changed) self.selection_changed = MrSignal() self.row_changed = MrSignal() self.column_changed = MrSignal() self._old_row = -1 self._old_column = -1 def _select_next_row_down(self): row, col = self.current_index() if row < self.model().rowCount() - 1: row += 1 self.set_selection_and_index([[row, col]]) def _select_next_row_up(self): row, col = self.current_index() if row > 0: row -= 1 self.set_selection_and_index([[row, col]]) def keyPressEvent(self, event): super().keyPressEvent(event) if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True if self._ctrl_down is False: if self._shift_down is True: self._select_next_row_up() else: self._select_next_row_down() elif event.key() == QtCore.Qt.Key_Shift: self._shift_down = True elif event.key() == QtCore.Qt.Key_Control: self._ctrl_down = True elif event.key() == QtCore.Qt.Key_Tab: event.accept() if event.matches(QtGui.QKeySequence.Copy): self._copy() event.accept() elif event.matches(QtGui.QKeySequence.Paste): selection_range = self.selection_range() paste_data = str(QtWidgets.QApplication.clipboard().text()) paste_data = _get_paste_data(selection_range, paste_data, (self.model().rowCount(), self.model().columnCount()) ) if paste_data is not None: self.model().set_data_range(selection_range[0], paste_data) top_left = selection_range[0] bot_right = selection_range[0][0] + len(paste_data) - 1, selection_range[0][1] + len(paste_data[0]) - 1 self.set_selection_range(top_left, bot_right) event.accept() elif event.matches(QtGui.QKeySequence.Undo): event.accept() self.undo.emit() elif event.matches(QtGui.QKeySequence.Redo): event.accept() self.redo.emit() def keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False elif event.key() == QtCore.Qt.Key_Shift: self._shift_down = False elif event.key() == QtCore.Qt.Key_Control: self._ctrl_down = False super().keyReleaseEvent(event) def wheelEvent(self, event): if not QtWidgets.QApplication.keyboardModifiers() & QtCore.Qt.ControlModifier: return super().wheelEvent(event) font = self.font() new_size = old_size = font.pointSize() if event.angleDelta().y() > 0: new_size += 1 else: new_size -= 1 if new_size == 0: new_size = old_size self._scroll_factor = new_size / old_size font.setPointSize(new_size) self.setFont(font) self.horizontalHeader().setFont(font) self.verticalHeader().setFont(font) self.resizeRowsToContents() self.resizeColumnsToContents() self._scroll_factor = 1. def resizeRowsToContents(self): header = self.verticalHeader() for i in range(self.model().rowCount()): header.resizeSection(i, self.rowHeight(i) * self._scroll_factor) def resizeColumnsToContents(self): header = self.horizontalHeader() for i in range(self.model().columnCount()): header.resizeSection(i, self.columnWidth(i) * self._scroll_factor) def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass selection_model = self.selectionModel() selection_model.clearSelection() first_index = None model = self.model() for i in range(len(selections)): selection = selections[i] index = model.index(selection[0], selection[1]) selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.setFocus() return first_index def set_selection_range(self, top_left, bot_right): selections = [] rows = bot_right[0] - top_left[0] + 1 cols = bot_right[1] - top_left[1] + 1 i_, j_ = top_left for i in range(rows): for j in range(cols): selections.append((i_ + i, j_ + j)) self.set_selection(selections) def set_selection_and_index(self, selections): self.setCurrentIndex(self.set_selection(selections)) def select_last_row(self): data_len = self.model().rowCount() self.set_selection_and_index([[data_len - 1, 0]]) def select_and_edit(self, row, column): index = self.model().index(row, column) selection_model = self.selectionModel() selection_model.clear() selection_model.select(index, QtCore.QItemSelectionModel.Select) self.edit(index) def selection_range(self): selection = self.selectionModel().selectedIndexes() min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) return [(min_row, min_col), (max_row, max_col)] def selection(self): selection = self.selectionModel().selectedIndexes() tmp = [] for index in selection: row = index.row() col = index.column() tmp.append((row, col)) return list(sorted(tmp, key=itemgetter(0))) def update_all(self): self.model().update_all() def current_index(self): index = self.currentIndex() return index.row(), index.column() def _copy(self): model = self.model() selection = self.selectionModel().selectedIndexes() edit_role = QtCore.Qt.EditRole try: row1 = selection[0].row() col1 = selection[0].column() except IndexError: return copy_data = [] min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) data = str(model.data(index, edit_role)) copy_data.append([row, col, data]) rows = max_row - min_row + 1 columns = max_col - min_col + 1 if rows == 0 or columns == 0: return np_data = np.zeros((rows, columns), dtype=object) for tmp in copy_data: row, col, data = tmp row -= min_row col -= min_col np_data[row, col] = data text = [] for i in range(np_data.shape[0]): _text = [] for j in range(np_data.shape[1]): _text.append(np_data[i, j]) text.append('\t'.join(_text)) text = '\n'.join(text) # noinspection PyArgumentList clipboard = QtWidgets.QApplication.clipboard() """:type: QtGui.QClipboard""" clipboard.setText(text) def set_model_data(self, data, update_all=True): self._model.set_model_data(data, update_all) def _selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous: QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit((new_row, new_column))
class HoveredInteractorStyle(vtkCameraManipulator): def __init__(self): vtkCameraManipulator.__init__(self) self.cell_picker = CellPicker() self.hovered_data = None self.visible_filter = None self.pickable_types = None self.picked_id = -1 self.vtk_graphics = VTKGraphics.instance() self.key_down = MrSignal() def visible_only(self): self.cell_picker.toggle_visible() def set_hovered_data(self, hovered_data): self.hovered_data = hovered_data def set_visible_filter(self, visible_filter): self.visible_filter = visible_filter self.cell_picker.SetInputConnection( self.visible_filter.GetOutputPort()) def set_pickable_types(self, pickable_types): self.pickable_types = pickable_types self.cell_picker.SetActiveData(self.pickable_types.raw_pointer(), 'card_types') def OnMouseMove(self, x, y, ren, iren): self.cell_picker.Pick(x, y, 0, ren) picked_id = self.cell_picker.GetClosestCellGlobalId() if self.picked_id != picked_id: self.picked_id = picked_id if picked_id > 0: self.hovered_data.set_data(picked_id) else: self.hovered_data.set_data([]) self.vtk_graphics.hovered_filter.Modified() self.vtk_graphics.render() def OnKeyDown(self, iren): super(HoveredInteractorStyle, self).OnKeyDown(iren) self.key_down.emit(self.KeyCode) def unload(self): self.hovered_data.set_data([]) def finalize(self): self.cell_picker.finalize() self.cell_picker = None self.hovered_data = None self.visible_filter = None self.pickable_types = None self.vtk_graphics = None
class MultiTable(QtWidgets.QWidget): MainData_1 = TableDataList MainData_2 = TableDataList main_data_1 = None main_data_2 = None def __init__(self, parent=None, dispatcher_id=None, id_1='Table1', id_2='Table2'): super(MultiTable, self).__init__(parent) class _Table1(BasicTable): MainData = self.MainData_1 main_data = self.main_data_1 class _Table2(BasicTable): MainData = self.MainData_2 main_data = self.main_data_2 self.table_1 = _Table1(self) self.table_1.dispatcher.dispatcher_id = id_1 self.table_2 = _Table2(self) self.table_2.dispatcher.dispatcher_id = id_2 self._splitter = QtWidgets.QSplitter(QtCore.Qt.Horizontal) self._splitter.addWidget(self.table_1) self._splitter.addWidget(self.table_2) self._layout = QtWidgets.QHBoxLayout(self) self.setLayout(self._layout) self._layout.addWidget(self._splitter) self.table_1.table_1.row_changed.connect(self._row_changed) self.dispatcher = _CommandDispatcher(self) self.dispatcher.dispatcher_id = dispatcher_id self.dispatcher.add_child(self.table_1.dispatcher) self.dispatcher.add_child(self.table_2.dispatcher) self.request_focus = MrSignal() self.data = {} """:type: dict[str, TableDataList]""" def _row_changed(self, row): try: data_id = self.table_1.main_data[row].id except IndexError: return if data_id == '': return try: data = self.data[data_id] except KeyError: data = self.data[data_id] = self.MainData_2() self.table_2.set_main_data(data) def current_data_id(self): try: return self.table_1.main_data[self.table_1.table_1.current_index()[0]].id except IndexError: return None def get_data(self, data_id): # debuginfo(self.data) return self.data.get(data_id, None) # @show_stack_trace def activate(self, data_id): # debuginfo('activate', 1) ids = self.table_1.main_data.ids() # debuginfo('activate', 2) try: index = ids.index(data_id) except ValueError: return # debuginfo('activate', 3) # debuginfo('MultiTable set selection and index') self.table_1.table_1.set_selection_and_index([[index, 0]]) # debuginfo('activate', 4) self.request_focus.emit() def update_all(self): self.table_1.update_all() self.table_2.update_all()
class FemGroupList(object): def __init__(self): self.groups = OrderedDict() """:type: OrderedDict[FemGroup]""" self.data_changed = MrSignal() self._all_groups = FemGroup() self._default_group = FemGroup() self._default_group.group_name = 'Default' self._default_group.data_changed.connect(self._data_changed) self.groups['Default'] = self._default_group def _data_changed(self): self.all_groups() self.data_changed.emit() def add_group(self, name): if name == 'Default': self.groups['Default'] = self._default_group return self._default_group if name in self.groups: new_name = self.new_name() name = new_name.replace('group', name) new_group = FemGroup() new_group.data_changed.connect(self._data_changed) self.groups[name] = new_group new_group.group_name = name return new_group def remove_group(self, name): if name == 'Default': return try: old_group = self.groups[name] old_group.data_changed.disconnect(self._data_changed) del self.groups[name] except KeyError: pass def get_group(self, name): return self.groups[name] def get_group_by_index(self, index): group_name = list(self.groups.keys())[index] return self.groups[group_name] def rename_group(self, old_name, new_name): if old_name == 'Default': return if old_name not in self.groups: return group_names = list(self.groups.keys()) tmp = dict(self.groups) self.groups.clear() for group_name in group_names: group = tmp[group_name] if group_name == old_name: group_name = new_name group.group_name = group_name self.groups[group_name] = group self.data_changed.emit() def set_active(self, group_name, bool): if group_name not in self.groups: return self.groups[group_name].set_active(bool) def show_group(self, name): try: self.groups[name].set_active(True) except KeyError: pass def hide_group(self, name): try: self.groups[name].set_active(False) except KeyError: pass def all_groups(self): data = self._all_groups data.data_changed.block() data.set_data([]) add_data = data.data.add_data4 for id, group in iteritems(self.groups): if group.is_active: add_data(group.data) data.data_changed.unblock() return data def size(self): return len(self.groups) def new_name(self): size = self.size() new_name_ = 'group_%d' % size while new_name_ in self.groups: size += 1 new_name_ = 'group_%d' % size return new_name_ def serialize(self): data = [] for key, item in iteritems(self.groups): data.append((key, item.to_str())) return data def clear(self): self.groups.clear() def load(self, data): if not isinstance(data, list): return self.clear() for data_ in data: group_name, group_data = data_ group = self.add_group(group_name) group.set_data(group_data)
class EmptyTable(QtWidgets.QWidget): def __init__(self, parent=None, *args): super(EmptyTable, self).__init__(parent, *args) self.setLayout(QtWidgets.QVBoxLayout()) #### buttons #### self.pushButton_add = QtWidgets.QPushButton('Add', self) self.pushButton_insert = QtWidgets.QPushButton('Insert', self) self.pushButton_delete = QtWidgets.QPushButton('Delete', self) self.button_spacer = QtWidgets.QSpacerItem( 100, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.button_layout = QtWidgets.QHBoxLayout() self.button_layout.addWidget(self.pushButton_add) self.button_layout.addWidget(self.pushButton_insert) self.button_layout.addWidget(self.pushButton_delete) self.button_layout.addItem(self.button_spacer) #### table_2 #### self.table = QtWidgets.QTableView(self) self.table.wheelEvent = self._wheel_event self.table.resizeRowsToContents = self._resize_rows self.table.resizeColumnsToContents = self._resize_columns # self.table_2.setModel(QtCore.QAbstractTableModel()) #### bottom buttons #### self.pushButton_up = QtWidgets.QPushButton('^', self) self.pushButton_down = QtWidgets.QPushButton('v', self) self.lineEdit_rows = QtWidgets.QLineEdit(self) self.lineEdit_rows.setAlignment(QtCore.Qt.AlignCenter) self.lineEdit_rows.setCursor(QtCore.Qt.ArrowCursor) self.lineEdit_rows.setMaximumWidth(50) self.lineEdit_rows.editingFinished.connect(self._set_rows) self.lineEdit_rows.mousePressEvent = self._rows_mouse_press self.lineEdit_rows.setStyleSheet(""" QLineEdit::hover{ background-color: Lightcyan } """) self.bottom_spacer = QtWidgets.QSpacerItem( 100, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.bottom_layout = QtWidgets.QHBoxLayout() self.bottom_layout.addWidget(self.pushButton_up) self.bottom_layout.addWidget(self.pushButton_down) self.bottom_layout.addItem(self.bottom_spacer) self.bottom_layout.addWidget(self.lineEdit_rows) #### add to layout #### self.layout().addItem(self.button_layout) self.layout().addWidget(self.table) self.layout().addItem(self.bottom_layout) # self.table_2.selectionModel().selectionChanged.connect(self._selection_changed) self._old_row = -1 self._old_column = -1 self._enter_down = False self.selection_changed = MrSignal() self.row_changed = MrSignal() self.column_changed = MrSignal() self.undo = MrSignal() self.redo = MrSignal() self.paste = MrSignal() self.set_data = MrSignal() self.set_rows = MrSignal() self.data_changed = MrSignal() self.table.keyPressEvent = self._keyPressEvent self.table.keyReleaseEvent = self._keyReleaseEvent # self.table.mousePressEvent = self._mousePressEvent self._scroll_factor = 1. def _wheel_event(self, event): if not QtWidgets.QApplication.keyboardModifiers( ) & QtCore.Qt.ControlModifier: return QtWidgets.QTableView.wheelEvent(self.table, event) font = self.table.font() new_size = old_size = font.pointSize() if event.angleDelta().y() > 0: new_size += 1 else: new_size -= 1 if new_size == 0: new_size = old_size self._scroll_factor = new_size / old_size font.setPointSize(new_size) self.table.setFont(font) self.table.horizontalHeader().setFont(font) self.table.verticalHeader().setFont(font) self._resize_rows() self._resize_columns() self._scroll_factor = 1. # return QtWidgets.QTableView.wheelEvent(self.table, event) def _resize_rows(self): header = self.table.verticalHeader() for i in range(self.table.model().rowCount()): header.resizeSection(i, self.table.rowHeight(i) * self._scroll_factor) def _resize_columns(self): header = self.table.horizontalHeader() for i in range(self.table.model().columnCount()): header.resizeSection( i, self.table.columnWidth(i) * self._scroll_factor) def _rows_mouse_press(self, event): event.accept() self.lineEdit_rows.selectAll() def _set_rows(self, *args): try: rows = int(self.lineEdit_rows.text()) except (ValueError, TypeError): rows = -1 self.lineEdit_rows.clearFocus() self.set_rows.emit(rows) def hide_buttons(self): self.pushButton_add.hide() self.pushButton_insert.hide() self.pushButton_delete.hide() self.pushButton_up.hide() self.pushButton_down.hide() self.lineEdit_rows.hide() def show_buttons(self): self.pushButton_add.show() self.pushButton_insert.show() self.pushButton_delete.show() self.pushButton_up.show() self.pushButton_down.show() self.lineEdit_rows.show() def set_model(self, model): self.table.setModel(model) self.table.selectionModel().selectionChanged.connect( self._selection_changed) self.table.model().set_data.connect(self._set_data) self.table.model().dataChanged.connect(self._data_changed) def _data_changed(self, *args): self.data_changed.emit() def _set_data(self, *args): self.set_data.emit(self._enter_down, *args) def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass selection_model = self.table.selectionModel() selection_model.clearSelection() first_index = None model = self.table.model() for i in range(len(selections)): selection = selections[i] index = model.index(selection[0], selection[1]) selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.table.setFocus() return first_index def set_selection_and_index(self, selections): self.table.setCurrentIndex(self.set_selection(selections)) def select_last_row(self): data_len = self.table.model().rowCount() self.set_selection_and_index([[data_len - 1, 0]]) def select_and_edit(self, row, column): index = self.table.model().index(row, column) selection_model = self.table.selectionModel() selection_model.clear() selection_model.select(index, QtCore.QItemSelectionModel.Select) self.edit(index) def selection_range(self): selection = self.table.selectionModel().selectedIndexes() min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) return [(min_row, min_col), (max_row, max_col)] def selection(self): selection = self.table.selectionModel().selectedIndexes() tmp = [] for index in selection: row = index.row() col = index.column() tmp.append((row, col)) return sorted(tmp, key=itemgetter(0)) def update_all(self): try: self.table.model().update_all() except AttributeError: pass def _selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous:QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit((new_row, new_column)) def _keyPressEvent(self, event): QtWidgets.QTableView.keyPressEvent(self.table, event) if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True # event.accept() elif event.key() == QtCore.Qt.Key_Tab: event.accept() if event.matches(QtGui.QKeySequence.Copy): self._copy() event.accept() elif event.matches(QtGui.QKeySequence.Paste): paste_data = str(QtWidgets.QApplication.clipboard().text()) self.paste.emit(self.selection_range(), paste_data) event.accept() elif event.matches(QtGui.QKeySequence.Undo): event.accept() self.undo.emit() elif event.matches(QtGui.QKeySequence.Redo): event.accept() self.redo.emit() def _keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False QtWidgets.QTableView.keyReleaseEvent(self.table, event) def mousePressEvent(self, event): self.lineEdit_rows.clearFocus() QtWidgets.QWidget.mousePressEvent(self, event) def current_index(self): index = self.table.currentIndex() return index.row(), index.column() def _copy(self): model = self.table.model() selection = self.table.selectionModel().selectedIndexes() edit_role = QtCore.Qt.EditRole try: row1 = selection[0].row() col1 = selection[0].column() except IndexError: return copy_data = [] min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) data = str(model.data(index, edit_role)) copy_data.append([row, col, data]) rows = max_row - min_row + 1 columns = max_col - min_col + 1 if rows == 0 or columns == 0: return np_data = np.zeros((rows, columns), dtype=object) for tmp in copy_data: row, col, data = tmp row -= min_row col -= min_col np_data[row, col] = data text = [] for i in range(np_data.shape[0]): _text = [] for j in range(np_data.shape[1]): _text.append(np_data[i, j]) text.append('\t'.join(_text)) text = '\n'.join(text) # noinspection PyArgumentList clipboard = QtWidgets.QApplication.clipboard() """:type: QtGui.QClipboard""" clipboard.setText(text) def row_count(self): return self.table.model().rowCount()
class BoxPicker(vtkCameraManipulator): def __init__(self): vtkCameraManipulator.__init__(self) self.picked_data = None self.box_picker = vtk.vtkExtractSelectedFrustum() self._start_position = [0, 0] self._end_position = [0, 0] self._pixel_array = vtk.vtkUnsignedCharArray() self.ex = vtk.vtkExtractSelection() self.selection_node = vtk.vtkSelectionNode() self.selection_node.SetContentType(vtk.vtkSelectionNode.THRESHOLDS) self.ex_selection = vtk.vtkSelection() self.ex_selection.AddNode(self.selection_node) self.ex.SetInputConnection(0, self.box_picker.GetOutputPort()) self.ex.SetInputData(1, self.ex_selection) self._down_pos = None self._up_pos = None self.iren = None self.ren_win = None self.ren_win_size = None self.data_picked = MrSignal() self.done_picking = MrSignal() self._picking_active = False # self.vtk_graphics = VTKGraphics.instance() from .picking_manager import PickingManager self.picking_manager = PickingManager.instance() def set_input_connection(self, port): self.box_picker.SetInputConnection(port) def begin_picking(self, interactor): self.iren = interactor self.ren_win = interactor.GetRenderWindow() self.ren_win_size = self.ren_win.GetSize() self._start_position[0] = interactor.GetEventPosition()[0] self._start_position[1] = interactor.GetEventPosition()[1] self._end_position[0] = self._start_position[0] self._end_position[1] = self._start_position[1] self._pixel_array.Reset() self._pixel_array.SetNumberOfComponents(4) self._pixel_array.SetNumberOfTuples(self.ren_win_size[0] * self.ren_win_size[1]) self.ren_win.GetRGBACharPixelData(0, 0, self.ren_win_size[0] - 1, self.ren_win_size[1] - 1, 1, self._pixel_array) pos = interactor.GetEventPosition() self._down_pos = pos self._picking_active = True def end_picking(self, renderer, interactor): pos = interactor.GetEventPosition() self._up_pos = pos self._frustum = create_box_frustum(self._down_pos[0], self._down_pos[1], self._up_pos[0], self._up_pos[1], renderer) self.box_picker.SetFrustum(self._frustum) self.something_picked() self._picking_active = False self.done_picking.emit() def get_picking_frustums(self): return [self._frustum] def something_picked(self): self.box_picker.Modified() self.box_picker.Update() global_ids = self.box_picker.GetOutput().GetCellData().GetArray("global_ids") if global_ids is None: self.picking_manager.set_picked_data([]) return get_value = global_ids.GetValue data = [] for i in range(global_ids.GetNumberOfTuples()): data.append(get_value(i)) self.picking_manager.set_picked_data(data) def _redraw_picking_box(self, interactor): tmp_array = vtk.vtkUnsignedCharArray() tmp_array.DeepCopy(self._pixel_array) min = [0, 0] max = [0, 0] size = self.ren_win_size if self._start_position[0] <= self._end_position[0]: min[0] = self._start_position[0] else: min[0] = self._end_position[0] if min[0] < 0: min[0] = 0 if min[0] >= size[0]: min[0] = size[0] - 1 if self._start_position[1] <= self._end_position[1]: min[1] = self._start_position[1] else: min[1] = self._end_position[1] if min[1] < 0: min[1] = 0 if min[1] >= size[1]: min[1] = size[1] - 1 if self._end_position[0] > self._start_position[0]: max[0] = self._end_position[0] else: max[0] = self._start_position[0] if max[0] < 0: max[0] = 0 if max[0] >= size[0]: max[0] = size[0] - 1 if self._end_position[1] > self._start_position[1]: max[1] = self._end_position[1] else: max[1] = self._start_position[1] if max[1] < 0: max[1] = 0 if max[1] >= size[1]: max[1] = size[1] - 1 for i in range(min[0], max[0] + 1): index1 = min[1] * size[0] + i tmp_array.SetTuple4(index1, 255, 120, 0, 1) index1 = max[1] * size[0] + i tmp_array.SetTuple4(index1, 255, 120, 0, 1) for i in range(min[1] + 1, max[1]): index1 = i*size[0] + min[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) index1 = i*size[0] + max[0] tmp_array.SetTuple4(index1, 255, 120, 0, 1) interactor.GetRenderWindow().SetRGBACharPixelData(0, 0, size[0] - 1, size[1] - 1, tmp_array, 0) interactor.GetRenderWindow().Frame() def OnButtonDown(self, x, y, ren, iren): self.begin_picking(iren) def OnButtonUp(self, x, y, ren, iren): self.end_picking(ren, iren) def OnMouseMove(self, x, y, ren, iren): if not self._picking_active: return if not ren: return self._end_position[0] = iren.GetEventPosition()[0] self._end_position[1] = iren.GetEventPosition()[1] self.ren_win_size = self.ren_win.GetSize() size = self.ren_win_size if self._end_position[0] > size[0] - 1: self._end_position[0] = size[0] - 1 if self._end_position[0] < 0: self._end_position[0] = 0 if self._end_position[1] > size[1] - 1: self._end_position[1] = size[1] - 1 if self._end_position[1] < 0: self._end_position[1] = 0 self._redraw_picking_box(iren) def PrintSelf(self): super(self, BoxPicker).PrintSelf() print("Center: %f, %f, %f" % (self.Center[0], self.Center[1], self.Center[2])) def finalize(self): # self.vtk_graphics = None self.picking_manager = None
class BasicDockWidget(QtWidgets.QDockWidget): def __init__(self, dock_name='BasicDockWidget'): super(BasicDockWidget, self).__init__() self.dock_name = dock_name self.setWindowTitle(dock_name) self.dispatcher = _CommandDispatcher(dock_name, self) self.widget = None self.show_dock = MrSignal() self.data_changed = MrSignal() """:type: MrSignal""" def set_widget(self, tab_widget): try: self.widget.data_changed.disconnect_all() except AttributeError: pass self.widget = tab_widget self.setWidget(self.widget) self.dispatcher.add_child(self.widget.dispatcher) try: self.widget.data_changed.connect(self._data_changed) except AttributeError: pass def _data_changed(self, *args): self.data_changed.emit() def request_focus(self): self.show() self.raise_() def keyPressEvent(self, event): super(BasicDockWidget, self).keyPressEvent(event) if event.isAccepted(): return if event.matches(QtGui.QKeySequence.Undo): event.accept() self.dispatcher.dispatch('Undo') elif event.matches(QtGui.QKeySequence.Redo): event.accept() self.dispatcher.dispatch('Redo') def serialize(self): return self.widget.serialize() def load(self, data): self.widget.load(data) def clear(self): self.widget.clear() def update_all(self): self.widget.update_all() def clear_data(self): try: self.widget.clear_data() except AttributeError: pass
class BasicTabWidget(QtWidgets.QTabWidget): def __init__(self, tab_name, parent=None): super(BasicTabWidget, self).__init__(parent) self.tab_name = tab_name self.dispatcher = _CommandDispatcher(tab_name, self) self.tables = {} self.data_changed = MrSignal() def add_table(self, table, name, prefix): """ :param table: :type table: BasicTable :param name: :type name: str :param prefix: :type prefix: str :return: :rtype: """ self.dispatcher.add_child(table.dispatcher) self.addTab(table, name) self.tables[name] = table table.table_1.data_changed.connect(self._data_changed) table.table_2.data_changed.connect(self._data_changed) def _data_changed(self, *args): self.data_changed.emit() def keyPressEvent(self, event): super(BasicTabWidget, self).keyPressEvent(event) if event.isAccepted(): return if event.matches(QtGui.QKeySequence.Undo): event.accept() self.dispatcher.dispatch('Undo') elif event.matches(QtGui.QKeySequence.Redo): event.accept() self.dispatcher.dispatch('Redo') def serialize(self): data = [] for key, table in iteritems(self.tables): data.append([key, table.serialize()]) return data def load(self, data): for data_ in data: key, _data = data_ self.tables[key].load(_data) def clear(self): for key, table in iteritems(self.tables): table.clear() def update_all(self): for key, table in iteritems(self.tables): table.update_all()
class FemSelection(object): def __init__(self): self.data = FemSelectionCpp() self.data_changed = MrSignal() def clear(self): self.data.clear() def copy(self, other): """ :param other: :type other: FemSelection :return: :rtype: """ self.set_data(other.data._data) def set_data(self, data): if isinstance(data, int): self.data.set_data1(data) elif isinstance(data, list): self.data.set_data2(data) elif isinstance(data, set): self.data.set_data3(data) elif isinstance(data, np.ndarray): self.data.set_data4(data, data.size) elif isinstance(data, str): self.data.set_data2(self.from_str(data)) else: raise TypeError(type(data)) self.data_changed.emit() def add_data(self, data): if isinstance(data, int): self.data.add_data1(data) elif isinstance(data, list): self.data.add_data2(data) elif isinstance(data, set): self.data.add_data3(data) elif isinstance(data, np.ndarray): self.data.add_data2(data) elif isinstance(data, str): self.data.add_data2(self.from_str(data)) else: raise TypeError(type(data)) self.data_changed.emit() def intersect(self, data): if isinstance(data, int): self.data.intersect1(data) elif isinstance(data, list): self.data.intersect2(data) elif isinstance(data, set): self.data.intersect3(data) elif isinstance(data, np.ndarray): self.data.intersect2(data) elif isinstance(data, str): self.data.intersect2(self.from_str(data)) else: raise TypeError(type(data)) self.data_changed.emit() def remove_data(self, data): if isinstance(data, int): self.data.remove_data1(data) elif isinstance(data, list): self.data.remove_data2(data) elif isinstance(data, set): self.data.remove_data3(data) elif isinstance(data, np.ndarray): self.data.remove_data2(data) elif isinstance(data, str): self.data.remove_data2(self.from_str(data)) else: raise TypeError(type(data)) self.data_changed.emit() def to_set(self): return self.data._data def to_numpy(self): return self.data.to_vector() def to_vector(self): return self.data.to_vector() def selection_by_category(self, category): results = self.data.selection_by_category(category) tmp = FemSelection() tmp.set_data(results) return tmp def to_str(self): sorted_list = sorted(list(self.data.to_vector())) categories = OrderedDict() get_category = bdf_card_info.card_category_by_eid global_id = bdf_card_info.global_id for eid in sorted_list: category = get_category(eid) eid_ = global_id(eid) try: categories[category].append(eid_) except KeyError: categories[category] = [eid_] result = "" for category, the_list in iteritems(categories): result += "%s %s\n\n" % (str(category), condense_list(the_list)) return result[:-1] def to_str2(self): condensed = self.data.condense() get_category = bdf_card_info.card_category_by_eid global_id = bdf_card_info.global_id result = [] # FIXME: fix for len(condensed) < 3 # FIXME: this method doesn't work for tmp in condensed: try: category = get_category(tmp[0]).decode('utf-8') except IndexError: continue tmp_result = [category] for i in range(0, len(tmp), 3): eid1 = tmp[i] eid2 = tmp[i + 1] stride = tmp[i + 2] if stride != -1: eid1 = global_id(eid1) eid2 = global_id(eid2) tmp_result.append('%d:%d:%d' % (eid1, eid2, stride)) elif eid2 != -1: eid1 = global_id(eid1) eid2 = global_id(eid2) tmp_result.append('%d:%d' % (eid1, eid2)) else: tmp_result.append('%d' % global_id(eid1)) if len(tmp_result) > 1: result.append(' '.join(tmp_result)) return '\n\n'.join(result) def from_str(self, data): if data == "": return [] data_ = re.split(' |\n', data) def get_category(data): try: first = data[0].upper() except IndexError: return None if "G" == first or "N" == first: return "GRID" elif "E" == first: return "ELEMENT" elif "P" == first: return "PROPERTY" elif "R" == first: return "RBE" elif "M" == first: return "MPC" elif "F" == first: return "FORCE" elif "D" == first: return "Disp" elif "C" == first: return "COORD" else: return None results_ = [] offset = 0 for dat_ in data_: category = get_category(dat_) if category is not None: offset = bdf_card_info.categories(category) * 100000000 continue new_list = [i + offset for i in expand_list(dat_)] results_.extend(new_list) return results_ def set_from_str(self, data): self.set_data(self.from_str(data)) return self def raw_pointer(self): return self.data._data def __iand__(self, data): self.intersect(data) return self def __ior__(self, data): self.add_data(data) return self def __contains__(self, data): return self.data.contains(data)
class MrDataTable2(QtWidgets.QWidget): row_changed = QtCore.Signal(int) column_changed = QtCore.Signal(int) selection_changed = QtCore.Signal(int, int) @classmethod def wrap_obj(cls, obj=None, *args, **kwargs): """ :rtype: MrDataTable """ if obj is None: obj = MrDataTable2(None, *args) return obj elif isinstance(obj, MrDataTable2): return obj assert isinstance(obj, QtWidgets.QTableView) return MrDataTable2(obj, *args) def __init__(self, table_view=None, *args): super(MrDataTable2, self).__init__(*args) if table_view is None: table_view = QtWidgets.QTableView(self) self.table_view = table_view self.table_view.keyPressEvent = self.keyPressEvent self.table_view.keyReleaseEvent = self.keyReleaseEvent self.table_model = MrTableModel(self.table_view) self.table_view.setModel(self.table_model) self.selection_model = self.table_view.selectionModel() """:type: QtGui.QItemSelectionModel""" self.selection_model.selectionChanged.connect(self._selection_changed) self._old_row = -1 self._old_column = -1 self._enter_down = False self.data_changed = self.table_model.data_changed self.data_changed.connect(self._data_changed) self.copy = MrSignal() self.paste = MrSignal() self.show() def horizontalHeader(self): return self.table_view.horizontalHeader() def _data_changed(self, row, column): if self._enter_down: row += 1 column = column if row >= self.table_model.rowCount(): row -= 1 self.set_selection([[row, column]]) def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass self.selection_model.clearSelection() first_index = None for i in range(len(selections)): selection = selections[i] index = self.table_model.index(selection[0], selection[1]) self.selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.setCurrentIndex(first_index) #self.setFocus(True) self.setFocus() def keyPressEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True elif event.matches(QtGui.QKeySequence.Copy): self.copy.emit((self.current_row(), self.current_column())) elif event.matches(QtGui.QKeySequence.Paste): tmp = QtWidgets.QApplication.clipboard().text().split('\n') del tmp[-1] paste_data = [] for tmp_ in tmp: paste_data.append([str(i) for i in tmp_.split('\t')]) self.paste.emit((self.current_row(), self.current_column()), paste_data) QtWidgets.QTableView.keyPressEvent(self.table_view, event) def keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False QtWidgets.QTableView.keyReleaseEvent(self.table_view, event) def setup_data(self, headers, data): self.table_model.setup_data(headers, data) def set_headers(self, headers): self.table_model.set_headers(headers) def sizeHint(self): return QtCore.QSize(800, 500) def update_all(self): self.table_model.update_all() def current_row(self): return self._old_row def current_column(self): return self._old_column def set_editable_columns(self, int_set): self.table_model.set_editable_columns(int_set) def _selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous:QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit(new_row, new_column) def select_last_row(self): data_len = len(self.table_model._data) self.set_selection([[data_len-1, 0]]) def select_and_edit(self, row, column): index = self.table_model.index(row, column) self.selectionModel().clear() self.selectionModel().select(index, QtCore.QItemSelectionModel.Select) self.edit(index)
class DockDataTable(QtWidgets.QTableView): # row_changed = QtCore.Signal(int) # column_changed = QtCore.Signal(int) # selection_changed = QtCore.Signal(int, int) @classmethod def wrap_obj(cls, obj=None, *args, **kwargs): """ :rtype: DockDataTable """ if obj is None: obj = cls(*args, **kwargs) return obj elif isinstance(obj, cls): return obj assert isinstance(obj, QtWidgets.QTableView) obj.__class__ = cls # noinspection PyCallByClass,PyTypeChecker cls.init(obj) return obj def __init__(self, *args): super(DockDataTable, self).__init__(*args) self.table_model = None """:type: DockDataTableModel""" self.selection_model = None """:type: QtGui.QItemSelectionModel""" self._old_row = -1 self._old_column = -1 self._enter_down = False self.set_data = None """:type: MrSignal""" self.copy = None """:type: MrSignal""" self.paste = None """:type: MrSignal""" self.right_click = None """:type: MrSignal""" self.row_changed = None """:type: MrSignal""" self.column_changed = None """:type: MrSignal""" self.selection_changed = None """:type: MrSignal""" self.init() def init(self): self.table_model = DockDataTableModel(self) self.setModel(self.table_model) self.selection_model = self.selectionModel() """:type: QtGui.QItemSelectionModel""" self.selection_model.selectionChanged.connect(self._selection_changed) self._old_row = -1 self._old_column = -1 self._enter_down = False self.set_data = self.table_model.set_data self.copy = MrSignal() self.paste = MrSignal() self.set_data = self.table_model.set_data self.right_click = MrSignal() self.row_changed = MrSignal() self.column_changed = MrSignal() self.selection_changed = MrSignal() def set_selection(self, selections): try: QtWidgets.QApplication.instance().focusWidget().clearFocus() except AttributeError: pass self.selection_model.clearSelection() first_index = None for i in range(len(selections)): selection = selections[i] index = self.table_model.index(selection[0], selection[1]) self.selection_model.select(index, QtCore.QItemSelectionModel.Select) if first_index is None: first_index = index self.setCurrentIndex(first_index) # self.setFocus(True) self.setFocus() def selection(self): selection = self.selectionModel().selectedIndexes() min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) return [(min_row, min_col), (max_row, max_col)] def keyPressEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = True elif event.matches(QtGui.QKeySequence.Copy): self._copy() return elif event.matches(QtGui.QKeySequence.Paste): paste_data = str(QtWidgets.QApplication.clipboard().text()) self.paste.emit(self.selection(), paste_data) super(DockDataTable, self).keyPressEvent(event) def _copy(self): model = self.model() selection = self.selectionModel().selectedIndexes() edit_role = QtCore.Qt.EditRole try: row1 = selection[0].row() col1 = selection[0].column() except IndexError: return copy_data = [] min_row = 9999999 max_row = -1 min_col = 9999999 max_col = -1 for index in selection: row = index.row() col = index.column() min_row = min(min_row, row) max_row = max(max_row, row) min_col = min(min_col, col) max_col = max(max_col, col) data = str(model.data(index, edit_role)) copy_data.append([row, col, data]) rows = max_row - min_row + 1 columns = max_col - min_col + 1 if rows == 0 or columns == 0: return np_data = np.zeros((rows, columns), dtype=object) for tmp in copy_data: row, col, data = tmp row -= min_row col -= min_col np_data[row, col] = data text = '' for i in range(np_data.shape[0]): for j in range(np_data.shape[1]): text += np_data[i, j] + '\t' text += '\n' # noinspection PyArgumentList clipboard = QtWidgets.QApplication.clipboard() """:type: QtGui.QClipboard""" # print('text to copy = ', text) text = text.replace('\t\n', '\n')[:-1] # print('text to copy = ', text) clipboard.setText(text) # may not be needed self.copy.emit(self.selection(), text) def keyReleaseEvent(self, event): if event.key() in [QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return]: self._enter_down = False super(DockDataTable, self).keyReleaseEvent(event) def mousePressEvent(self, event): if event.button() == QtCore.Qt.RightButton: index = self.indexAt(event.pos()) self.set_selection([[index.row(), index.column()]]) super(DockDataTable, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.RightButton: index = self.indexAt(event.pos()) self.right_click.emit(index.row(), index.column()) super(DockDataTable, self).mouseReleaseEvent(event) def setup_data(self, data, headers=None): self.table_model.setup_data(data, headers) def sizeHint(self): return QtCore.QSize(800, 500) def update_all(self): self.table_model.update_all() def current_row(self): try: self.selectionModel().selectedIndices()[0].row() except Exception: return self._old_row def current_column(self): try: self.selectionModel().selectedIndices()[0].column() except Exception: return self._old_column def row_count(self): return self.table_model.rowCount() def column_count(self): return self.table_model.columnCount() def set_editable_columns(self, int_set): self.table_model.set_editable_columns(int_set) def _selection_changed(self, current, previous): """ :type current: QtGui.QItemSelection :type previous:QtGui.QItemSelection """ try: first_index = current.indexes()[0] except IndexError: return new_row = first_index.row() new_column = first_index.column() old_row = self._old_row old_column = self._old_column selection_changed = False if new_row != old_row: self._old_row = new_row self.row_changed.emit(self._old_row) selection_changed = True if new_column != old_column: self._old_column = new_column self.column_changed.emit(self._old_column) selection_changed = True if selection_changed: self.selection_changed.emit(new_row, new_column) def select_last_row(self): data_len = len(self.table_model.model_data) column = self.current_column() if column < 0: column = 0 self.set_selection([[data_len - 1, column]]) def select_and_edit(self, index): index = self.table_model.index(*index) self.selectionModel().clear() self.selectionModel().select(index, QtCore.QItemSelectionModel.Select) self.edit(index) def select(self, index): index = self.table_model.index(*index) self.selectionModel().clear() self.selectionModel().select(index, QtCore.QItemSelectionModel.Select)
class DoubleTreeHandler(object): def __init__(self, tree1, tree2, add_btn, del_btn, add_all=None, remove_all=None): self.data_added = MrSignal() self.data_removed = MrSignal() self.selection_changed = MrSignal() if not isinstance(tree1, BasicTreeView): tree1 = BasicTreeView.wrap_obj(tree1) if not isinstance(tree2, BasicTreeView): tree2 = BasicTreeView.wrap_obj(tree2) self._tree1 = tree1 self._tree2 = tree2 self._tree1.sorting_changed.connect(self.update_trees) self._tree2.sorting_changed.connect(self.update_trees) self.pushButton_add = add_btn """:type: QtGui.QPushButton""" self.pushButton_delete = del_btn """:type: QtGui.QPushButton""" self.pushButton_add_all = add_all """:type: QtGui.QPushButton""" self.pushButton_remove_all = remove_all """:type: QtGui.QPushButton""" self.pushButton_add_clicked = MrSignal() self.pushButton_delete_clicked = MrSignal() self.pushButton_add_all_clicked = MrSignal() self.pushButton_remove_all_clicked = MrSignal() self.pushButton_add.clicked.connect(self.pushButton_add_clicked.emit) self.pushButton_delete.clicked.connect( self.pushButton_delete_clicked.emit) if self.pushButton_add_all: self.pushButton_add_all.clicked.connect( self.pushButton_add_all_clicked.emit) if self.pushButton_remove_all: self.pushButton_remove_all.clicked.connect( self.pushButton_remove_all_clicked.emit) self.pushButton_add_clicked.connect(self._add_btn_clicked) self.pushButton_delete_clicked.connect(self._remove_btn_clicked) self.pushButton_add_all_clicked.connect(self.add_all) self.pushButton_remove_all_clicked.connect(self.remove_all) self._data = OrderedDict() def _add_btn_clicked(self, *args): self.add_selection(self._tree1.get_selected_items_text()) def _remove_btn_clicked(self, *args): self.remove_selection(self._tree2.get_selected_items_text()) def get_selected_1(self): return self._tree1.get_selected_items_text() def get_selected_2(self): return self._tree2.get_selected_items_text() def add_selection(self, selected_items_text): data_keys = list(self._data.keys()) if not data_keys: return selection = selected_items_text if not selection: return for item in selection: row = data_keys.index(item) self._data[data_keys[row]] = 1 self.update_trees() first_index = data_keys.index(selection[0]) self.data_added.emit(first_index, selection[0]) self.selection_changed.emit() def remove_selection(self, selected_items_text): data_keys = list(self._data.keys()) if not data_keys: return selection = selected_items_text if not selection: return for item in selection: row = data_keys.index(item) self._data[data_keys[row]] = 0 self.update_trees() first_index = data_keys.index(selection[0]) self.data_added.emit(first_index, selection[0]) self.selection_changed.emit() def _add_all_clicked(self): self.add_all() def add_all(self, *args): data_keys = self._data.keys() for data in data_keys: self._data[data] = 1 self.update_trees() self.selection_changed.emit() def _remove_all_clicked(self): self.remove_all() def remove_all(self, *args): data_keys = self._data.keys() for data in data_keys: self._data[data] = 0 self.update_trees() self.selection_changed.emit() def clear(self): self._tree1.clear() self._tree2.clear() self._data.clear() def set_data(self, new_data, selected=()): self.clear() new_dict = OrderedDict() for data in new_data: new_dict[str(data)] = 0 for data in selected: new_dict[str(data)] = 1 self._data = new_dict self.update_trees() def set_data_dict(self, data_dict): self.clear() new_dict = OrderedDict() for key in data_dict.keys(): new_dict[str(key)] = data_dict[key] self._data = new_dict self.update_trees() def get_data(self): return self._data.keys() def get_data_dict(self): return OrderedDict(self._data) def get_selected_data(self): data = [] for key, item in iteritems(self._data): if item == 1: data.append(key) return data def get_selected_indices(self): data = [] i = 0 for key, item in iteritems(self._data): if item == 1: data.append(i) i += 1 return data def get_unselected_indices(self): data = [] i = 0 for key, item in iteritems(self._data): if item != 1: data.append(i) i += 1 return data def set_selected_indices(self, indices): i = 0 _data = self._data for key, item in iteritems(_data): if i in indices: _data[key] = 1 else: _data[key] = 0 i += 1 self.update_trees() def update_trees(self): tree1_data = [] tree2_data = [] for data in self._data.keys(): if self._data[data]: tree2_data.append(data) else: tree1_data.append(data) self._tree1.clear() self._tree1.add_items(tree1_data) self._tree2.clear() self._tree2.add_items(tree2_data) def get_tree1(self): return self._tree1 def get_tree2(self): return self._tree2 def set_headers(self, left_header, right_header): self._tree1.set_header(left_header) self._tree2.set_header(right_header)
class DockDataTableModel(QtCore.QAbstractTableModel): def __init__(self, *args): super(DockDataTableModel, self).__init__(*args) self._headers = None self.model_data = None self.editable_columns = set() self.set_data = MrSignal() self._count = 0 def setup_data(self, data, headers=None): if data == []: self.model_data = [] self._headers = [] return if headers is None: headers = data.headers if not isinstance(headers, (list, tuple)): headers = [headers] self._headers = headers[:] if self._headers[-1] is None: del self._headers[-1] self.model_data = data if self.model_data is None: return self.update_all() def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): if role != QtCore.Qt.DisplayRole: # if '' is returned, the headers won't show up... return QtCore.QVariant() if orientation == QtCore.Qt.Horizontal: try: return self._headers[section] except (TypeError, IndexError): return '' else: return section + 1 def rowCount(self, index=QtCore.QModelIndex()): if self.model_data is None: return 0 return len(self.model_data) def columnCount(self, index=QtCore.QModelIndex()): if self._headers is None: return 0 return len(self._headers) def set_editable_columns(self, int_set): self.editable_columns = int_set def flags(self, index): if int(index.column()) in self.editable_columns: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable else: return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable def data(self, index, role=QtCore.Qt.DisplayRole): if self.model_data is None or self._headers is None: return '' if role == QtCore.Qt.EditRole: row = index.row() col = index.column() data = self.model_data[row][col] if data is None: return '' return str(data) elif role == QtCore.Qt.DisplayRole: row = index.row() col = index.column() data = self.model_data[row][col] if data is None: return '' if isinstance(data, list) and len(data) > 0 and isinstance( data[0], float): return str([round(i, 6) for i in data]) return str(data) def setData(self, index, value, role=QtCore.Qt.DisplayRole): if self.model_data is None or self._headers is None: return False self.set_data.emit(index, value, role) return self.set_data.results[0] def update_all(self): self.layoutChanged.emit() top_left = self.index(0, 0) bot_right = self.index(self.rowCount() - 1, self.columnCount() - 1) self.dataChanged.emit(top_left, bot_right)
class Configuration(object): config_file = config_file _major_version = 0 _minor_version = 0 _micro_version = 0 _other_version = 'alpha' def __init__(self): self._database_exe = None self._application_name = 'N/A' self._user_manual = None self._email_recipient = None self._long_name = None self._date_created = None self._date_modified = None self._author = None self._description = None self._icon = None self._file_extension = None self._macro_extension = None tmp = scriptinfo() self._executable = tmp['name'] self._executable_directory = tmp['dir'] self._frozen = tmp['frozen'] self._directory = None self._filename = '' self._dpi = 0 self._app_data_path = None self._settings_file = None self._default_settings_file = None self._release_file = None self._beta_file = None self._app = None """:type: PyQt5.QtWidgets.QApplication.QApplication""" self._main_window = None """:type: PyQt5.QtWidgets.QMainWindow.QMainWindow""" self._main_data = None self.dispatcher = CommandDispatcher() ############################################################################## self._msgs = [] self.message = MrSignal() self.msg = MrSignal() self._read_config() self.picking_manager = None """:type: fem.gui.vtk_widget.vtk_graphics.picking.PickingManager""" def register_picking_manager(self, picking_manager): self.picking_manager = picking_manager def database_exe(self): return self._database_exe def application_name(self): return self._application_name def major_version(self): return self._major_version def minor_version(self): return self._minor_version def micro_version(self): return self._micro_version def other_version(self): return self._other_version def user_manual(self): return self._user_manual def email_recipient(self): return self._email_recipient def long_name(self): return self._long_name def date_created(self): return self._date_created def date_modified(self): return self._date_modified def author(self): return self._author def description(self): return self._description def icon(self): return self._icon def file_extension(self): return self._file_extension def macro_extension(self): return self._macro_extension def executable(self): return self._executable def executable_directory(self): return self._executable_directory def frozen(self): return self._frozen def directory(self): # type: () -> str if self._directory is None: return self.home_directory() return self._directory def set_directory(self, directory): # type: (str) -> None directory = os.path.dirname(os.path.realpath(str(directory))) assert os.path.isdir(directory) self._directory = directory def filename(self): # type: () -> str return self._filename def set_filename(self, filename): # type: (str) -> None self.set_directory(filename) self._filename = filename def dpi(self): return self._dpi def app_data_path(self): return self._app_data_path def settings_file(self): return self._settings_file def default_settings_file(self): if os.path.isfile(self._default_settings_file): return self._default_settings_file return None def release_file(self): return self._release_file def beta_file(self): return self._beta_file def app(self): if self._app is None: self._app = QtWidgets.QApplication([]) w = QtWidgets.QWidget() self._dpi = w.logicalDpiX() if self._dpi != 96: font = self._app.font() font.setPixelSize(13) self._app.setFont(font) return self._app def set_icon(self): self.app().setWindowIcon(QtGui.QIcon(self._icon)) def main_window(self): return self._main_window def register_main_window(self, mw): self._main_window = mw try: self.dispatcher.register_main_window(mw) except AttributeError: pass def main_data(self): return self._main_data def register_main_data(self, md): self._main_data = md def version(self): if self._other_version == '': return self._major_version, self._minor_version, self._micro_version else: return self._major_version, self._minor_version, self._micro_version, self._other_version def application_version(self): return ('%d.%d.%d %s' % (self._major_version, self._minor_version, self._micro_version, self._other_version)).strip() def program_name(self): # type: () -> str return '%s %s' % (self._application_name, self.application_version()) def application_info(self): # _data_roles = OrderedDict() data = {} data['Application Name'] = self._application_name data['Application Version'] = self.application_version() ts = timestamp().split(' ') data['Date'] = ts[0] data['Time'] = ts[1] data['User ID'] = self.user_id() return data def window_title(self): # type: () -> str if self._filename is None: filename = "*" else: filename = self._filename if not self.dispatcher.undo_stack.isClean(): filename += "*" return "%s - [%s]" % (self.program_name(), filename) def user_id(self): return getpass.getuser() @staticmethod def home_directory(): # type: () -> str return os.path.expanduser('~') def view_label(self): # type: () -> str if self._filename is None: filename = '*' else: filename = self._filename return '%s\n%s\n%s' % (self.program_name(), filename, timestamp()) def about(self): about_txt = """ Program Name: %s Version: %s Description: %s Author: %s Date Created: %s Date Modified: %s """ % (self._long_name, self.application_version(), self._description, self._author, self._date_created, self._date_modified) return about_txt @staticmethod def file_in_use(filename): if os.path.exists(filename): # noinspection PyBroadException try: os.rename(filename, filename + '_') os.rename(filename + '_', filename) return False except Exception: return True return False def info_message(self, msg): # type: (str) -> None self.msg.emit('Info: %s' % msg) def push_error(self, msg): self._msgs.append('Error: %s' % msg) def push_info(self, msg): self._msgs.append('Info: %s' % msg) def flush_msgs(self): for msg in self._msgs: self.msg.emit(msg) del self._msgs[:] def clear_msgs(self): del self._msgs[:] def error_message(self, msg): # type: (str) -> None self.msg.emit('Error: %s' % msg) def _read_config(self): config_file = self.config_file if config_file is None: return # config_file = 'configuration.%s.%d.%d.%d.json' % ( # self.config_app_name, self._major_version, self._minor_version, self._micro_version # ) # config_file = os.path.join(self.config_directory, config_file) with open(config_file, 'r') as f: data = json.load(f) application = data['application'] self._author = application['author'] self._date_created = application['date_created'] self._date_modified = application['date_modified'] self._description = application['description'] self._long_name = application['long_name'] self._application_name = application['application_name'] version = application['version'] major = version['major'] minor = version['minor'] micro = version['micro'] other = version['other'] files = data['files'] self._release_file = files['release_file'] self._beta_file = files['beta_file'] self._icon = files['icon'] self._user_manual = files['user_manual'] # self._default_settings_file = files['default_settings_file'] feedback = data['feedback'] self._email_recipient = feedback['email_recipient'] extensions = data['extensions'] self._file_extension = extensions['file_extension'] self._macro_extension = extensions['macro_extension'] # self._database_exe = data['plugins']['punch_database'] self._app_data_path = os.getenv( 'APPDATA') + r'\StressApps\%s' % self._application_name.lower() assert (major, minor, micro, other) == (self._major_version, self._minor_version, self._micro_version, self._other_version) self.set_icon() return data
class PickingManager(object): _instance = None @classmethod def instance(cls): """ :return: :rtype: PickingManager """ if cls._instance is None: cls._instance = cls() return cls._instance def __new__(cls, *args, **kwargs): if cls._instance is None: cls._instance = super(PickingManager, cls).__new__(cls) return cls._instance def __init__(self): from fem.gui.vtk_widget.vtk_graphics import VTKGraphics self.vtk_graphics = VTKGraphics.instance() """:type: fem.gui.vtk_widget.vtk_graphics.VTKGraphics""" self.picked_selection = self.vtk_graphics.picked_selection """:type: fem.gui.vtk_widget.vtk_graphics.picked.PickedSelection""" self.default_single_picker = DefaultSinglePicker(self) self._single_pickers = [self.default_single_picker] """:type: list[SinglePicker]""" self.single_picker = self.default_single_picker self.picking_option = 1 self._registered_selection = None """:type: fem.gui.vtk_widget.vtk_graphics.picked.PickedSelection""" self.picking_finished = MrSignal() def picking_done(self): self.picking_finished.emit() def register_selection(self, selection): if selection is None: self._registered_selection = None self.picked_selection.data_changed.disconnect_all() return self._registered_selection = selection self.picked_selection.data_changed.block() self.picked_selection.copy(self._registered_selection) self.picked_selection.data_changed.unblock() self.picked_selection.data_changed.disconnect_all() self.picked_selection.data_changed.connect(self._picked_selection_changed) def register_single_picker(self, single_picker): if single_picker is not self.single_picker: if self.single_picker is not None: try: last_ = self._single_pickers[-1] except IndexError: last_ = None if self.single_picker is not last_: self._single_pickers.append(self.single_picker) self.single_picker = single_picker def unload_single_picker(self, picker): if picker is self.single_picker: try: self.single_picker = self._single_pickers.pop() except IndexError: self.single_picker = None def single_pick(self, screen_pos, cell_pos, picked_global_id): if self.single_picker is None: return self.single_picker.pick(screen_pos, cell_pos, picked_global_id) def set_picking_option(self, option): assert option in (1, 2, 3) self.picking_option = option def set_picked_data(self, data): option = self.picking_option if option == 1: self.picked_selection.set_data(data) elif option == 2: self.picked_selection.add_data(data) elif option == 3: self.picked_selection.remove_data(data) else: raise ValueError self.vtk_graphics.picked_filter.Modified() self.vtk_graphics.render() def box_picker_activate(self): self.vtk_graphics.interactor_style.box_picker_activate() def poly_picker_activate(self): self.vtk_graphics.interactor_style.poly_picker_activate() def _picked_selection_changed(self, *args): if self._registered_selection is None: return self._registered_selection.copy(self.picked_selection) def finalize(self): for picker in self._single_pickers: picker.finalize() del self._single_pickers[:] self.default_single_picker.finalize() self.default_single_picker = None self.vtk_graphics = None