From d56d23017908dee7f7c2e75aa81d4ac413caa16c Mon Sep 17 00:00:00 2001 From: Alexander Bus <busfromrus@gmail.com> Date: Mon, 15 Jan 2018 20:41:32 +0700 Subject: [PATCH] Change exception indication, add conn. closure * Options for how existence of an exception is shown, * Now a special logger record will appear when a connection closes. --- README.md | 4 +- cutelog/config.py | 11 +++++ cutelog/logger_tab.py | 65 +++++++++++++++++++++---- cutelog/resources/ui/settings_dialog.ui | 56 +++++++++++++++------ cutelog/settings_dialog.py | 8 +-- setup.py | 2 +- 6 files changed, 115 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 5841602..b204b20 100644 --- a/README.md +++ b/README.md @@ -57,11 +57,9 @@ Afterwards it's recommended to designate different loggers for different parts o This will create "log namespaces" which allow you to filter out messages from various subsystems of your program. ## Planned features -* [ ] Indication that the connection has been closed * [ ] Presets for colors -* [ ] Presets for the logger header +* [ ] Presets for the logger header (with option to add columns for extra data) * [ ] Modify how rows are arranged in the detail table (like the header dialog) -* [ ] Improve the way existence of an exception is shown * [ ] Fix double-search on the last matched result (or indicate that the last result was reached) * [ ] Ability to save and load logs (as text or as full records) * [ ] Alarms/notifications triggered by specified messages diff --git a/cutelog/config.py b/cutelog/config.py index 462aa1a..12658bf 100644 --- a/cutelog/config.py +++ b/cutelog/config.py @@ -1,3 +1,4 @@ +import enum import logging import os import sys @@ -24,6 +25,15 @@ else: QT55_COMPAT = False +# Maybe there should be one common enum with all options instead of +# one enum for each thing? I guess I'll decide when there will be +# more than one thing in total. +class Exc_Indication(enum.IntEnum): + RED_BG = 0 + MSG_ICON = 1 + ICON_AND_RED_BG = 2 + + # There must be a better way to do this, right? Option = namedtuple('Option', ['name', 'type', 'default']) OPTION_SPEC = ( @@ -34,6 +44,7 @@ OPTION_SPEC = ( ('text_view_dialog_font', str, 'Courier New'), ('text_view_dialog_font_size', int, 12), ('logger_row_height', int, 20), + ('exception_indication', int, Exc_Indication.RED_BG), # Search ('search_open_default', bool, False), diff --git a/cutelog/logger_tab.py b/cutelog/logger_tab.py index ac9dfe1..2255a44 100644 --- a/cutelog/logger_tab.py +++ b/cutelog/logger_tab.py @@ -7,11 +7,11 @@ from functools import partial from PyQt5 import uic from PyQt5.QtCore import (QAbstractItemModel, QAbstractTableModel, QEvent, QModelIndex, QSortFilterProxyModel, Qt) -from PyQt5.QtGui import QFont +from PyQt5.QtGui import QBrush, QColor, QFont from PyQt5.QtWidgets import (QCheckBox, QHBoxLayout, QMenu, QShortcut, QStyle, QTableWidgetItem, QWidget) -from .config import CONFIG +from .config import CONFIG, Exc_Indication from .level_edit_dialog import LevelEditDialog from .log_levels import LevelFilter, LogLevel from .logger_table_header import HeaderEditDialog, LoggerTableHeader @@ -152,6 +152,8 @@ class LogRecordModel(QAbstractTableModel): result = None record = self.records[index.row()] + if getattr(record, '_cutelog', False): + return self.data_internal(index, record, role) level = self.levels[record.levelno] if role == Qt.DisplayRole: @@ -160,7 +162,10 @@ class LogRecordModel(QAbstractTableModel): elif role == Qt.DecorationRole: if self.headerData(index.column()) == 'Message': if record.exc_text: - result = self.parent_widget.style().standardIcon(QStyle.SP_BrowserStop) + mode = CONFIG['exception_indication'] + should = mode in (Exc_Indication.MSG_ICON, Exc_Indication.ICON_AND_RED_BG) + if should: + result = self.parent_widget.style().standardIcon(QStyle.SP_BrowserStop) elif role == Qt.FontRole: result = None styles = level.styles if not self.dark_theme else level.stylesDark @@ -181,6 +186,16 @@ class LogRecordModel(QAbstractTableModel): else: result = level.fgDark elif role == Qt.BackgroundRole: + if record.exc_text: + mode = CONFIG['exception_indication'] + should = mode in (Exc_Indication.RED_BG, Exc_Indication.ICON_AND_RED_BG) + if should: + if not self.dark_theme: + color = QColor(255, 180, 180) + else: + color = Qt.darkRed + result = QBrush(color, Qt.DiagCrossPattern) + return result if not self.dark_theme: result = level.bg else: @@ -189,20 +204,45 @@ class LogRecordModel(QAbstractTableModel): result = record.message return result + def data_internal(self, index, record, role): + result = None + if role == Qt.DisplayRole: + if index.column() == self.columnCount(INVALID_INDEX) - 1: # if last column + result = record._cutelog + else: + column = self.table_header[index.column()] + if column.name == 'asctime': + result = record.asctime + elif role == Qt.FontRole: + result = QFont(CONFIG.logger_table_font, CONFIG.logger_table_font_size) + elif role == Qt.ForegroundRole: + if not self.dark_theme: + result = QColor(Qt.black) + else: + result = QColor(Qt.white) + elif role == Qt.BackgroundRole: + if not self.dark_theme: + color = QColor(Qt.lightGray) + else: + color = QColor(Qt.darkGray) + result = QBrush(color, Qt.BDiagPattern) + return result + def headerData(self, section, orientation=Qt.Horizontal, role=Qt.DisplayRole): result = None if orientation == Qt.Horizontal and role == Qt.DisplayRole: result = self.table_header[section].title return result - def add_record(self, record): - self.trim_if_needed() + def add_record(self, record, internal=False): + if not internal: + self.trim_if_needed() + self.date_formatter.format(record) row = len(self.records) + self.beginInsertRows(INVALID_INDEX, row, row) - self.date_formatter.format(record) self.records.append(record) self.endInsertRows() - return row def trim_except_last_n(self, n): from itertools import islice @@ -360,7 +400,7 @@ class LoggerTab(*LoggerTabBase): self.main_window = main_window self.loop = loop self.level_filter = LevelFilter() - self.level_filter.set_all_pass(False) + self.level_filter.set_all_pass(True) self.filter_model_enabled = True self.detail_model = DetailTableModel() self.namespace_tree_model = LogNamespaceTreeModel() @@ -566,7 +606,13 @@ class LoggerTab(*LoggerTabBase): self.register_logger(record.name) self.record_count += 1 self.monitor_count += 1 - # self.loggerTable.resizeRowsToContents() + + def add_conn_closed_record(self, conn): + d = {'_cutelog': 'Connection "{}" closed'.format(conn.name)} + record = logging.makeLogRecord(d) + self.record_model.add_record(record) + if self.autoscroll: + self.loggerTable.scrollToBottom() def get_record(self, index): if self.filter_model_enabled: @@ -797,6 +843,7 @@ class LoggerTab(*LoggerTabBase): def remove_connection(self, connection): self.log.debug('Removing connection "{}"'.format(connection)) self.connections.remove(connection) + self.add_conn_closed_record(connection) def stop_all_connections(self): for conn in self.connections: diff --git a/cutelog/resources/ui/settings_dialog.ui b/cutelog/resources/ui/settings_dialog.ui index 6fbd967..be5577d 100644 --- a/cutelog/resources/ui/settings_dialog.ui +++ b/cutelog/resources/ui/settings_dialog.ui @@ -83,13 +83,6 @@ <property name="spacing"> <number>10</number> </property> - <item row="1" column="2"> - <widget class="QSpinBox" name="loggerTableFontSize"> - <property name="minimum"> - <number>1</number> - </property> - </widget> - </item> <item row="0" column="1"> <widget class="QCheckBox" name="darkThemeDefaultCheckBox"> <property name="text"> @@ -100,13 +93,6 @@ <item row="2" column="1"> <widget class="QFontComboBox" name="textViewFont"/> </item> - <item row="2" column="2"> - <widget class="QSpinBox" name="textViewFontSize"> - <property name="minimum"> - <number>1</number> - </property> - </widget> - </item> <item row="1" column="0"> <widget class="QLabel" name="label_9"> <property name="text"> @@ -148,7 +134,7 @@ </property> </widget> </item> - <item row="4" column="1"> + <item row="5" column="1"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -161,6 +147,46 @@ </property> </spacer> </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_16"> + <property name="text"> + <string>Indicate exception with</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QSpinBox" name="loggerTableFontSize"> + <property name="minimum"> + <number>1</number> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QSpinBox" name="textViewFontSize"> + <property name="minimum"> + <number>1</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="excIndicationComboBox"> + <item> + <property name="text"> + <string>Red crossed background</string> + </property> + </item> + <item> + <property name="text"> + <string>Cross icon in the message column</string> + </property> + </item> + <item> + <property name="text"> + <string>Both</string> + </property> + </item> + </widget> + </item> </layout> </widget> </widget> diff --git a/cutelog/settings_dialog.py b/cutelog/settings_dialog.py index 0c00763..fedc143 100644 --- a/cutelog/settings_dialog.py +++ b/cutelog/settings_dialog.py @@ -50,6 +50,7 @@ class SettingsDialog(*SettingsDialogBase): self.textViewFont.setCurrentFont(QFont(CONFIG['text_view_dialog_font'])) self.textViewFontSize.setValue(CONFIG['text_view_dialog_font_size']) self.loggerTableRowHeight.setValue(CONFIG['logger_row_height']) + self.excIndicationComboBox.setCurrentIndex(CONFIG['exception_indication']) # Search self.searchOpenDefaultCheckBox.setChecked(CONFIG['search_open_default']) @@ -74,9 +75,6 @@ class SettingsDialog(*SettingsDialogBase): self.lightThemeNativeCheckBox.setChecked(CONFIG['light_theme_is_native']) self.server_restart_needed = False - def server_options_changed(self): - self.server_restart_needed = True - def save_to_config(self): o = {} # Appearance @@ -85,6 +83,7 @@ class SettingsDialog(*SettingsDialogBase): o['logger_table_font_size'] = self.loggerTableFontSize.value() o['text_view_dialog_font'] = self.textViewFont.currentFont().family() o['text_view_dialog_font_size'] = self.textViewFontSize.value() + o['exception_indication'] = self.excIndicationComboBox.currentIndex() new_row_height = self.loggerTableRowHeight.value() if new_row_height != CONFIG['logger_row_height']: # to prevent resizing unnecessarily o['logger_row_height'] = new_row_height @@ -120,6 +119,9 @@ class SettingsDialog(*SettingsDialogBase): # print('rejecting') self.done(0) + def server_options_changed(self): + self.server_restart_needed = True + def display_warning(self): m = QMessageBox(self.parent_widget) m.setText('You need to restart the server for the changes to take effect') diff --git a/setup.py b/setup.py index 4feb7ae..f6e1059 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup from setuptools.command.install import install -VERSION = '1.1.3' +VERSION = '1.1.4' def build_qt_resources(): -- GitLab