Skip to content

Commit

Permalink
Combine error and warning boxes that have the same message
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindjahren authored Jun 17, 2024
1 parent f29176b commit 90998f2
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 38 deletions.
131 changes: 100 additions & 31 deletions src/ert/gui/suggestor/_suggestor_message.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from __future__ import annotations

from typing import TYPE_CHECKING

from PyQt5 import QtSvg
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
Expand All @@ -10,9 +8,10 @@
QHBoxLayout,
QLabel,
QSizePolicy,
QVBoxLayout,
QWidget,
)
from typing_extensions import Self
from typing_extensions import Any, Self

from ._colors import (
BLUE_BACKGROUND,
Expand All @@ -23,9 +22,6 @@
YELLOW_TEXT,
)

if TYPE_CHECKING:
from ert.config import ErrorInfo, WarningInfo


def _svg_icon(image_name: str) -> QtSvg.QSvgWidget:
widget = QtSvg.QSvgWidget(f"img:{image_name}.svg")
Expand All @@ -40,7 +36,8 @@ def __init__(
text_color: str,
bg_color: str,
icon: QWidget,
info: ErrorInfo,
message: str,
locations: list[str],
) -> None:
super().__init__()
self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground)
Expand All @@ -58,39 +55,111 @@ def __init__(
self.setGraphicsEffect(shadowEffect)
self.setContentsMargins(0, 0, 0, 0)

self.icon = icon
info.message = info.message.replace("<", "&lt;").replace(">", "&gt;")
self.lbl = QLabel(
'<div style="font-size: 16px; line-height: 24px;">'
+ f'<b style="color: {text_color}">'
+ header
+ "</b>"
+ info.message
+ "<p>"
+ info.location()
+ "</p>"
+ "</div>"
)
self._icon = icon
self._message = message.replace("<", "&lt;").replace(">", "&gt;")
self._locations = locations
self._header = header
self._text_color = text_color

self._hbox = QHBoxLayout()
self._hbox.setContentsMargins(16, 16, 16, 16)
self._hbox.addWidget(self._icon, alignment=Qt.AlignmentFlag.AlignTop)
self.setLayout(self._hbox)

self.lbl = QLabel(self._collapsed_text())
self.lbl.setOpenExternalLinks(False)
self.lbl.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.lbl.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
self.lbl.setWordWrap(True)
self._expanded = False
if len(self._locations) > 1:
self._expand_collapse_label = QLabel(self._expand_link())
self._expand_collapse_label.setOpenExternalLinks(False)
self._expand_collapse_label.linkActivated.connect(self._toggle_expand)

self._vbox = QWidget()
layout = QVBoxLayout()
self._vbox.setLayout(layout)
layout.addWidget(self.lbl)
layout.addWidget(self._expand_collapse_label)
self._hbox.addWidget(self._vbox, alignment=Qt.AlignmentFlag.AlignTop)
else:
self._expand_collapse_label = QLabel()
self._hbox.addWidget(self.lbl, alignment=Qt.AlignmentFlag.AlignTop)

def _toggle_expand(self, _link: Any) -> None:
if self._expanded:
self.lbl.setText(self._collapsed_text())
self._expand_collapse_label.setText(self._expand_link())
else:
self.lbl.setText(self._expanded_text())
self._expand_collapse_label.setText(self._hide_link())
self._expanded = not self._expanded

def _hide_link(self) -> str:
return " <a href=#morelocations>show less</a>"

def _expand_link(self) -> str:
return f" <a href=#morelocations>and {len(self._locations) - 1} more</a>"

def _collapsed_text(self) -> str:
location_paragraph = ""
if self._locations:
location_paragraph = self._locations[0]
location_paragraph = (
"<p>" + self._color_bold("location: ") + location_paragraph + "</p>"
)

self.hbox = QHBoxLayout()
self.hbox.setContentsMargins(16, 16, 16, 16)
self.hbox.addWidget(self.icon, alignment=Qt.AlignmentFlag.AlignTop)
self.hbox.addWidget(self.lbl, alignment=Qt.AlignmentFlag.AlignTop)
self.setLayout(self.hbox)
return self._text(location_paragraph)

def _expanded_text(self) -> str:
location_paragraphs = ""
first = True
for loc in self._locations:
if first:
location_paragraphs += f'<p>{self._color_bold("location:")}{loc}</p>'
first = False
else:
location_paragraphs += f"<p>{loc}</p>"

return self._text(location_paragraphs)

def _text(self, location: str) -> str:
return (
'<div style="font-size: 16px; line-height: 24px;">'
+ self._color_bold(self._header)
+ self._message
+ location
+ "</div>"
)

def _color_bold(self, text: str) -> str:
return f'<b style="color: {self._text_color}">{text}</b>'

@classmethod
def error_msg(cls, info: ErrorInfo) -> Self:
return cls("Error: ", RED_TEXT, RED_BACKGROUND, _svg_icon("error"), info)
def error_msg(cls, message: str, locations: list[str]) -> Self:
return cls(
"Error: ", RED_TEXT, RED_BACKGROUND, _svg_icon("error"), message, locations
)

@classmethod
def warning_msg(cls, info: WarningInfo) -> Self:
def warning_msg(cls, message: str, locations: list[str]) -> Self:
return cls(
"Warning: ", YELLOW_TEXT, YELLOW_BACKGROUND, _svg_icon("warning"), info
"Warning: ",
YELLOW_TEXT,
YELLOW_BACKGROUND,
_svg_icon("warning"),
message,
locations,
)

@classmethod
def deprecation_msg(cls, info: WarningInfo) -> Self:
return cls("Deprecation: ", BLUE_TEXT, BLUE_BACKGROUND, _svg_icon("bell"), info)
def deprecation_msg(cls, message: str, locations: list[str]) -> Self:
return cls(
"Deprecation: ",
BLUE_TEXT,
BLUE_BACKGROUND,
_svg_icon("bell"),
message,
locations,
)
27 changes: 20 additions & 7 deletions src/ert/gui/suggestor/suggestor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import functools
import logging
import webbrowser
from typing import TYPE_CHECKING, Callable, Dict, List, Optional
from collections import defaultdict
from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Sequence

from PyQt5.QtGui import QCursor
from qtpy.QtCore import Qt
Expand Down Expand Up @@ -33,6 +34,13 @@ def _clicked_help_button(menu_label: str, link: str) -> None:
webbrowser.open(link)


def _combine_messages(infos: Sequence[ErrorInfo]) -> list[tuple[str, list[str]]]:
combined = defaultdict(list)
for info in infos:
combined[info.message].append(info.location())
return list(combined.items())


LIGHT_GREY = "#f7f7f7"
MEDIUM_GREY = "#eaeaea"
HEAVY_GREY = "#dcdcdc"
Expand Down Expand Up @@ -232,6 +240,7 @@ def _messages(
NUM_COLUMNS = 2

suggest_msgs = QWidget(parent=self)
suggest_msgs.setObjectName("suggestor_messages")
suggest_msgs.setContentsMargins(0, 0, 16, 0)
suggest_layout = QGridLayout()
suggest_layout.setContentsMargins(0, 0, 0, 0)
Expand All @@ -241,20 +250,24 @@ def _messages(
column = 0
row = 0
num = 0
for msg in errors:
suggest_layout.addWidget(SuggestorMessage.error_msg(msg), row, column)
for combined in _combine_messages(errors):
suggest_layout.addWidget(SuggestorMessage.error_msg(*combined), row, column)
if column:
row += 1
column = (column + 1) % NUM_COLUMNS
num += 1
for msg in warnings:
suggest_layout.addWidget(SuggestorMessage.warning_msg(msg), row, column)
for combined in _combine_messages(warnings):
suggest_layout.addWidget(
SuggestorMessage.warning_msg(*combined), row, column
)
if column:
row += 1
column = (column + 1) % NUM_COLUMNS
num += 1
for msg in deprecations:
suggest_layout.addWidget(SuggestorMessage.deprecation_msg(msg), row, column)
for combined in _combine_messages(deprecations):
suggest_layout.addWidget(
SuggestorMessage.deprecation_msg(*combined), row, column
)
if column:
row += 1
column = (column + 1) % NUM_COLUMNS
Expand Down
23 changes: 23 additions & 0 deletions tests/unit_tests/gui/test_suggestor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import pytest
from qtpy.QtWidgets import QWidget

from ert.config import ErrorInfo
from ert.gui.suggestor import Suggestor


@pytest.mark.parametrize(
"errors, expected_num",
[
([ErrorInfo("msg_1")], 1),
([ErrorInfo("msg_1"), ErrorInfo("msg_2")], 2),
([ErrorInfo("msg_1"), ErrorInfo("msg_1"), ErrorInfo("msg_2")], 2),
([ErrorInfo("msg_1"), ErrorInfo("msg_2"), ErrorInfo("msg_3")], 3),
],
)
def test_suggestor_combines_errors_with_the_same_message(qtbot, errors, expected_num):
suggestor = Suggestor(errors, [], [], lambda: None)
msgs = suggestor.findChild(QWidget, name="suggestor_messages")
assert msgs is not None
msg_layout = msgs.layout()
assert msg_layout is not None
assert msg_layout.count() == expected_num

0 comments on commit 90998f2

Please sign in to comment.