Skip to content

Add warnings banner, redirect Qt messages #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion OATFWGUI/log_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
from datetime import datetime
from typing import Tuple, List, Optional

from PySide6.QtCore import Slot, Signal, QObject, QFileSystemWatcher, QFile, QMetaMethod
from PySide6.QtCore import Slot, Signal, QObject, QFileSystemWatcher, QFile, QMetaMethod, QtMsgType, QMessageLogContext, \
qInstallMessageHandler

from external_processes import get_install_dir
from platform_check import get_platform, PlatformEnum
from qt_extensions import get_signal
from qwarningbannerholder import global_warning_banners


class LogObject(QObject):
Expand Down Expand Up @@ -110,6 +112,7 @@ def create_file(self, file_suffix: str = '') -> Optional[str]:
watch_success = self.file_watcher.addPath(self.tempfile.name)
if not watch_success:
self.log.warning(f'Could not watch external file: {self.tempfile.name}')
global_warning_banners.add(f'Could not watch external file: {self.tempfile.name}')
return None
return self.tempfile.name

Expand All @@ -131,6 +134,26 @@ def stop(self):
self.log.warning(f'Could not remove temp file {self.tempfile.name}')


def qt_message_handler(msg_type: QtMsgType, msg_ctx: QMessageLogContext, msg: str):
qt_log_level_map = {
QtMsgType.QtDebugMsg: logging.DEBUG,
QtMsgType.QtInfoMsg: logging.INFO,
QtMsgType.QtWarningMsg: logging.WARNING,
QtMsgType.QtCriticalMsg: logging.CRITICAL,
QtMsgType.QtFatalMsg: logging.FATAL,
}
py_log_level = qt_log_level_map.get(msg_type, logging.INFO)

if any([msg_ctx.file, msg_ctx.function, msg_ctx.line]):
# I don't think the context is usually filled but here if needed
context_str = f' {msg_ctx.file}:{msg_ctx.function}:{msg_ctx.line}'
else:
context_str = ''
# Don't want to global the `log` variable here (idk if things will break)
log = logging.getLogger('')
log.log(py_log_level, f'Qt:{msg}{context_str}')


def setup_logging(logger, qt_log_obj: LogObject):
logger.setLevel(logging.DEBUG)
# file handler
Expand All @@ -153,4 +176,7 @@ def setup_logging(logger, qt_log_obj: LogObject):
gh.setFormatter(CustomFormatter(colour_type=LogColourTypes.html))
logger.addHandler(gh)

# Qt logging
qInstallMessageHandler(qt_message_handler)

logger.debug(f'Logging initialized (logfile={log_file})')
4 changes: 4 additions & 0 deletions OATFWGUI/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from gui_logic import BusinessLogic
from platform_check import get_platform, PlatformEnum
from external_processes import external_processes, add_external_process, get_install_dir
from qwarningbannerholder import global_warning_banners
from anon_usage_data import create_anon_stats
from misc_utils import delete_directory

Expand All @@ -43,6 +44,7 @@ def check_and_warn_directory_path_length(dir_to_check: Path, max_path_len: int,
lengths greater than the default Windows path length of 260 characters.
'''
log.warning(general_warn_str + warn_str)
global_warning_banners.add(f'{dir_to_check} might have too many characters in it ({num_chars_in_dir})!')


def setup_environment():
Expand Down Expand Up @@ -107,6 +109,7 @@ def raw_version_to_semver() -> Optional[semver.VersionInfo]:
semver_ver = semver.VersionInfo.parse(__version__)
except ValueError as e:
log.warning(f'Could not parse my own version string {__version__} {e}')
global_warning_banners.add(f'Could not parse my own version string {__version__}')
return None
return semver_ver

Expand All @@ -130,6 +133,7 @@ def check_new_oatfwgui_release() -> Optional[Tuple[str, str]]:
release_ver = semver.VersionInfo.parse(release_json['tag_name'])
except ValueError as e:
log.warning(f'Could not parse tag name as semver {release_json["tag_name"]} {e}')
global_warning_banners.add(f'Could not parse tag name as semver {release_json["tag_name"]}')
continue
releases[release_ver] = release_json['html_url']
if latest_release_ver is None or release_ver > latest_release_ver:
Expand Down
105 changes: 56 additions & 49 deletions OATFWGUI/main_widget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,19 @@
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="3" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_upload"/>
</item>
<item row="2" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_build"/>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="wBtn_select_local_config">
<property name="text">
<string>Select local config file</string>
</property>
</widget>
</item>
<item row="5" column="3">
<widget class="QPushButton" name="wBtn_what_stats">
<property name="text">
<string>What will be uploaded?</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="wBtn_upload_fw">
<property name="enabled">
Expand All @@ -48,34 +47,17 @@
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="wCombo_serial_port">
<property name="placeholderText">
<string>No port selected</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="wCombo_pio_env">
<property name="placeholderText">
<string>No FW downloaded yet...</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="wMsg_fw_version">
<item row="1" column="0">
<widget class="QLabel" name="wMsg_pio_env">
<property name="text">
<string>Select firmware version:</string>
<string>Select board:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="wBtn_download_fw">
<property name="enabled">
<bool>false</bool>
</property>
<item row="5" column="3">
<widget class="QPushButton" name="wBtn_what_stats">
<property name="text">
<string>Download</string>
<string>What will be uploaded?</string>
</property>
</widget>
</item>
Expand All @@ -89,17 +71,37 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="wMsg_pio_env">
<item row="0" column="0">
<widget class="QLabel" name="wMsg_fw_version">
<property name="text">
<string>Select board:</string>
<string>Select firmware version:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="wCombo_fw_version">
<item row="0" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_download"/>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="wCombo_pio_env">
<property name="placeholderText">
<string>Grabbing FW Versions...</string>
<string>No FW downloaded yet...</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="wMsg_config_path">
<property name="text">
<string>No config file selected</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="wBtn_download_fw">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
Expand All @@ -116,8 +118,12 @@
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_build"/>
<item row="3" column="1">
<widget class="QComboBox" name="wCombo_serial_port">
<property name="placeholderText">
<string>No port selected</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="wBtn_build_fw">
Expand All @@ -136,19 +142,16 @@
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_upload"/>
</item>
<item row="0" column="4">
<widget class="QBusyIndicatorGoodBad" name="wSpn_download"/>
</item>
<item row="2" column="0" colspan="4">
<widget class="QLabel" name="wMsg_config_path">
<property name="text">
<string>No config file selected</string>
<item row="0" column="1">
<widget class="QComboBox" name="wCombo_fw_version">
<property name="placeholderText">
<string>Grabbing FW Versions...</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="5">
<widget class="QWarningBannerHolder" name="wWarnBanner"/>
</item>
</layout>
</item>
<item>
Expand All @@ -175,7 +178,11 @@
<class>QBusyIndicatorGoodBad</class>
<extends>QWidget</extends>
<header>qbusyindicatorgoodbad</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QWarningBannerHolder</class>
<extends>QWidget</extends>
<header>qwarningbannerholder</header>
</customwidget>
</customwidgets>
<resources/>
Expand Down
3 changes: 3 additions & 0 deletions OATFWGUI/platform_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import platform
import logging

from qwarningbannerholder import global_warning_banners

platform_lookup_cache = None
log = logging.getLogger('')

Expand Down Expand Up @@ -33,5 +35,6 @@ def get_platform() -> PlatformEnum:
log.debug(f'platform_str={platform_str}')
if platform_lookup == PlatformEnum.UNKNOWN:
log.warning(f'Unknown platform {platform_str}!')
global_warning_banners.add(f'Unknown platform {platform_str}!')

return platform_lookup
25 changes: 0 additions & 25 deletions OATFWGUI/qbusyindicatorgoodbad.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,31 +13,6 @@


class BusyIndicatorState(enum.Enum):
# designer_dom_xml = '''
# <ui language='c++'>
# <widget class='QBusyIndicatorGoodBad' name='qBusyIndicatorGoodBad'>
# <property name='fixed_size'>
# <size>
# <width>10</width>
# <height>10</height>
# </size>
# </property>
# </widget>
# </ui>
# '''
#
# def get_fixed_size(self) -> QSize:
# return self._fixed_size
#
# def set_fixed_size(self, fixed_size: QSize):
# self._fixed_size = fixed_size
# self.setFixedSize(fixed_size)
#
# fixed_size = Property(QSize, get_fixed_size, set_fixed_size)
#
# ...
#
# self._fixed_size = QSize(200, 200)
NONE = enum.auto()
BUSY = enum.auto()
GOOD = enum.auto()
Expand Down
2 changes: 1 addition & 1 deletion OATFWGUI/qt_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class RegisteredCustomWidget(QWidget):
def factory(cls: 'RegisteredCustomWidget'):
if not cls.designer_tooltip:
cls.designer_tooltip = f'{cls.__name__} tooltip'
if cls.designer_dom_xml:
if not cls.designer_dom_xml:
cls.designer_dom_xml = f'''
<ui language='c++'>
<widget class='{cls.__name__}' name='{cls.__name__.lower()}'>
Expand Down
53 changes: 53 additions & 0 deletions OATFWGUI/qwarningbannerholder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import List, Set

from PySide6.QtCore import Slot, Signal, Qt, QTimer
from PySide6.QtWidgets import QVBoxLayout, QSizePolicy, QLabel
from qt_extensions import RegisteredCustomWidget

global_warning_banners: Set[str] = set()


class QWarningBannerHolder(RegisteredCustomWidget):
add_warning_signal = Signal(str)

def __init__(self, parent=None):
super().__init__(parent)

self.label_widgets: List[QWarningLabel] = []

self.vbox = QVBoxLayout()
self.vbox.setAlignment(Qt.AlignHCenter)
self.setLayout(self.vbox)

self.check_timer = QTimer(self)
self.check_timer.timeout.connect(self.check_global_warnings)
self.check_timer.setInterval(1000) # every second
self.check_timer.start()

self.add_warning_signal.connect(self.add_warning)

if self.running_in_designer():
global_warning_banners.add('Test warning 1')
global_warning_banners.add('Test warning 2')
global_warning_banners.add('Test warning 3')

def check_global_warnings(self):
# Just go through all of our labels and compare the text
# Not efficient but whatever
for warn_str in global_warning_banners:
if not any(warn_str in wid.text() for wid in self.label_widgets):
self.add_warning_signal.emit(warn_str)

# Need to use signals and slots else we get:
# QObject::setParent: Cannot set parent, new parent is in a different thread
@Slot()
def add_warning(self, text: str):
self.label_widgets.append(QWarningLabel(text))
self.vbox.addWidget(self.label_widgets[-1])


class QWarningLabel(QLabel):
def __init__(self, text: str):
super().__init__(f'WARNING:{text}')
self.setStyleSheet('QLabel { background-color : yellow; }')
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum)
8 changes: 8 additions & 0 deletions OATFWGUI/register_custom_qt_widgets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection

from qbusyindicatorgoodbad import QBusyIndicatorGoodBad
from qwarningbannerholder import QWarningBannerHolder

"""
Set the environment variable PYSIDE_DESIGNER_PLUGINS to this directory and load the plugin,
Expand All @@ -17,3 +18,10 @@
tool_tip=qbusyindicatorgoodbad.designer_tooltip,
xml=qbusyindicatorgoodbad.designer_dom_xml,
)
qwarningbannerholder = QWarningBannerHolder.factory()
QPyDesignerCustomWidgetCollection.registerCustomWidget(
qwarningbannerholder,
module=qwarningbannerholder.designer_module, # idk what this actually affects
tool_tip=qwarningbannerholder.designer_tooltip,
xml=qwarningbannerholder.designer_dom_xml,
)