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 DataSourceWidget(_AbstractCtrlWidget): """DataSourceWidget class. Widgets provide data source management and monitoring. """ _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_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_device_delegate) self._src_view.setItemDelegateForColumn(1, self._src_ppt_delegate) self._src_view.setItemDelegateForColumn(2, self._src_slicer_delegate) self._src_view.setItemDelegateForColumn(3, 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._avail_src_timer = QTimer() self._avail_src_timer.timeout.connect(self.updateSourceList) 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, "Available sources") 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.expandToDepth(1) self._src_view.resizeColumnToContents(0) self._src_view.resizeColumnToContents(1) 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 updateSourceList(self): available_sources = self._mon.get_available_sources() if available_sources is not None: # for unittest self._avail_src_model.setupModelData(list( available_sources.keys())) def updateProcessInfo(self): info = [] for p in list_foam_processes(): info.append(list(p)) self._process_mon_model.setupModelData(info)
class DanaBrowseWindow(QMainWindow): def __init__(self, args): super(DanaBrowseWindow, self).__init__() #Leeo la configuracion self.configFile = args.configFile self.secure = args.secure self.cubeFile = args.cubeFile self.sysExclude = args.sysExclude self.maxLevel = 1 #para poder modificarlo luego self.dictionary = DataDict(defFile=args.configFile, secure=args.secure, sysExclude=args.sysExclude) #TODO variables asociadas del diccionario. Reevaluar al limpiar self.baseModel = self.dictionary.baseModel self.configData = self.dictionary.configData self.conn = self.dictionary.conn if self.dictionary.isEmpty: self.newConfigData() #self.dictionary._cargaModelo(self.dictionary.baseModel) self.setupView() self.cubeMgr = None # necesito mas adelante que este definida if config.DEBUG: print('inicializacion completa') #CHANGE here self.queryView = TableBrowse(None) self.dictMenu = self.menuBar().addMenu("&Conexiones") self.dictMenu.addAction("&New ...", self.newConnection, "Ctrl+N") self.dictMenu.addAction("&Modify ...", self.modConnection, "Ctrl+M") self.dictMenu.addAction("&Delete ...", self.delConnection, "Ctrl+D") self.dictMenu.addAction("&Save Config File", self.saveConfigFile, "Ctrl+S") self.dictMenu.addAction("E&xit", self.close, "Ctrl+Q") self.queryMenu = self.menuBar().addMenu('Consulta de &datos') self.queryMenu.addAction("Cerrar", self.hideDatabrowse) self.queryMenu.setEnabled(False) self.cubeMenu = self.menuBar().addMenu("C&ubo") self.cubeMenu.addAction("&Salvar", self.saveCubeFile, "Ctrl+S") #self.cubeMenu.addAction("&Restaurar", self.restoreCubeFile, "Ctrl+M") self.cubeMenu.addAction("S&alir", self.hideCube, "Ctrl+C") self.cubeMenu.addSeparator() self.cubeMenu.addAction("Ver &ejemplo de datos del cubo", self.previewCube, "Ctrl+E") self.cubeMenu.setEnabled(False) #self.queryModel = self.queryView.baseModel self.querySplitter = QSplitter(Qt.Vertical) self.querySplitter.addWidget(self.view) #self.querySplitter.addWidget(self.queryView) self.configSplitter = QSplitter(Qt.Horizontal) self.configSplitter.addWidget(self.querySplitter) self.setCentralWidget(self.configSplitter) self.setWindowTitle("Visualizador de base de datos") """ estas funciones son para soportar para los decoradores keep position y tal """ def model(self): return self.baseModel def isExpanded(self, idx): return self.view.isExpanded(idx) def setExpanded(self, idx, state): return self.view.setExpanded(idx, state) def setupView(self): self.view = QTreeView(self) self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect(self.openContextMenu) self.view.doubleClicked.connect(self.test) self.view.setModel(self.baseModel) #self.view.resizeColumnToContents(0) self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) self.view.expandAll() for m in range(self.baseModel.columnCount()): self.view.resizeColumnToContents(m) self.view.collapseAll() self.view.expandToDepth(0) #self.view.setHeaderHidden(True) #self.view.setSortingEnabled(True) #self.view.setRootIsDecorated(False) self.view.setAlternatingRowColors(True) #self.view.sortByColumn(0, Qt.AscendingOrder) def newConfigData(self): self.configData = dict() self.configData['Conexiones'] = dict() self.editConnection(None) if self.configData['Conexiones']: self.saveConfigFile() print(self.configData) self.dictionary._cargaModelo(confData=self.configData['Conexiones'] ) #self.dictionary.baseModel) else: QMessageBox.critical( self, "Error Fatal", "No se ha encontrado una conexión valida.\nFin de proceso") self.close() def saveConfigFile(self): dump_config(self.configData, getConfigFileName(self.configFile), secure=self.secure) #TODO de momento def closeEvent(self, event): self.close() def close(self): if self.cubeMgr: self.saveConfigFile() for conid in self.conn: if self.conn[conid] is None: continue if self.conn[conid].closed: self.conn[conid].close() self.saveConfigFile() sys.exit() def newConnection(self): confName = self.editConnection(None) # esta claro que sobran parametros self.dictionary.appendConnection(confName) def modConnection(self, nombre=None): if nombre is None: selDialog = SelectConnectionDlg(self.configData['Conexiones']) if selDialog.exec_(): confName = selDialog.conexion else: return else: confName = nombre self.editConnection(confName) self.updateModel(confName) @waiting_effects def updateModel(self, nombre=None): self.dictionary.updateModel(nombre) def delConnection(self, nombre=None): if nombre is None: selDialog = SelectConnectionDlg(self.configData['Conexiones']) if selDialog.exec_(): confName = selDialog.conexion else: return else: confName = nombre self.dictionary.dropConnection(confName) def editConnection(self, nombre=None): attr_list = ('driver', 'dbname', 'dbhost', 'dbuser', 'dbpass', 'dbport', 'debug') if nombre is None: datos = [None for k in range(len(attr_list) + 1)] else: datos = [ nombre, ] + dict2row(self.configData['Conexiones'][nombre], attr_list) datos[1] = DRIVERS.index(datos[1]) #contexto context = ( ( 'Nombre', QLineEdit, { 'setReadOnly': True } if nombre is not None else None, None, ), # driver ( "Driver ", QComboBox, None, DRIVERS, ), ( "DataBase Name", QLineEdit, None, None, ), ( "Host", QLineEdit, None, None, ), ( "User", QLineEdit, None, None, ), ( "Password", QLineEdit, { 'setEchoMode': QLineEdit.Password }, None, ), ( "Port", QLineEdit, None, None, ), ( "Debug", QCheckBox, None, None, )) parmDialog = ConnectionSheetDlg('Edite la conexion', context, datos, self) if parmDialog.exec_(): #TODO deberia verificar que se han cambiado los datos #datos[1]=DRIVERS[datos[1]] self.configData['Conexiones'][datos[0]] = row2dict( datos[1:], attr_list) return datos[0] @keep_tree_layout() def openContextMenu(self, position): """ """ item = None indexes = self.view.selectedIndexes() if len(indexes) > 0: index = indexes[0] item = self.baseModel.itemFromIndex(index) menu = QMenu() if item: item.setMenuActions(menu, self) action = menu.exec_(self.view.viewport().mapToGlobal(position)) #getContextMenu(item,action,self) @waiting_effects def databrowse(self, confName, schema, table, iters=0): #print(confName,schema,table,self.dictionary.conn[confName]) self.queryView.reconnect( self.queryView.getConnection(self.dictionary, confName, schema, table, iters)) self.queryView.executeNewScript( self.queryView.generateSQL(confName, schema, table, iters, pFilter=None)) if self.queryView.isHidden(): self.queryView.show() self.queryMenu.setEnabled(True) if self.querySplitter.count( ) == 1: #de momento parece un modo sencillo de no multiplicar en exceso self.querySplitter.addWidget(self.queryView) def hideDatabrowse(self): self.queryView.hide() self.queryMenu.setEnabled(False) def prepareNewCube(self, confName, schema, table): # aqui tiene que venir un dialogo para seleccionar nombre del cubo maxLevel = self.maxLevel parmDlg = GenerationSheetDlg('Parámetros de generación', table, maxLevel) if parmDlg.exec_(): kname = parmDlg.data[0] maxLevel = parmDlg.data[1] infox = info2cube(self.dictionary, confName, schema, table, maxLevel) if kname != table: infox[kname] = infox.pop(table) return infox def cubebrowse(self, confName, schema, table): infox = self.prepareNewCube(confName, schema, table) if self.cubeMgr and not self.cubeMgr.isHidden(): self.hideCube() self.cubeMgr = CubeMgr(self, confName, schema, table, self.dictionary, rawCube=infox, cubeFile=self.cubeFile) self.cubeMgr.expandToDepth(1) #if self.configSplitter.count() == 1: #de momento parece un modo sencillo de no multiplicar en exceso self.configSplitter.addWidget(self.cubeMgr) self.cubeMgr.show() self.cubeMenu.setEnabled(True) def saveCubeFile(self): self.cubeMgr.saveCubeFile() def restoreCubeFile(self): self.cubeMgr.restoreConfigFile() def hideCube(self): self.cubeMgr.saveCubeFile() self.cubeMgr.hide() self.cubeMenu.setEnabled(False) def test(self, index): return print(index.row(), index.column()) item = self.baseModel.itemFromIndex(index) print(item.text(), item.model()) def refreshTable(self): self.baseModel.emitModelReset() def previewCube(self): startItem = self.cubeMgr.model().item(0, 0) conName = self.cubeMgr.defaultConnection self.queryView.reconnect( self.queryView.getConnection(self.dictionary, confName=conName)) query = self.cubeMgr.getPreviewQuery(startItem) self.queryView.executeNewScript(query) if self.queryView.isHidden(): self.queryView.show() self.queryMenu.setEnabled(True) if self.querySplitter.count( ) == 1: #de momento parece un modo sencillo de no multiplicar en exceso self.querySplitter.addWidget(self.queryView)