def initUI(self): # bottom left frame (hosts) hostsArea = QFrame(self) self.hostTable = hostsTable.hostsTable() # bottom right frame (KPIs) self.kpisTable = kpiTable.kpiTable() kpisTable = self.kpisTable # top (main chart area) self.chartArea = chartArea.chartArea() # establish hard links: kpisTable.kpiScales = self.chartArea.widget.nscales self.chartArea.widget.hosts = self.hostTable.hosts kpisTable.hosts = self.chartArea.widget.hosts #why do we have hosts inside widget? because we have all data there... kpisTable.hostKPIs = self.chartArea.hostKPIs kpisTable.srvcKPIs = self.chartArea.srvcKPIs kpisTable.nkpis = self.chartArea.widget.nkpis # bottm part left+right kpiSplitter = QSplitter(Qt.Horizontal) kpiSplitter.addWidget(self.hostTable) kpiSplitter.addWidget(kpisTable) kpiSplitter.setSizes([200, 380]) self.tabs = QTabWidget() console = sqlConsole.sqlConsole() # main window splitter mainSplitter = QSplitter(Qt.Vertical) kpisWidget = QWidget() lo = QVBoxLayout(kpisWidget) lo.addWidget(kpiSplitter) mainSplitter.addWidget(self.chartArea) mainSplitter.addWidget(kpisWidget) mainSplitter.setSizes([300, 90]) mainSplitter.setAutoFillBackground(True) # central widget #self.setCentralWidget(mainSplitter) kpisWidget.autoFillBackground = True self.tabs.addTab(mainSplitter, 'Chart') if cfg('experimental-notnow'): self.tabs.addTab(console, 'Sql') self.setCentralWidget(self.tabs) # service stuff self.statusbar = self.statusBar() #menu iconPath = resourcePath('ico\\favicon.ico') exitAct = QAction('&Exit', self) exitAct.setShortcut('Alt+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(self.menuQuit) aboutAct = QAction(QIcon(iconPath), '&About', self) aboutAct.setStatusTip('About this app') aboutAct.triggered.connect(self.menuAbout) dummyAct = QAction('&Dummy', self) dummyAct.setShortcut('Alt+D') dummyAct.setStatusTip('Dummy Data provider') dummyAct.triggered.connect(self.menuDummy) configAct = QAction('&Connect', self) configAct.setShortcut('Alt+C') configAct.setStatusTip('Configure connection') configAct.triggered.connect(self.menuConfig) importAct = QAction('&Import', self) importAct.setShortcut('Ctrl+I') importAct.setStatusTip('Import nameserver.trc') importAct.triggered.connect(self.menuImport) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(aboutAct) fileMenu.addAction(configAct) if cfg('experimental'): fileMenu.addAction(importAct) fileMenu.addAction(dummyAct) fileMenu.addAction(exitAct) if cfg('experimental'): actionsMenu = menubar.addMenu('&Actions') fileMenu.addAction(aboutAct) fontAct = QAction('&Adjust Fonts', self) fontAct.setStatusTip('Adjust margins after font change (for example after move to secondary screen)') fontAct.triggered.connect(self.menuFont) reloadConfigAct = QAction('Reload &Config', self) reloadConfigAct.setStatusTip('Reload configuration file. Note: some values used during the connect or other one-time-actions') reloadConfigAct.triggered.connect(self.menuReloadConfig) actionsMenu.addAction(fontAct) actionsMenu.addAction(reloadConfigAct) reloadCustomKPIsAct = QAction('Reload Custom &KPIs', self) reloadCustomKPIsAct.setStatusTip('Reload definition of custom KPIs') reloadCustomKPIsAct.triggered.connect(self.menuReloadCustomKPIs) actionsMenu.addAction(reloadCustomKPIsAct) # finalization self.setGeometry(200, 200, 1400, 800) #self.setWindowTitle('SAP HANA Studio Light') # self.setWindowTitle('HANA Army Knife') self.setWindowTitle('Ryba Fish Charts') self.setWindowIcon(QIcon(iconPath)) self.show() ''' set up some interactions ''' # bind kpi checkbox signal kpisTable.checkboxToggle.connect(self.chartArea.checkboxToggle) # bind change scales signal kpisTable.adjustScale.connect(self.chartArea.adjustScale) kpisTable.setScale.connect(self.chartArea.setScale) # host table row change signal self.hostTable.hostChanged.connect(kpisTable.refill) # to fill hosts self.chartArea.hostsUpdated.connect(self.hostTable.hostsUpdated) # refresh self.chartArea.kpiToggled.connect(kpisTable.refill) # update scales signal self.chartArea.scalesUpdated.connect(kpisTable.updateScales) self.chartArea.scalesUpdated.emit() # it really not supposed to have any to update here #bind statusbox updating signals self.chartArea.statusMessage_.connect(self.statusMessage) self.chartArea.widget.statusMessage_.connect(self.statusMessage) self.chartArea.connected.connect(self.setTabName) log('init finish()') if self.chartArea.dp: self.chartArea.initDP()
class UI_mainWindow(QMainWindow): __tlvInfoGB_ = None __tlvPkgListGB_ = None __videoGB_ = None __videoLabel_ = None __audioGB_ = None __audioLabel_ = None __menubar_ = None __winResolution_ = (1280, 720) def __init__(self): super().__init__() # self.setWindowFlag(Qt.FramelessWindowHint) self.__vsplitter_ = QSplitter(Qt.Vertical) self.__vsplitter_.setChildrenCollapsible(False) # 拉动分割器至最小,被分割部分不会消失 self.__vsplitter_.setAutoFillBackground(True) # 分割器随主窗口大小自适应变化 self.__hsplitter_ = QSplitter(Qt.Horizontal) self.__hsplitter_.setChildrenCollapsible(False) self.__hsplitter_.setAutoFillBackground(True) self.__initTlvInfoLayout() self.__initVideoLayout() self.__initAudioLayout() self.__initTlvPkgListLayout() self.__initMainWindow() def __initMainWindow(self): availGeometry = QDesktopWidget().availableGeometry() self.resize(availGeometry.width() * 0.7, availGeometry.height() * 0.7) self.__center() self.__menubar_ = UIMenuBar() self.setMenuBar(self.__menubar_) self.setCentralWidget(self.__hsplitter_) self.setWindowTitle('tlv分析工具') def __center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def __initTlvInfoLayout(self): tlvinfo = UITlvInfo('TLV INFO') tlvinfo.setMinimumWidth(250) self.__hsplitter_.addWidget(tlvinfo) def __initTlvPkgListLayout(self): self.__tlvpkglist_ = UITlvPkgList('Tlv Pkg List') for i in range(30): pkg_level = UITlvPkgList.PKG_LEVEL.NORMAL if i % 10 == 0: pkg_level = UITlvPkgList.PKG_LEVEL.LOSS elif i % 11 == 0: pkg_level = UITlvPkgList.PKG_LEVEL.ORDER self.__tlvpkglist_.insertTlvPkgItem( "H264 RTP Header #{:<10d}".format(i), '''this is an example! this is an apple! this is a banana! this is a pen! end''', pkg_level) self.__hsplitter_.addWidget(self.__tlvpkglist_) def __initVideoLayout(self): label = UIVideoLabel() label.setMinimumSize(640, 480) hlayout = QHBoxLayout() hlayout.addStretch(1) hlayout.addWidget(label) hlayout.addStretch(1) vlayout = QVBoxLayout() # vlayout.addStretch(1) vlayout.addLayout(hlayout) # vlayout.addStretch(1) video = QGroupBox("Video Replay") video.setLayout(vlayout) self.__vsplitter_.addWidget(video) def __initAudioLayout(self): hlayout = QHBoxLayout() hlayout.addStretch(1) hlayout.addWidget(QLabel('Audio Replay')) hlayout.addStretch(1) audio = QGroupBox("Audio Replay") audio.setLayout(hlayout) self.__vsplitter_.addWidget(audio) self.__vsplitter_.setSizes([420, 300]) self.__hsplitter_.addWidget(self.__vsplitter_)
class ChartWidget(QWidget): def __init__(self, *args, **kwargs): super(ChartWidget, self).__init__(*args, **kwargs) self.resize(800, 600) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self.splitter = QSplitter(self) layout.addWidget(self.splitter) self.splitter.setOrientation(Qt.Horizontal) self.splitter.setStretchFactor(0, 2) self.splitter.setStretchFactor(1, 3) self.splitter.setStretchFactor(2, 5) self.splitter.setAutoFillBackground(True) self.splitter.setChildrenCollapsible(False) self.splitter.setHandleWidth(2) # 分类 self.classifyWidget = ClassifyWidget(self) self.splitter.addWidget(self.classifyWidget) # 代码 self.codeWidget = CodeWidget(self) self.splitter.addWidget(self.codeWidget) # 等待界面 self.loadingWidget = LoadingWidget(self, visible=False) self.loadingWidget.resize(self.size()) # 绑定信号槽 self.classifyWidget.fileSelected.connect(self.codeWidget.openFile) self.codeWidget.runSignal.connect(self.onRun) def onRun(self, text): self.setEnabled(False) self.loadingWidget.show() # 解析json生成view并添加 if hasattr(self, "previewView"): # 删除旧view self.previewView.setParent(None) self.previewView.setVisible(False) self.previewView.hide() self.previewView.deleteLater() del self.previewView self.previewView = self.getChartView(text) if isinstance(self.previewView, QChartView): self.splitter.addWidget(self.previewView) else: QMessageBox.warning(self, "提示", self.previewView) del self.previewView self.setEnabled(True) self.loadingWidget.close() def getChartView(self, text): try: return ChartView(text) except Exception as e: return str(e) def resizeEvent(self, event): super(ChartWidget, self).resizeEvent(event) self.loadingWidget.resize(self.size()) def closeEvent(self, event): self.loadingWidget.close() self.loadingWidget.deleteLater() del self.loadingWidget super(ChartWidget, self).closeEvent(event)
class hslWindow(QMainWindow): statusbar = None connectionConf = None kpisTable = None def __init__(self): self.layoutDumped = False self.sqlTabCounter = 0 #static tab counter self.tabs = None super().__init__() self.initUI() # def tabChanged(self, newidx): def closeTab(self): indx = self.tabs.currentIndex() if indx > 0: #print need a better way to identify sql consoles... cons = self.tabs.currentWidget() cons.delayBackup() status = cons.close() if status == True: self.statusbar.removeWidget(cons.indicator) self.tabs.removeTab(indx) def keyPressEvent(self, event): #log('window keypress: %s' % (str(event.key()))) modifiers = event.modifiers() if (modifiers == Qt.ControlModifier and event.key() == 82) or event.key() == Qt.Key_F5: log('reload request!') self.chartArea.reloadChart() elif modifiers == Qt.ControlModifier and event.key() == Qt.Key_W: self.closeTab() else: super().keyPressEvent(event) def statusMessage(self, message, repaint): if not self.statusbar: log('self.statusbar.showMessage(' '%s' ')' % (message)) else: self.statusbar.showMessage(message) if repaint: self.repaint() def closeEvent(self, event): log('Exiting...') if cfg('saveLayout', True): self.dumpLayout() ''' for i in range(self.tabs.count() -1, 0, -1): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): w.delayBackup() status = w.close(False) # can not abort clipboard = QApplication.clipboard() event = QEvent(QEvent.Clipboard) QApplication.sendEvent(clipboard, event) ''' def dumpLayout(self): if self.layoutDumped: return if self.layout is None: return self.layoutDumped = True kpis = {} for i in range(len(self.chartArea.widget.hosts)): host = self.chartArea.widget.hosts[i] hst = '%s:%s' % (host['host'], host['port']) if i < len(self.chartArea.widget.nkpis ) and self.chartArea.widget.nkpis[i]: kpis[hst] = self.chartArea.widget.nkpis[i] if kpis: self.layout['kpis'] = kpis else: if 'kpis' in self.layout.lo: del self.layout.lo['kpis'] self.layout['pos'] = [self.pos().x(), self.pos().y()] self.layout['size'] = [self.size().width(), self.size().height()] self.layout['mainSplitter'] = self.mainSplitter.sizes() self.layout['kpiSplitter'] = self.kpiSplitter.sizes() hostTableWidth = [] KPIsTableWidth = [] for i in range(self.hostTable.columnCount()): hostTableWidth.append(self.hostTable.columnWidth(i)) for i in range(self.kpisTable.columnCount()): KPIsTableWidth.append(self.kpisTable.columnWidth(i)) self.layout['hostTableWidth'] = hostTableWidth self.layout['KPIsTableWidth'] = KPIsTableWidth # print(self.pos().x(), self.pos().y()) tabs = [] self.layout['currentTab'] = self.tabs.currentIndex() if cfg('saveOpenTabs', True): for i in range(self.tabs.count() - 1, 0, -1): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): w.delayBackup() if w.fileName is not None or w.backup is not None: pos = w.cons.textCursor().position() block = w.cons.edit.verticalScrollBar().value() #print('scroll position:', block) #block = w.cons.firstVisibleBlock().position() if w.backup: bkp = os.path.abspath(w.backup) else: bkp = None tabs.append([w.fileName, bkp, pos, block]) #tabs.append([w.fileName, bkp, pos]) w.close(None) # can not abort (and dont need to any more!) self.tabs.removeTab(i) tabs.reverse() if len(tabs) > 0: self.layout['tabs'] = tabs else: if 'tabs' in self.layout.lo: self.layout.lo.pop('tabs') if 'running' in self.layout.lo: self.layout.lo.pop('running') self.layout.dump() def menuQuit(self): ''' for i in range(self.tabs.count() -1, 0, -1): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): status = w.close(True) # can abort if status == True: self.tabs.removeTab(i) if status == False: return ''' if cfg('saveLayout', True): self.dumpLayout() self.close() def menuReloadCustomKPIs(self): kpiStylesNN = kpiDescriptions.kpiStylesNN for type in ('host', 'service'): for kpiName in list(kpiStylesNN[type]): kpi = kpiStylesNN[type][kpiName] if kpi['sql'] is not None: del (kpiStylesNN[type][kpiName]) if type == 'host': self.chartArea.hostKPIs.remove(kpiName) else: self.chartArea.srvcKPIs.remove(kpiName) # del host custom groups kpis_len = len(self.chartArea.hostKPIs) i = 0 while i < kpis_len: if self.chartArea.hostKPIs[i][:1] == '.' and ( i == len(self.chartArea.hostKPIs) - 1 or self.chartArea.hostKPIs[i + 1][:1] == '.'): del (self.chartArea.hostKPIs[i]) kpis_len -= 1 else: i += 1 # del service custom groups kpis_len = len(self.chartArea.srvcKPIs) i = 0 while i < kpis_len: if self.chartArea.srvcKPIs[i][:1] == '.' and ( i == len(self.chartArea.srvcKPIs) - 1 or self.chartArea.srvcKPIs[i + 1][:1] == '.'): del (self.chartArea.srvcKPIs[i]) kpis_len -= 1 else: i += 1 try: dpDBCustom.scanKPIsN(self.chartArea.hostKPIs, self.chartArea.srvcKPIs, kpiStylesNN) except Exception as e: self.chartArea.disableDeadKPIs() msgDialog( 'Custom KPIs Error', 'There were errors during custom KPIs load. Load of the custom KPIs STOPPED because of that.\n\n' + str(e)) self.chartArea.widget.initPens() self.chartArea.widget.update() #really unsure if this one can be called twice... kpiDescriptions.clarifyGroups() #trigger refill self.kpisTable.refill(self.hostTable.currentRow()) self.statusMessage('Custom KPIs reload finish', False) def menuReloadConfig(self): loadConfig() self.statusMessage('Configuration file reloaded.', False) def menuFont(self): id = QInputDialog sf = cfg('fontScale', 1) sf, ok = id.getDouble(self, 'Input the scaling factor', 'Scaling Factor', sf, 0, 5, 2) if ok: self.chartArea.widget.calculateMargins(sf) self.chartArea.adjustScale(sf) def menuAbout(self): abt = aboutDialog.About() abt.exec_() def menuConfHelp(self): QDesktopServices.openUrl(QUrl('https://www.rybafish.net/config')) def menuCustomConfHelp(self): QDesktopServices.openUrl(QUrl('https://www.rybafish.net/customKPI')) def menuTips(self): QDesktopServices.openUrl(QUrl('https://www.rybafish.net/tips')) def menuDummy(self): self.chartArea.dp = dpDummy.dataProvider() # generated data if cfg('saveKPIs', True): self.chartArea.initDP(self.layout['kpis']) else: self.chartArea.initDP() def menuConfig(self): if self.connectionConf is None: connConf = cfg('server') else: connConf = self.connectionConf conf, ok = configDialog.Config.getConfig(connConf, self) if ok: self.connectionConf = conf if ok and conf['ok']: try: # need to disconnect open consoles first... self.statusMessage('Disconnecing open consoles...', False) for i in range(self.tabs.count()): w = self.tabs.widget(i) if isinstance( w, sqlConsole.sqlConsole) and w.conn is not None: log('closing connection...') w.disconnectDB() w.indicator.status = 'disconnected' w.indicator.repaint() log('disconnected...') self.statusMessage('Connecting...', False) self.repaint() self.chartArea.setStatus('sync', True) self.chartArea.dp = dpDB.dataProvider(conf) # db data provider self.chartArea.setStatus('idle') for i in range(self.tabs.count()): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): w.config = conf if cfg('saveKPIs', True): if self.layout and 'kpis' in self.layout.lo: self.chartArea.initDP(self.layout['kpis']) else: self.chartArea.initDP() starttime = datetime.datetime.now() - datetime.timedelta( seconds=12 * 3600) starttime -= datetime.timedelta( seconds=starttime.timestamp() % 3600) self.chartArea.fromEdit.setText( starttime.strftime('%Y-%m-%d %H:%M:%S')) self.chartArea.toEdit.setText('') else: self.chartArea.initDP() if hasattr(self.chartArea.dp, 'dbProperties'): self.chartArea.widget.timeZoneDelta = self.chartArea.dp.dbProperties[ 'timeZoneDelta'] self.chartArea.reloadChart() propStr = conf['user'] + '@' + self.chartArea.dp.dbProperties[ 'sid'] self.tabs.setTabText(0, propStr) self.setWindowTitle('RybaFish Charts [%s]' % propStr) #setup keep alives if cfg('keepalive'): try: keepalive = int(cfg('keepalive')) self.chartArea.dp.enableKeepAlive(self, keepalive) except: log('wrong keepalive setting: %s' % (cfg('keepalive'))) except dbException as e: log('Connect or init error:') if hasattr(e, 'message'): log(e.message) else: log(e) msgBox = QMessageBox() msgBox.setWindowTitle('Connection error') msgBox.setText('Connection failed: %s ' % (str(e))) iconPath = resourcePath('ico\\favicon.ico') msgBox.setWindowIcon(QIcon(iconPath)) msgBox.setIcon(QMessageBox.Warning) msgBox.exec_() self.statusMessage('', False) except Exception as e: log('Init exception not related to DB') log(str(e)) msgBox = QMessageBox() msgBox.setWindowTitle('Error') msgBox.setText( 'Init failed: %s \n\nSee more deteails in the log file.' % (str(e))) iconPath = resourcePath('ico\\favicon.ico') msgBox.setWindowIcon(QIcon(iconPath)) msgBox.setIcon(QMessageBox.Warning) msgBox.exec_() self.statusMessage('', False) else: # cancel or parsing error if ok and conf[ 'ok'] == False: #it's connection string dict in case of [Cancel] msgBox = QMessageBox() msgBox.setWindowTitle('Connection string') msgBox.setText( 'Could not start the connection. Please check the connection string: host, port, etc.' ) iconPath = resourcePath('ico\\favicon.ico') msgBox.setWindowIcon(QIcon(iconPath)) msgBox.setIcon(QMessageBox.Warning) msgBox.exec_() self.statusMessage('', False) def changeActiveTabName(self, name): i = self.tabs.currentIndex() # must be a better way verity if we attempt to update chart tab name if i == 0: return self.tabs.setTabText(i, name) def menuSave(self): indx = self.tabs.currentIndex() w = self.tabs.widget(indx) if not isinstance(w, sqlConsole.sqlConsole): return w.delayBackup() w.saveFile() def menuOpen(self): ''' so much duplicate code with menuSqlConsole and with dumpLayout! ''' fname = QFileDialog.getOpenFileNames(self, 'Open file', '', '*.sql') openfiles = {} for i in range(self.tabs.count()): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): fn = w.fileName if fn is not None: openfiles[fn] = i for filename in fname[0]: if filename in openfiles: # the file is already open idx = openfiles[filename] self.tabs.setCurrentIndex(idx) continue conf = self.connectionConf self.statusMessage('Connecting console...', True) try: console = sqlConsole.sqlConsole(self, conf, 'sqlopen') except: self.statusMessage('Failed', True) log('[!] error creating console for the file') return self.statusMessage('', False) console.nameChanged.connect(self.changeActiveTabName) console.cons.closeSignal.connect(self.closeTab) self.tabs.addTab(console, console.tabname) console.selfRaise.connect(self.raiseTab) ind = indicator() console.indicator = ind ind.iClicked.connect(console.reportRuntime) self.statusbar.addPermanentWidget(ind) self.tabs.setCurrentIndex(self.tabs.count() - 1) console.openFile(filename) if self.layout == None: # no backups to avoid conflicts... console.noBackup = True #def populateConsoleTab(self): def menuSQLConsole(self): conf = self.connectionConf if conf is None: self.statusMessage('No configuration...', False) return self.statusMessage('Connecting...', True) ind = indicator() self.statusbar.addPermanentWidget(ind) ind.status = 'sync' ind.repaint() log('menuSQLConsole...') noname = True while noname: self.sqlTabCounter += 1 idx = self.sqlTabCounter if idx > 1: tname = 'sql' + str(idx) else: tname = 'sql' for i in range(self.tabs.count() - 1, 0, -1): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): if w.tabname == tname or w.tabname == tname + ' *': # so not nice... break else: noname = False # console = sqlConsole.sqlConsole(self, conf, tname) # self = window try: console = sqlConsole.sqlConsole(self, conf, tname) # self = window log('seems connected...') except dbException as e: log('[!] failed to open console expectedly') self.statusMessage('Connection error', True) self.statusbar.removeWidget(ind) return ''' except Exception as e: log('[!] failed to open console unexpectedly: ' + str(e)) self.statusMessage('Connection error?', True) return ''' console.indicator = ind ind.iClicked.connect(console.reportRuntime) console.nameChanged.connect(self.changeActiveTabName) console.cons.closeSignal.connect(self.closeTab) self.tabs.addTab(console, tname) console.selfRaise.connect(self.raiseTab) self.tabs.setCurrentIndex(self.tabs.count() - 1) if console.unsavedChanges: # if autoloaded from backup # cannot be triggered from inside as signal not connected on __init__ self.changeActiveTabName(console.tabname + ' *') if self.layout == None: # no backups to avoid conflicts... console.noBackup = True self.statusMessage('', False) console.indicator.status = 'idle' console.indicator.repaint() def menuImport(self): fname = QFileDialog.getOpenFileNames( self, 'Import nameserver_history.trc...', None, 'Import nameserver history trace (*.trc)') log(fname[0]) if len(fname[0]) > 0: self.chartArea.dp = dpTrace.dataProvider( fname[0]) # db data provider self.chartArea.initDP( message='Parsing the trace file, will take a minute or so...') toTime = self.chartArea.widget.hosts[0]['to'] fromTime = toTime - datetime.timedelta(hours=10) self.chartArea.toEdit.setText(toTime.strftime('%Y-%m-%d %H:%M:%S')) self.chartArea.fromEdit.setText( fromTime.strftime('%Y-%m-%d %H:%M:%S')) self.chartArea.reloadChart() def raiseTab(self, tab): for i in range(self.tabs.count()): w = self.tabs.widget(i) if w is tab: self.tabs.setCurrentIndex(i) break def setTabName(self, str): self.tabs.setTabText(0, str) def initUI(self): if cfg('saveLayout', True): self.layout = Layout(True) if self.layout['running']: answer = utils.yesNoDialog( 'Warning', 'Another RybaFish is already running, all the layout and autosave features will be disabled.\n\nExit now?', ignore=True) #answer = utils.yesNoDialog('Warning', 'RybaFish is already running or crashed last time, all the layout and autosave features will be disabled.\n\nExit now?', ignore = True) if answer == True or answer is None: exit(0) if answer == 'ignore': log('Ignoring the layout') else: self.layout = None else: self.layout['running'] = True self.layout.dump() else: self.layout = Layout() # bottom left frame (hosts) hostsArea = QFrame(self) self.hostTable = hostsTable.hostsTable() # bottom right frame (KPIs) self.kpisTable = kpiTable.kpiTable() kpisTable = self.kpisTable # top (main chart area) self.chartArea = chartArea.chartArea() ind = indicator() self.chartArea.indicator = ind # establish hard links: kpisTable.kpiScales = self.chartArea.widget.nscales self.chartArea.widget.hosts = self.hostTable.hosts kpisTable.hosts = self.chartArea.widget.hosts #why do we have hosts inside widget? because we have all data there... kpisTable.hostKPIs = self.chartArea.hostKPIs kpisTable.srvcKPIs = self.chartArea.srvcKPIs kpisTable.nkpis = self.chartArea.widget.nkpis # bottm part left+right self.kpiSplitter = QSplitter(Qt.Horizontal) self.kpiSplitter.addWidget(self.hostTable) self.kpiSplitter.addWidget(kpisTable) self.kpiSplitter.setSizes([200, 380]) self.tabs = QTabWidget() # self.tabs.currentChanged.connect(self.tabChanged) # main window splitter self.mainSplitter = QSplitter(Qt.Vertical) kpisWidget = QWidget() lo = QVBoxLayout(kpisWidget) lo.addWidget(self.kpiSplitter) self.mainSplitter.addWidget(self.chartArea) self.mainSplitter.addWidget(kpisWidget) if self.layout is not None: if self.layout['mainSplitter']: self.mainSplitter.setSizes(self.layout['mainSplitter']) else: self.mainSplitter.setSizes([300, 90]) if self.layout['kpiSplitter']: self.kpiSplitter.setSizes(self.layout['kpiSplitter']) else: self.kpiSplitter.setSizes([200, 380]) if self.layout['hostTableWidth']: hostTableWidth = self.layout['hostTableWidth'] for i in range(self.hostTable.columnCount()): if i > len(hostTableWidth) - 1: break self.hostTable.setColumnWidth(i, hostTableWidth[i]) if self.layout['KPIsTableWidth']: KPIsTableWidth = self.layout['KPIsTableWidth'] for i in range(self.kpisTable.columnCount()): if i > len(KPIsTableWidth) - 1: break self.kpisTable.setColumnWidth(i, KPIsTableWidth[i]) else: self.mainSplitter.setSizes([300, 90]) self.kpiSplitter.setSizes([200, 380]) self.mainSplitter.setAutoFillBackground(True) # central widget #self.setCentralWidget(mainSplitter) kpisWidget.autoFillBackground = True self.tabs.addTab(self.mainSplitter, 'Chart') self.chartArea.selfRaise.connect(self.raiseTab) ind.iClicked.connect(self.chartArea.indicatorSignal) self.setCentralWidget(self.tabs) # service stuff self.statusbar = self.statusBar() self.statusbar.addPermanentWidget(ind) #menu iconPath = resourcePath('ico\\favicon.ico') exitAct = QAction('&Exit', self) exitAct.setShortcut('Alt+Q') exitAct.setStatusTip('Exit application') exitAct.triggered.connect(self.menuQuit) dummyAct = QAction('&Dummy', self) dummyAct.setShortcut('Alt+D') dummyAct.setStatusTip('Dummy Data provider') dummyAct.triggered.connect(self.menuDummy) configAct = QAction('&Connect', self) configAct.setShortcut('Alt+C') configAct.setStatusTip('Configure connection') configAct.triggered.connect(self.menuConfig) importAct = QAction('&Import nameserver history trace', self) importAct.setShortcut('Ctrl+I') importAct.setStatusTip('Import nameserver.trc') importAct.triggered.connect(self.menuImport) sqlConsAct = QAction('New &SQL Console', self) sqlConsAct.setShortcut('Alt+S') sqlConsAct.setStatusTip('Create SQL Console') sqlConsAct.triggered.connect(self.menuSQLConsole) openAct = QAction('&Open file in new sql console', self) openAct.setShortcut('Ctrl+O') openAct.setStatusTip('Open new console with the file') openAct.triggered.connect(self.menuOpen) saveAct = QAction('&Save sql to a file', self) saveAct.setShortcut('Ctrl+S') saveAct.setStatusTip('Saves sql from current console to a file') saveAct.triggered.connect(self.menuSave) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(configAct) fileMenu.addAction(importAct) fileMenu.addAction(sqlConsAct) fileMenu.addAction(openAct) fileMenu.addAction(saveAct) if cfg('experimental'): fileMenu.addAction(dummyAct) fileMenu.addAction(exitAct) actionsMenu = menubar.addMenu('&Actions') if cfg('experimental'): # fileMenu.addAction(aboutAct) -- print not sure why its here fontAct = QAction('&Adjust Fonts', self) fontAct.setStatusTip( 'Adjust margins after font change (for example after move to secondary screen)' ) fontAct.triggered.connect(self.menuFont) actionsMenu.addAction(fontAct) # issue #255 reloadConfigAct = QAction('Reload &Config', self) reloadConfigAct.setStatusTip( 'Reload configuration file. Note: some values used during the connect or other one-time-actions (restart required).' ) reloadConfigAct.triggered.connect(self.menuReloadConfig) actionsMenu.addAction(reloadConfigAct) reloadCustomKPIsAct = QAction('Reload Custom &KPIs', self) reloadCustomKPIsAct.setStatusTip('Reload definition of custom KPIs') reloadCustomKPIsAct.triggered.connect(self.menuReloadCustomKPIs) actionsMenu.addAction(reloadCustomKPIsAct) # help menu part aboutAct = QAction(QIcon(iconPath), '&About', self) aboutAct.setStatusTip('About this app') aboutAct.triggered.connect(self.menuAbout) confHelpAct = QAction('Configuration', self) confHelpAct.setStatusTip('Configuration options description') confHelpAct.triggered.connect(self.menuConfHelp) confCustomHelpAct = QAction('Custom KPIs', self) confCustomHelpAct.setStatusTip('Short manual on custom KPIs') confCustomHelpAct.triggered.connect(self.menuCustomConfHelp) confTipsAct = QAction('Tips and tricks', self) confTipsAct.setStatusTip('Tips and tricks description') confTipsAct.triggered.connect(self.menuTips) helpMenu = menubar.addMenu('&Help') helpMenu.addAction(confHelpAct) helpMenu.addAction(confCustomHelpAct) helpMenu.addAction(confTipsAct) helpMenu.addAction(aboutAct) # finalization if self.layout is not None and self.layout['pos'] and self.layout[ 'size']: pos = self.layout['pos'] size = self.layout['size'] #print('screen number', QApplication.desktop().screenNumber()) #print('number of screens', QApplication.desktop().screenCount()) #print('available geometry:', QApplication.desktop().availableGeometry()) #print('screen geometry:', QApplication.desktop().screenGeometry()) r = QRect(pos[0], pos[1], size[0], size[1]) if QApplication.desktop().screenCount() == 1: # only when just one screen is available... if not QApplication.desktop().screenGeometry().contains( r) and not cfg('dontAutodetectScreen'): #the window will not be visible so jump to the main screen: (pos[0], pos[1]) = (100, 50) #self.setGeometry(pos[0] + 8, pos[1] + 31, size[0], size[1]) #self.setGeometry(pos[0], pos[1], size[0], size[1]) self.move(pos[0], pos[1]) self.resize(size[0], size[1]) else: self.setGeometry(200, 200, 1400, 800) self.setWindowTitle('RybaFish Charts') self.setWindowIcon(QIcon(iconPath)) scrollPosition = [] if cfg('saveOpenTabs', True) and self.layout is not None and self.layout['tabs']: for t in self.layout['tabs']: if len(t) != 4: continue console = sqlConsole.sqlConsole(self, None, '?') console.nameChanged.connect(self.changeActiveTabName) console.cons.closeSignal.connect(self.closeTab) self.tabs.addTab(console, console.tabname) ind = indicator() console.indicator = ind console.selfRaise.connect(self.raiseTab) ind.iClicked.connect(console.reportRuntime) self.statusbar.addPermanentWidget(ind) self.tabs.setCurrentIndex(self.tabs.count() - 1) if t[0] is not None or t[1] is not None: # such a tab should not ever be saved (this call will just open fileOpen dialog), anyway... # should we even create such a tab? console.openFile(t[0], t[1]) pos = t[2] block = t[3] scrollPosition.append(block) if isinstance(pos, int) and isinstance(block, int): cursor = console.cons.textCursor() cursor.setPosition(pos, cursor.MoveAnchor) console.cons.setTextCursor(cursor) indx = self.layout['currentTab'] if isinstance(indx, int): self.tabs.setCurrentIndex(indx) w = self.tabs.widget(indx) if isinstance(w, sqlConsole.sqlConsole): w.cons.setFocus() else: self.tabs.setCurrentIndex(0) self.show() #scroll everything to stored position for i in range(self.tabs.count() - 1, 0, -1): w = self.tabs.widget(i) if isinstance(w, sqlConsole.sqlConsole): if i - 1 < len(scrollPosition): block = scrollPosition[i - 1] w.cons.edit.verticalScrollBar().setValue(block) else: log('[w] scroll position list out of range, ignoring scrollback...' ) ''' set up some interactions ''' # bind kpi checkbox signal kpisTable.checkboxToggle.connect(self.chartArea.checkboxToggle) # bind change scales signal kpisTable.adjustScale.connect(self.chartArea.adjustScale) kpisTable.setScale.connect(self.chartArea.setScale) # host table row change signal self.hostTable.hostChanged.connect(kpisTable.refill) # to fill hosts self.chartArea.hostsUpdated.connect(self.hostTable.hostsUpdated) # refresh self.chartArea.kpiToggled.connect(kpisTable.refill) # update scales signal self.chartArea.scalesUpdated.connect(kpisTable.updateScales) log('self.scalesUpdated.emit() #0', 5) self.chartArea.scalesUpdated.emit( ) # it really not supposed to have any to update here #bind statusbox updating signals self.chartArea.statusMessage_.connect(self.statusMessage) self.chartArea.widget.statusMessage_.connect(self.statusMessage) self.chartArea.connected.connect(self.setTabName) log('init finish()') # offline console tests if cfg('developmentMode'): #tname = sqlConsole.generateTabName() #idx = self.tabs.count() self.sqlTabCounter += 1 idx = self.sqlTabCounter if idx > 1: tname = 'sql' + str(idx) else: tname = 'sql' console = sqlConsole.sqlConsole(self, None, tname) console.nameChanged.connect(self.changeActiveTabName) from SQLSyntaxHighlighter import SQLSyntaxHighlighter self.tabs.addTab(console, tname) console.selfRaise.connect(self.raiseTab) self.tabs.setCurrentIndex(self.tabs.count() - 1) self.SQLSyntax = SQLSyntaxHighlighter(console.cons.document()) #console.cons.setPlainText('select * from dummy;\n\nselect \n *\n from dummy;\n\nselect * from m_host_information;'); ind = indicator() console.indicator = ind self.statusbar.addPermanentWidget(ind) ind.iClicked.connect(console.reportRuntime) if cfg('developmentMode'): console.cons.setPlainText('''select 0 from dummy; create procedure ... ( (as begin) select * from dummy); end; where timestamp between '2020-02-10 00:00:00' and '2020-02-16 23:59:59' -- test comment where not "NAME1" = '' and "DOKST" in ('D0', 'D2') and (1 = 2) select 1 from dummy; select 2 from dummy; select 3 from dummy;''') console.dummyResultTable() self.statusMessage('', False) if self.chartArea.dp: self.chartArea.initDP()
def initWin(self): iptGrid = QGridLayout() title = Text("TSP", (255, 0, 0), 16, "center") pic = QPixmap("C:\\tsp.png") picLbl = QLabel() picLbl.setPixmap(pic) picLbl.setScaledContents(True) titleLayout = QVBoxLayout() titleLayout.addWidget(title) titleLayout.addWidget(picLbl) titleFrame = QFrame() titleFrame.setFrameShape(QFrame.StyledPanel) titleFrame.setAutoFillBackground(True) p5 = titleFrame.palette() p5.setColor(titleFrame.backgroundRole(), QColor(255, 255, 255)) titleFrame.setPalette(p5) titleFrame.setLayout(titleLayout) iptTitle = Text("Program Input", (255, 0, 0), 12, "center") iptTxt1 = QLabel("Cities No:") iptTxt1.setFont(QFont("Decorative", 12)) iptTxt2 = QLabel("start:") iptTxt2.setFont(QFont("Decorative", 12)) self.iptEdt1 = QLineEdit() self.iptEdt1.textChanged[str].connect(self.get_input) self.iptEdt2 = QLineEdit() self.iptEdt2.textChanged[str].connect(self.get_input) self.iptBtn1 = QPushButton("Build") self.iptBtn1.clicked.connect(self.bulid_map) self.iptBtn2 = QPushButton("Rturn") self.iptBtn2.clicked.connect(self.get_initial) iptH = QHBoxLayout() iptH.addWidget(self.iptBtn1) iptH.addWidget(self.iptBtn2) iptGrid.addWidget(iptTitle, 1, 0, 1, 5) iptGrid.addWidget(iptTxt1, 2, 0) iptGrid.addWidget(self.iptEdt1, 2, 1) iptGrid.addWidget(iptTxt2, 3, 0) iptGrid.addWidget(self.iptEdt2, 3, 1) iptGrid.setVerticalSpacing(10) iptV = QVBoxLayout() iptV.addLayout(iptGrid) iptV.addLayout(iptH) iptFrame = QFrame() iptFrame.setAutoFillBackground(True) p6 = iptFrame.palette() p6.setColor(iptFrame.backgroundRole(), QColor(220, 225, 255)) iptFrame.setPalette(p6) iptFrame.setFrameShape(QFrame.StyledPanel) iptFrame.setLayout(iptV) srgGrid = QGridLayout() #srgGrid.setVerticalSpacing(10) srgTitle = Text("Algorithms", (255, 0, 0), 12, "center") self.srgBtn1 = QPushButton("Genetic") self.srgBtn1.clicked.connect(self.run_algorithm) self.srgBtn2 = QPushButton("Simulated") self.srgBtn2.clicked.connect(self.run_algorithm) self.srgBtn3 = QPushButton("Tabu") self.srgBtn3.clicked.connect(self.run_algorithm) self.srgBtn4 = QPushButton("reset") self.srgBtn4.clicked.connect(self.reset) srgGrid.addWidget(srgTitle, 1, 0, 1, 6) srgGrid.addWidget(self.srgBtn1, 2, 1, 2, 4) srgGrid.addWidget(self.srgBtn2, 3, 1, 3, 4) srgGrid.addWidget(self.srgBtn3, 4, 1, 4, 4) srgGrid.addWidget(self.srgBtn4, 5, 1, 5, 4) srgFrame = QFrame() srgFrame.setFrameShape(QFrame.StyledPanel) srgFrame.setAutoFillBackground(True) p7 = srgFrame.palette() p7.setColor(srgFrame.backgroundRole(), QColor(255, 255, 255)) srgFrame.setPalette(p7) srgFrame.setLayout(srgGrid) otpGrid = QGridLayout() otpTitle = Text("Program Output", (255, 0, 0), 12, "center") otpTxt1 = QLabel("The Cost") otpTxt1.setFont(QFont("Decorative", 12)) self.lcd1 = QLCDNumber() otpGrid.addWidget(otpTitle, 1, 0, 1, 2) otpGrid.addWidget(otpTxt1, 2, 0) otpGrid.addWidget(self.lcd1, 2, 1) otpFrame = QFrame() otpFrame.setFrameShape(QFrame.StyledPanel) otpFrame.setAutoFillBackground(True) p8 = otpFrame.palette() p8.setColor(otpFrame.backgroundRole(), QColor(220, 225, 255)) otpFrame.setPalette(p8) otpFrame.setLayout(otpGrid) splitter1 = QSplitter(Qt.Vertical) splitter1.addWidget(titleFrame) splitter1.addWidget(iptFrame) splitter1.setSizes([240, 135]) splitter2 = QSplitter(Qt.Vertical) splitter2.addWidget(srgFrame) splitter2.addWidget(otpFrame) splitter2.setSizes([200, 92]) splitter3 = QSplitter(Qt.Vertical) splitter3.addWidget(splitter1) splitter3.addWidget(splitter2) splitter3.setSizes([382, 291]) splitter3.resize(260, 685) splitter3.move(1100, 5) splitter3.setParent(self) splitter3.setAutoFillBackground(True) p3 = splitter3.palette() p3.setColor(splitter3.backgroundRole(), QColor(255, 255, 255)) splitter3.setPalette(p3) self.mapFrame = QFrame() self.mapFrame.setFrameShape(QFrame.StyledPanel) self.mapFrame.move(5, 5) self.mapFrame.resize(1090, 685) self.mapFrame.setParent(self) self.setAutoFillBackground(True) p2 = self.palette() p2.setColor(self.backgroundRole(), QColor(0, 0, 0)) self.setPalette(p2) self.mapFrame.setParent(self) self.hint = Text("Click the bulid button to bulid a random map", (255, 0, 0), 23, "center") self.hint.move(230, 100) self.hint.setParent(self) self.setWindowTitle("TSP") self.width = QDesktopWidget().availableGeometry().width() self.height = QDesktopWidget().availableGeometry().height() - 40 self.resize(self.width, self.height) self.show() self.nodes = {} self.points = {} self.flag = True