diff --git a/OATFWGUI/log_utils.py b/OATFWGUI/log_utils.py
index 0a19b48..a58bd46 100644
--- a/OATFWGUI/log_utils.py
+++ b/OATFWGUI/log_utils.py
@@ -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):
@@ -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
@@ -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
@@ -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})')
diff --git a/OATFWGUI/main.py b/OATFWGUI/main.py
index 790585f..ebf5465 100755
--- a/OATFWGUI/main.py
+++ b/OATFWGUI/main.py
@@ -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
@@ -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():
@@ -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
@@ -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:
diff --git a/OATFWGUI/main_widget.ui b/OATFWGUI/main_widget.ui
index 8ee85c7..0b0f693 100644
--- a/OATFWGUI/main_widget.ui
+++ b/OATFWGUI/main_widget.ui
@@ -24,6 +24,12 @@
-
+
-
+
+
+ -
+
+
-
@@ -31,13 +37,6 @@
- -
-
-
- What will be uploaded?
-
-
-
-
@@ -48,34 +47,17 @@
- -
-
-
- No port selected
-
-
-
- -
-
-
- No FW downloaded yet...
-
-
-
- -
-
+
-
+
- Select firmware version:
+ Select board:
- -
-
-
- false
-
+
-
+
- Download
+ What will be uploaded?
@@ -89,17 +71,37 @@
- -
-
+
-
+
- Select board:
+ Select firmware version:
- -
-
+
-
+
+
+ -
+
- Grabbing FW Versions...
+ No FW downloaded yet...
+
+
+
+ -
+
+
+ No config file selected
+
+
+
+ -
+
+
+ false
+
+
+ Download
@@ -116,8 +118,12 @@
- -
-
+
-
+
+
+ No port selected
+
+
-
@@ -136,19 +142,16 @@
- -
-
-
- -
-
-
- -
-
-
- No config file selected
+
-
+
+
+ Grabbing FW Versions...
+ -
+
+
-
@@ -175,7 +178,11 @@
QBusyIndicatorGoodBad
QWidget
- 1
+
+
+ QWarningBannerHolder
+ QWidget
+
diff --git a/OATFWGUI/platform_check.py b/OATFWGUI/platform_check.py
index 8049c7e..28df41a 100644
--- a/OATFWGUI/platform_check.py
+++ b/OATFWGUI/platform_check.py
@@ -2,6 +2,8 @@
import platform
import logging
+from qwarningbannerholder import global_warning_banners
+
platform_lookup_cache = None
log = logging.getLogger('')
@@ -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
diff --git a/OATFWGUI/qbusyindicatorgoodbad.py b/OATFWGUI/qbusyindicatorgoodbad.py
index 1a3931a..6778d29 100644
--- a/OATFWGUI/qbusyindicatorgoodbad.py
+++ b/OATFWGUI/qbusyindicatorgoodbad.py
@@ -13,31 +13,6 @@
class BusyIndicatorState(enum.Enum):
- # designer_dom_xml = '''
- #
- #
- #
- #
- # 10
- # 10
- #
- #
- #
- #
- # '''
- #
- # 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()
diff --git a/OATFWGUI/qt_extensions.py b/OATFWGUI/qt_extensions.py
index 6c4a775..c315d3a 100644
--- a/OATFWGUI/qt_extensions.py
+++ b/OATFWGUI/qt_extensions.py
@@ -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'''
diff --git a/OATFWGUI/qwarningbannerholder.py b/OATFWGUI/qwarningbannerholder.py
new file mode 100644
index 0000000..44b8322
--- /dev/null
+++ b/OATFWGUI/qwarningbannerholder.py
@@ -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)
diff --git a/OATFWGUI/register_custom_qt_widgets.py b/OATFWGUI/register_custom_qt_widgets.py
index 8bdfbda..7ae6bf9 100644
--- a/OATFWGUI/register_custom_qt_widgets.py
+++ b/OATFWGUI/register_custom_qt_widgets.py
@@ -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,
@@ -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,
+ )