class DataSourceWidget(_AbstractCtrlWidget): """DataSourceWidget class. Widgets provide data source management and monitoring. """ class AvailStateDelegate(QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent=parent) self._brush = FColor.mkBrush('g') def paint(self, painter, option, index): """Override.""" v = index.data() painter.setPen(Qt.NoPen) if v: painter.setBrush(self._brush) else: painter.setBrush(Qt.NoBrush) rect = option.rect h = rect.height() painter.drawRect(rect.x() + 2, rect.y() + 2, h - 4, h - 4) class DataTypeDelegate(QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent=parent) self._c_brush = FColor.mkBrush('c') self._p_brush = FColor.mkBrush('p') def paint(self, painter, option, index): """Override.""" v = index.data() if isinstance(v, int): painter.setPen(Qt.NoPen) if v == 0: # control data painter.setBrush(self._c_brush) elif v == 1: # pipeline data painter.setBrush(self._p_brush) else: raise ValueError(f"Unknown data type: {v}") rect = option.rect h = rect.height() painter.drawRect(rect.x() + 2, rect.y() + 2, h - 4, h - 4) else: super().paint(painter, option, index) _source_types = { "Run directory": DataSource.FILE, "ZeroMQ bridge": DataSource.BRIDGE, } SPLITTER_HANDLE_WIDTH = 9 def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._con_view = QTableView() self._con_model = ConnectionTableModel(self._source_types) self._con_view.setModel(self._con_model) self._con_src_type_delegate = ComboBoxDelegate(self._source_types) self._con_addr_delegate = LineEditItemDelegateN(self) self._con_port_delegate = LineEditItemDelegateN( self, validator=QIntValidator(0, 65535)) self._con_view.setItemDelegateForColumn(1, self._con_src_type_delegate) self._con_view.setItemDelegateForColumn(2, self._con_addr_delegate) self._con_view.setItemDelegateForColumn(3, self._con_port_delegate) self._src_view = QTreeView() self._src_tree_model = DataSourceItemModel(self) self._src_avail_delegate = self.AvailStateDelegate(self) self._src_data_type_delegate = self.DataTypeDelegate(self) self._src_device_delegate = LineEditItemDelegate(self) self._src_ppt_delegate = LineEditItemDelegate(self) self._src_slicer_delegate = SliceItemDelegate(self) self._src_boundary_delegate = BoundaryItemDelegate(self) self._src_view.setModel(self._src_tree_model) self._src_view.setItemDelegateForColumn(0, self._src_avail_delegate) self._src_view.setItemDelegateForColumn(1, self._src_data_type_delegate) self._src_view.setItemDelegateForColumn(2, self._src_device_delegate) self._src_view.setItemDelegateForColumn(3, self._src_ppt_delegate) self._src_view.setItemDelegateForColumn(4, self._src_slicer_delegate) self._src_view.setItemDelegateForColumn(5, self._src_boundary_delegate) self._monitor_tb = QTabWidget() self._avail_src_view = QListView() self._avail_src_model = DataSourceListModel() self._avail_src_view.setModel(self._avail_src_model) self._process_mon_view = QTableView() self._process_mon_model = ProcessMonitorTableModel() self._process_mon_view.setModel(self._process_mon_model) self._process_mon_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.initUI() self.initConnections() self._non_reconfigurable_widgets = [ self._con_view, ] self._mon = MonProxy() self._raw_srcs = dict() self._matched_srcs = dict() self._avail_src_timer = QTimer() self._avail_src_timer.timeout.connect(self.updateAvailableSources) self._avail_src_timer.start(config["SOURCE_AVAIL_UPDATE_TIMER"]) self._process_mon_timer = QTimer() self._process_mon_timer.timeout.connect(self.updateProcessInfo) self._process_mon_timer.start(config["PROCESS_MONITOR_UPDATE_TIMER"]) def initUI(self): """Override.""" self._monitor_tb.setTabPosition(QTabWidget.TabPosition.South) self._monitor_tb.addTab(self._avail_src_view, "Source monitor") self._monitor_tb.addTab(self._process_mon_view, "Process monitor") splitter = QSplitter(Qt.Vertical) splitter.setHandleWidth(self.SPLITTER_HANDLE_WIDTH) splitter.setChildrenCollapsible(False) splitter.addWidget(self._con_view) splitter.addWidget(self._src_view) splitter.addWidget(self._monitor_tb) splitter.setStretchFactor(0, 3) splitter.setStretchFactor(1, 1) h = splitter.sizeHint().height() splitter.setSizes([0.1 * h, 0.6 * h, 0.3 * h]) layout = QVBoxLayout() layout.addWidget(splitter) self.setLayout(layout) self._con_view.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self._src_view.setIndentation(self._src_view.indentation()/2) self._src_view.expandToDepth(1) for i in range(4): self._src_view.resizeColumnToContents(i) for i in range(2): self._src_view.header().setSectionResizeMode( i, QHeaderView.Fixed) def initConnections(self): """Override.""" mediator = self._mediator mediator.file_stream_initialized_sgn.connect(self.updateMetaData) def updateMetaData(self): """Override.""" try: cons = self._con_model.connections() self._mediator.onBridgeConnectionsChange(cons) except ValueError as e: logger.error(e) return False return True def loadMetaData(self): """Override.""" pass def updateAvailableSources(self): ret = self._mon.get_available_sources() if ret is not None: raw, matched = ret self._avail_src_model.setupModelData(raw) self._src_tree_model.updateMatchedSources(matched) def updateProcessInfo(self): info = [] for p in list_foam_processes(): info.append(list(p)) self._process_mon_model.setupModelData(info)
class TreeView(QWidget): def __init__(self, table, parent): QWidget.__init__(self, parent) self.window = parent self.tree = QTreeView(self) indent = self.tree.indentation() self.tree.setIndentation(indent / 2) self.model = DataModel(table) self.sorter = sorter = FilterModel(self) sorter.setSourceModel(self.model) self.tree.setModel(sorter) for col in range(3, 9): self.tree.setItemDelegateForColumn(col, PercentDelegate(self)) self.tree.header().setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tree.header().customContextMenuRequested.connect( self._on_header_menu) self.tree.setSortingEnabled(True) self.tree.setAutoExpandDelay(0) self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(NAME_COLUMN) self.tree.expand(self.sorter.index(0, 0)) #self.tree.expandAll() self.tree.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tree.customContextMenuRequested.connect(self._on_tree_menu) searchbox = QHBoxLayout() self.search = QLineEdit(self) searchbox.addWidget(self.search) self.search_type = QComboBox(self) self.search_type.addItem("Contains", SEARCH_CONTAINS) self.search_type.addItem("Exact", SEARCH_EXACT) self.search_type.addItem("Reg.Exp", SEARCH_REGEXP) searchbox.addWidget(self.search_type) btn = QPushButton("&Search", self) searchbox.addWidget(btn) btn.clicked.connect(self._on_search) btn = QPushButton("&Next", self) searchbox.addWidget(btn) btn.clicked.connect(self._on_search_next) filterbox = QHBoxLayout() label = QLabel("Time Individual", self) filterbox.addWidget(label) self.individual_time = QSpinBox(self) self.individual_time.setMinimum(0) self.individual_time.setMaximum(100) self.individual_time.setSuffix(" %") filterbox.addWidget(self.individual_time) label = QLabel("Alloc Individual", self) filterbox.addWidget(label) self.individual_alloc = QSpinBox(self) self.individual_alloc.setMinimum(0) self.individual_alloc.setMaximum(100) self.individual_alloc.setSuffix(" %") filterbox.addWidget(self.individual_alloc) label = QLabel("Time Inherited", self) filterbox.addWidget(label) self.inherited_time = QSpinBox(self) self.inherited_time.setMinimum(0) self.inherited_time.setMaximum(100) self.inherited_time.setSuffix(" %") filterbox.addWidget(self.inherited_time) label = QLabel("Alloc Inherited", self) filterbox.addWidget(label) self.inherited_alloc = QSpinBox(self) self.inherited_alloc.setMinimum(0) self.inherited_alloc.setMaximum(100) self.inherited_alloc.setSuffix(" %") filterbox.addWidget(self.inherited_alloc) btn = QPushButton("&Filter", self) btn.clicked.connect(self._on_filter) filterbox.addWidget(btn) btn = QPushButton("&Reset", self) filterbox.addWidget(btn) btn.clicked.connect(self._on_reset_filter) vbox = QVBoxLayout() vbox.addLayout(searchbox) vbox.addLayout(filterbox) vbox.addWidget(self.tree) self.setLayout(vbox) self._search_idxs = None self._search_idx_no = 0 def _expand_to(self, idx): idxs = [idx] parent = idx while parent and parent.isValid(): parent = self.sorter.parent(parent) idxs.append(parent) #print(idxs) for idx in reversed(idxs[:-1]): data = self.sorter.data(idx, QtCore.Qt.DisplayRole) #print(data) self.tree.expand(idx) def _on_search(self): text = self.search.text() selected = self.tree.selectedIndexes() # if selected: # start = selected[0] # else: start = self.sorter.index(0, NAME_COLUMN) search_type = self.search_type.currentData() if search_type == SEARCH_EXACT: method = QtCore.Qt.MatchFixedString elif search_type == SEARCH_CONTAINS: method = QtCore.Qt.MatchContains else: method = QtCore.Qt.MatchRegExp self._search_idxs = idxs = self.sorter.search(start, text, search_type) if idxs: self.window.statusBar().showMessage( "Found: {} occurence(s)".format(len(idxs))) self._search_idx_no = 0 idx = idxs[0] self._locate(idx) else: self.window.statusBar().showMessage("Not found") def _locate(self, idx): self.tree.resizeColumnToContents(0) self.tree.resizeColumnToContents(NAME_COLUMN) self._expand_to(idx) self.tree.setCurrentIndex(idx) #self.tree.selectionModel().select(idx, QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Current | QItemSelectionModel.Rows) #self.tree.scrollTo(idx, QAbstractItemView.PositionAtCenter) def _on_search_next(self): if self._search_idxs: n = len(self._search_idxs) self._search_idx_no = (self._search_idx_no + 1) % n idx = self._search_idxs[self._search_idx_no] self.window.statusBar().showMessage("Occurence {} of {}".format( self._search_idx_no, n)) self._locate(idx) else: self.window.statusBar().showMessage("No search results") def _on_filter(self): self.sorter.setFilter(self.search.text(), self.individual_time.value(), self.individual_alloc.value(), self.inherited_time.value(), self.inherited_alloc.value()) def _on_reset_filter(self): self.sorter.reset() def _on_header_menu(self, pos): menu = make_header_menu(self.tree) menu.exec_(self.mapToGlobal(pos)) def _on_tree_menu(self, pos): index = self.tree.indexAt(pos) #print("index: {}".format(index)) if index.isValid(): record = self.sorter.data(index, QtCore.Qt.UserRole + 1) #print("okay?..") #print("context: {}".format(record)) menu = self.window.make_item_menu(self.model, record) menu.exec_(self.tree.viewport().mapToGlobal(pos))