class LogDialog(QDialog): def __init__(self, parent, rpt_file_path): self.rpt_file_path = rpt_file_path QDialog.__init__(self, parent) self.setWindowTitle('Log: ' + self.rpt_file_path) main_lay = QVBoxLayout(self) self.txt_log = QPlainTextEdit(self) self.txt_log.setMinimumWidth(500) self.txt_log.setMinimumHeight(300) main_lay.addWidget(self.txt_log) self.btn_close = QPushButton('Close') self.btn_close.clicked.connect(self.close_dialog) main_lay.addWidget(self.btn_close) self.fill_txt() def close_dialog(self): self.close() def fill_txt(self): with codecs.open(self.rpt_file_path, 'r', encoding='UTF-8') as inp_f: lines = inp_f.read().splitlines() for line in lines: self.txt_log.appendPlainText(line.replace('\b', '')) # Scroll up self.txt_log.moveCursor(QTextCursor.Start) self.txt_log.ensureCursorVisible()
def on_actionShow_logfiles_triggered(self): self._item.setText(3, '') try: loglines = self._client.getServiceLogs(self._service, self._instance) except ClientError as err: self._item.setText(3, str(err)) return if not loglines: self._item.setText(3, 'Service does not return logs') return dlg = QDialog(self) loadUi(dlg, 'details.ui') dlg.tabber.clear() logs = [] for logline in loglines: filename, content = logline.split(':', 1) if not logs or filename != logs[-1][0]: logs.append((filename, [])) logs[-1][1].append(content) for filename, content in logs: widget = QPlainTextEdit(dlg) font = widget.font() font.setFamily('Monospace') widget.setFont(font) widget.setPlainText(''.join(content)) widget.moveCursor(QTextCursor.End) widget.ensureCursorVisible() dlg.tabber.addTab(widget, filename) dlg.exec_()
class LogViewer(QWidget): """ The log (+stdout, +stderr) viewer widget """ def __init__(self, parent=None): QWidget.__init__(self, parent) self.__isEmpty = True self.__copyAvailable = False self.clearButton = None self.messages = None self.copyButton = None self.selectAllButton = None self.__createLayout(parent) # create the context menu self.__menu = QMenu(self) self.__selectAllMenuItem = self.__menu.addAction( PixmapCache().getIcon('selectall.png'), 'Select All', self.messages.selectAll) self.__copyMenuItem = self.__menu.addAction( PixmapCache().getIcon('copytoclipboard.png'), 'Copy', self.messages.copy) self.__menu.addSeparator() self.__clearMenuItem = self.__menu.addAction( PixmapCache().getIcon('trash.png'), 'Clear', self.__clear) self.messages.setContextMenuPolicy(Qt.CustomContextMenu) self.messages.customContextMenuRequested.connect( self.__handleShowContextMenu) self.messages.copyAvailable.connect(self.__onCopyAvailable) self.cNormalFormat = self.messages.currentCharFormat() self.cErrorFormat = self.messages.currentCharFormat() self.cErrorFormat.setForeground(QBrush(QColor(Qt.red))) self.__updateToolbarButtons() return def __createLayout(self, parent): " Helper to create the viewer layout " # Messages list area self.messages = QPlainTextEdit(parent) self.messages.setLineWrapMode(QPlainTextEdit.NoWrap) self.messages.setFont(QFont(GlobalData().skin.baseMonoFontFace)) self.messages.setReadOnly(True) self.messages.setMaximumBlockCount(MAX_LINES) # Default font size is good enough for most of the systems. # 12.0 might be good only in case of the XServer on PC (Xming). # self.messages.setFontPointSize( 12.0 ) # Buttons self.selectAllButton = QAction(PixmapCache().getIcon('selectall.png'), 'Select all', self) self.selectAllButton.triggered.connect(self.messages.selectAll) self.copyButton = QAction(PixmapCache().getIcon('copytoclipboard.png'), 'Copy to clipboard', self) self.copyButton.triggered.connect(self.messages.copy) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.clearButton = QAction(PixmapCache().getIcon('trash.png'), 'Clear all', self) self.clearButton.triggered.connect(self.__clear) # Toolbar self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Vertical) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.LeftToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedWidth(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.selectAllButton) self.toolbar.addAction(self.copyButton) self.toolbar.addWidget(spacer) self.toolbar.addAction(self.clearButton) # layout layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.toolbar) layout.addWidget(self.messages) self.setLayout(layout) return def __handleShowContextMenu(self, coord): """ Show the context menu """ self.__selectAllMenuItem.setEnabled(not self.__isEmpty) self.__copyMenuItem.setEnabled(self.__copyAvailable) self.__clearMenuItem.setEnabled(not self.__isEmpty) self.__menu.popup(QCursor.pos()) return def __appendText(self, txt, isError): " Append the text " if len(txt) == 0: return self.__isEmpty = False cursor = self.messages.textCursor() cursor.movePosition(QTextCursor.End) self.messages.setTextCursor(cursor) if isError: self.messages.setCurrentCharFormat(self.cErrorFormat) else: self.messages.setCurrentCharFormat(self.cNormalFormat) self.messages.insertPlainText(txt) self.messages.insertPlainText('\n') self.messages.ensureCursorVisible() self.__updateToolbarButtons() return def appendMessage(self, txt): " Append the regular message " self.__appendText(txt, False) #QApplication.processEvents() return def appendError(self, txt): " Append the error message " self.__appendText(txt, True) #QApplication.processEvents() return def append(self, txt): " Decides what the message is - error or not - and append it then " if txt.startswith( 'CRITICAL' ) or \ txt.startswith( 'ERROR' ) or \ txt.startswith( 'WARNING' ): self.appendError(txt) else: self.appendMessage(txt) return def __updateToolbarButtons(self): " Contextually updates toolbar buttons " self.selectAllButton.setEnabled(not self.__isEmpty) self.copyButton.setEnabled(self.__copyAvailable) self.clearButton.setEnabled(not self.__isEmpty) return def __clear(self): " Triggers when the clear function is selected " self.__isEmpty = True self.__copyAvailable = False self.messages.clear() self.__updateToolbarButtons() return def __onCopyAvailable(self, isAvailable): " Triggers on the copyAvailable signal " self.__copyAvailable = isAvailable self.__updateToolbarButtons() return def getText(self): " Provides the content as a plain text " return self.messages.toPlainText()
class LogViewer( QWidget ): """ The log (+stdout, +stderr) viewer widget """ def __init__( self, parent = None ): QWidget.__init__( self, parent ) self.__isEmpty = True self.__copyAvailable = False self.clearButton = None self.messages = None self.copyButton = None self.selectAllButton = None self.__createLayout( parent ) # create the context menu self.__menu = QMenu( self ) self.__selectAllMenuItem = self.__menu.addAction( PixmapCache().getIcon( 'selectall.png' ), 'Select All', self.messages.selectAll ) self.__copyMenuItem = self.__menu.addAction( PixmapCache().getIcon( 'copytoclipboard.png' ), 'Copy', self.messages.copy ) self.__menu.addSeparator() self.__clearMenuItem = self.__menu.addAction( PixmapCache().getIcon( 'trash.png' ), 'Clear', self.__clear ) self.messages.setContextMenuPolicy( Qt.CustomContextMenu ) self.messages.customContextMenuRequested.connect( self.__handleShowContextMenu ) self.messages.copyAvailable.connect( self.__onCopyAvailable ) self.cNormalFormat = self.messages.currentCharFormat() self.cErrorFormat = self.messages.currentCharFormat() self.cErrorFormat.setForeground( QBrush( QColor( Qt.red ) ) ) self.__updateToolbarButtons() return def __createLayout( self, parent ): " Helper to create the viewer layout " # Messages list area self.messages = QPlainTextEdit( parent ) self.messages.setLineWrapMode( QPlainTextEdit.NoWrap ) self.messages.setFont( QFont( GlobalData().skin.baseMonoFontFace ) ) self.messages.setReadOnly( True ) self.messages.setMaximumBlockCount( MAX_LINES ) # Default font size is good enough for most of the systems. # 12.0 might be good only in case of the XServer on PC (Xming). # self.messages.setFontPointSize( 12.0 ) # Buttons self.selectAllButton = QAction( PixmapCache().getIcon( 'selectall.png' ), 'Select all', self ) self.selectAllButton.triggered.connect( self.messages.selectAll ) self.copyButton = QAction( PixmapCache().getIcon( 'copytoclipboard.png' ), 'Copy to clipboard', self ) self.copyButton.triggered.connect( self.messages.copy ) spacer = QWidget() spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding ) self.clearButton = QAction( PixmapCache().getIcon( 'trash.png' ), 'Clear all', self ) self.clearButton.triggered.connect( self.__clear ) # Toolbar self.toolbar = QToolBar() self.toolbar.setOrientation( Qt.Vertical ) self.toolbar.setMovable( False ) self.toolbar.setAllowedAreas( Qt.LeftToolBarArea ) self.toolbar.setIconSize( QSize( 16, 16 ) ) self.toolbar.setFixedWidth( 28 ) self.toolbar.setContentsMargins( 0, 0, 0, 0 ) self.toolbar.addAction( self.selectAllButton ) self.toolbar.addAction( self.copyButton ) self.toolbar.addWidget( spacer ) self.toolbar.addAction( self.clearButton ) # layout layout = QHBoxLayout() layout.setContentsMargins( 0, 0, 0, 0 ) layout.setSpacing( 0 ) layout.addWidget( self.toolbar ) layout.addWidget( self.messages ) self.setLayout( layout ) return def __handleShowContextMenu( self, coord ): """ Show the context menu """ self.__selectAllMenuItem.setEnabled( not self.__isEmpty ) self.__copyMenuItem.setEnabled( self.__copyAvailable ) self.__clearMenuItem.setEnabled( not self.__isEmpty ) self.__menu.popup( QCursor.pos() ) return def __appendText( self, txt, isError ): " Append the text " if len( txt ) == 0: return self.__isEmpty = False cursor = self.messages.textCursor() cursor.movePosition( QTextCursor.End ) self.messages.setTextCursor( cursor ) if isError: self.messages.setCurrentCharFormat( self.cErrorFormat ) else: self.messages.setCurrentCharFormat( self.cNormalFormat ) self.messages.insertPlainText( txt ) self.messages.insertPlainText( '\n' ) self.messages.ensureCursorVisible() self.__updateToolbarButtons() return def appendMessage( self, txt ): " Append the regular message " self.__appendText( txt, False ) #QApplication.processEvents() return def appendError( self, txt ): " Append the error message " self.__appendText( txt, True ) #QApplication.processEvents() return def append( self, txt ): " Decides what the message is - error or not - and append it then " if txt.startswith( 'CRITICAL' ) or \ txt.startswith( 'ERROR' ) or \ txt.startswith( 'WARNING' ): self.appendError( txt ) else: self.appendMessage( txt ) return def __updateToolbarButtons( self ): " Contextually updates toolbar buttons " self.selectAllButton.setEnabled( not self.__isEmpty ) self.copyButton.setEnabled( self.__copyAvailable ) self.clearButton.setEnabled( not self.__isEmpty ) return def __clear( self ): " Triggers when the clear function is selected " self.__isEmpty = True self.__copyAvailable = False self.messages.clear() self.__updateToolbarButtons() return def __onCopyAvailable( self, isAvailable ): " Triggers on the copyAvailable signal " self.__copyAvailable = isAvailable self.__updateToolbarButtons() return def getText( self ): " Provides the content as a plain text " return self.messages.toPlainText()