Skip to content

Commit

Permalink
Type check ert.gui.ertwidgets
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindjahren committed Jun 17, 2024
1 parent f29176b commit faeebf8
Show file tree
Hide file tree
Showing 29 changed files with 240 additions and 162 deletions.
9 changes: 6 additions & 3 deletions .mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,21 @@ ignore_missing_imports = True
[mypy-ert._clib.*]
ignore_missing_imports = True

[mypy-ert.gui.ertwidgets.*]
[mypy-ert.gui.model.node]
ignore_missing_imports = True
ignore_errors = True

[mypy-ert.gui.model.node]
[mypy-ert.gui.model.snapshot]
ignore_missing_imports = True
ignore_errors = True

[mypy-ert.gui.model.snapshot]
[mypy-ert.gui.ertwidgets.validationsupport]
ignore_missing_imports = True
ignore_errors = True

[mypy-ert.gui.ertwidgets.analysismodulevariablepanel]
ignore_missing_imports = True
ignore_errors = True

[mypy-ert.gui.simulation.*]
ignore_missing_imports = True
Expand Down
7 changes: 4 additions & 3 deletions src/ert/gui/ertwidgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from qtpy.QtCore import Qt
from qtpy.QtGui import QCursor
from qtpy.QtWidgets import QApplication
from typing import Callable, Any


def showWaitCursorWhileWaiting(func):
def showWaitCursorWhileWaiting(func: Callable[..., Any]) -> Callable[..., Any]:
"""A function decorator to show the wait cursor while the function is working."""

def wrapper(*arg):
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
def wrapper(*arg: Any) -> Any:
QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
try:
res = func(*arg)
return res
Expand Down
8 changes: 6 additions & 2 deletions src/ert/gui/ertwidgets/analysismoduleedit.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(
variables_popup_button.clicked.connect(self.showVariablesPopup)
variables_popup_button.setMaximumSize(20, 20)

layout.addWidget(variables_popup_button, 0, Qt.AlignLeft)
layout.addWidget(variables_popup_button, 0, Qt.AlignmentFlag.AlignLeft)
layout.setContentsMargins(QMargins(0, 0, 0, 0))
layout.addStretch()

Expand All @@ -40,5 +40,9 @@ def showVariablesPopup(self) -> None:
variable_dialog = AnalysisModuleVariablesPanel(
self.analysis_module, self.ensemble_size
)
dialog = ClosableDialog("Edit variables", variable_dialog, self.parent())
dialog = ClosableDialog(
"Edit variables",
variable_dialog,
self.parent(), # type: ignore
)
dialog.exec_()
51 changes: 28 additions & 23 deletions src/ert/gui/ertwidgets/checklist.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from qtpy.QtCore import QSize, Qt
from __future__ import annotations

from typing import TYPE_CHECKING, Optional

from qtpy.QtCore import QPoint, QSize, Qt
from qtpy.QtGui import QIcon
from qtpy.QtWidgets import (
QAbstractItemView,
Expand All @@ -14,14 +18,21 @@

from ert.gui.ertwidgets import SearchBox

if TYPE_CHECKING:
from .models.selectable_list_model import SelectableListModel


class CheckList(QWidget):
def __init__(self, model, label: str = "", custom_filter_button=None):
def __init__(
self,
model: SelectableListModel,
label: str = "",
custom_filter_button: Optional[QToolButton] = None,
):
"""
:param custom_filter_button: if needed, add a button that opens a
custom filter menu. Useful when search alone isn't enough to filter the
list.
:type custom_filter_button: QToolButton
"""
QWidget.__init__(self)

Expand All @@ -32,7 +43,7 @@ def __init__(self, model, label: str = "", custom_filter_button=None):
self._createCheckButtons()

self._list = QListWidget()
self._list.setContextMenuPolicy(Qt.CustomContextMenu)
self._list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self._list.setSelectionMode(QAbstractItemView.ExtendedSelection)

self._search_box = SearchBox()
Expand Down Expand Up @@ -76,20 +87,20 @@ def _createCheckButtons(self) -> None:
self._checkAllButton = QToolButton()
self._checkAllButton.setIcon(QIcon("img:check.svg"))
self._checkAllButton.setIconSize(QSize(16, 16))
self._checkAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
self._checkAllButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
self._checkAllButton.setAutoRaise(True)
self._checkAllButton.setToolTip("Select all")
self._uncheckAllButton = QToolButton()
self._uncheckAllButton.setIcon(QIcon("img:checkbox_outline.svg"))
self._uncheckAllButton.setIconSize(QSize(16, 16))
self._uncheckAllButton.setToolButtonStyle(Qt.ToolButtonIconOnly)
self._uncheckAllButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
self._uncheckAllButton.setAutoRaise(True)
self._uncheckAllButton.setToolTip("Unselect all")

def itemChanged(self, item: QListWidgetItem):
if item.checkState() == Qt.Checked:
def itemChanged(self, item: QListWidgetItem) -> None:
if item.checkState() == Qt.CheckState.Checked:
self._model.selectValue(str(item.text()))
elif item.checkState() == Qt.Unchecked:
elif item.checkState() == Qt.CheckState.Unchecked:
self._model.unselectValue(str(item.text()))
else:
raise AssertionError("Unhandled checkstate!")
Expand All @@ -101,12 +112,12 @@ def modelChanged(self) -> None:

for item in items:
list_item = QListWidgetItem(item)
list_item.setFlags(list_item.flags() | Qt.ItemIsUserCheckable)
list_item.setFlags(list_item.flags() | Qt.ItemFlag.ItemIsUserCheckable)

if self._model.isValueSelected(item):
list_item.setCheckState(Qt.Checked)
list_item.setCheckState(Qt.CheckState.Checked)
else:
list_item.setCheckState(Qt.Unchecked)
list_item.setCheckState(Qt.CheckState.Unchecked)

self._list.addItem(list_item)

Expand All @@ -117,6 +128,7 @@ def filterList(self, _filter: str) -> None:

for index in range(0, self._list.count()):
item = self._list.item(index)
assert item is not None
text = item.text().lower()

if not _filter or _filter in text:
Expand All @@ -130,6 +142,7 @@ def checkAll(self) -> None:
"""
for index in range(0, self._list.count()):
item = self._list.item(index)
assert item is not None
if not item.isHidden():
self._model.selectValue(str(item.text()))

Expand All @@ -140,22 +153,14 @@ def uncheckAll(self) -> None:
self._model.unselectAll()

def checkSelected(self) -> None:
items = []
for item in self._list.selectedItems():
items.append(str(item.text()))

for item in items:
self._model.selectValue(item)
self._model.selectValue(str(item.text()))

def uncheckSelected(self) -> None:
items = []
for item in self._list.selectedItems():
items.append(str(item.text()))

for item in items:
self._model.unselectValue(item)
self._model.unselectValue(str(item.text()))

def showContextMenu(self, point):
def showContextMenu(self, point: QPoint) -> None:
p = self._list.mapToGlobal(point)
menu = QMenu()
check_selected = menu.addAction("Check selected")
Expand Down
20 changes: 14 additions & 6 deletions src/ert/gui/ertwidgets/closabledialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from qtpy.QtWidgets import QDialog, QHBoxLayout, QPushButton, QVBoxLayout, QWidget

if TYPE_CHECKING:
from qtpy.QtGui import QKeyEvent
from qtpy.QtWidgets import QT_SLOT


Expand All @@ -16,9 +17,14 @@ def __init__(
QDialog.__init__(self, parent)
self.setWindowTitle(title)
self.setModal(True)
self.setWindowFlags(self.windowFlags() | Qt.CustomizeWindowHint)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
self.setWindowFlags(self.windowFlags() & ~Qt.WindowCloseButtonHint)
self.setWindowFlags(self.windowFlags() | Qt.WindowType.CustomizeWindowHint)
self.setWindowFlags(
self.windowFlags()
& ~Qt.WindowFlags(Qt.WindowType.WindowContextHelpButtonHint)
)
self.setWindowFlags(
self.windowFlags() & ~Qt.WindowFlags(Qt.WindowType.WindowCloseButtonHint)
)

layout = QVBoxLayout()
layout.addWidget(widget, stretch=1)
Expand All @@ -41,9 +47,11 @@ def disableCloseButton(self) -> None:
def enableCloseButton(self) -> None:
self.close_button.setEnabled(True)

def keyPressEvent(self, q_key_event):
if self.close_button.isEnabled() or q_key_event.key() != Qt.Key_Escape:
QDialog.keyPressEvent(self, q_key_event)
def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None:
if self.close_button.isEnabled() or (
a0 is not None and a0.key() != Qt.Key.Key_Escape
):
QDialog.keyPressEvent(self, a0)

def addButton(self, caption: str, listener: QT_SLOT) -> None:
button = QPushButton(caption)
Expand Down
5 changes: 3 additions & 2 deletions src/ert/gui/ertwidgets/create_experiment_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ def __init__(
)
buttons.accepted.connect(self.accept)
buttons.rejected.connect(self.reject)
self._ok_button = buttons.button(QDialogButtonBox.Ok)
assert self._ok_button
ok_button = buttons.button(QDialogButtonBox.Ok)
assert ok_button
self._ok_button = ok_button

self._ok_button.clicked.connect(
lambda: self.onDone.emit(
Expand Down
2 changes: 1 addition & 1 deletion src/ert/gui/ertwidgets/ensemblelist.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,5 @@ def updateList(self) -> None:
item = QListWidgetItem(
f"{ensemble.name} - {ensemble.started_at} ({ensemble.id})"
)
item.setData(Qt.UserRole, ensemble)
item.setData(Qt.ItemDataRole.UserRole, ensemble)
self._list.addItem(item)
6 changes: 3 additions & 3 deletions src/ert/gui/ertwidgets/ensembleselector.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def populate(self) -> None:

def _ensemble_list(self) -> Iterable[Ensemble]:
if self._show_only_undefined:
ensemble_list = (
ensembles = (
ensemble
for ensemble in self.notifier.storage.ensembles
if all(
Expand All @@ -90,8 +90,8 @@ def _ensemble_list(self) -> Iterable[Ensemble]:
)
)
else:
ensemble_list = self.notifier.storage.ensembles
ensemble_list = list(ensemble_list)
ensembles = self.notifier.storage.ensembles
ensemble_list = list(ensembles)
if self._show_only_no_children:
parents = [
ens.parent for ens in self.notifier.storage.ensembles if ens.parent
Expand Down
5 changes: 2 additions & 3 deletions src/ert/gui/ertwidgets/legend.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Optional

from qtpy.QtCore import QSize
from qtpy.QtGui import QColor, QPainter
from qtpy.QtGui import QColor, QPainter, QPaintEvent
from qtpy.QtWidgets import QHBoxLayout, QLabel, QWidget


Expand All @@ -16,8 +16,7 @@ def __init__(self, color: QColor):

self.color = color

def paintEvent(self, paintevent):
"""Paints the box"""
def paintEvent(self, a0: Optional[QPaintEvent]) -> None:
painter = QPainter(self)

rect = self.contentsRect()
Expand Down
49 changes: 32 additions & 17 deletions src/ert/gui/ertwidgets/listeditbox.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import List
from typing import Iterable, List, Optional

from qtpy.QtCore import QSize, Qt
from qtpy.QtGui import QIcon
from qtpy.QtGui import QIcon, QKeyEvent
from qtpy.QtWidgets import (
QCompleter,
QHBoxLayout,
Expand All @@ -17,19 +17,26 @@

class AutoCompleteLineEdit(QLineEdit):
# http://blog.elentok.com/2011/08/autocomplete-textbox-for-multiple.html
def __init__(self, items, parent=None):
def __init__(
self, items: Iterable[Optional[str]], parent: Optional[QWidget] = None
):
super().__init__(parent)

self._separators = [",", " "]

self._completer = QCompleter(items, self)
self._completer.setWidget(self)
self._completer.activated[str].connect(self.__insertCompletion)
self._completer.setCaseSensitivity(Qt.CaseInsensitive)
self._completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)

self.__keysToIgnore = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab]
self.__keysToIgnore = [
Qt.Key.Key_Enter,
Qt.Key.Key_Return,
Qt.Key.Key_Escape,
Qt.Key.Key_Tab,
]

def __insertCompletion(self, completion):
def __insertCompletion(self, completion: str) -> None:
extra = len(completion) - len(self._completer.completionPrefix())
extra_text = completion[-extra:]
extra_text += ", "
Expand All @@ -44,26 +51,34 @@ def textUnderCursor(self) -> str:
i -= 1
return text_under_cursor

def keyPressEvent(self, event):
if self._completer.popup().isVisible() and event.key() in self.__keysToIgnore:
event.ignore()
def keyPressEvent(self, a0: Optional[QKeyEvent]) -> None:
popup = self._completer.popup()
if (
popup is not None
and popup.isVisible()
and a0 is not None
and a0.key() in self.__keysToIgnore
):
a0.ignore()
return

super().keyPressEvent(event)
super().keyPressEvent(a0)

completion_prefix = self.textUnderCursor()
if completion_prefix != self._completer.completionPrefix():
self.__updateCompleterPopupItems(completion_prefix)
if len(event.text()) > 0 and len(completion_prefix) > 0:
if a0 is not None and len(a0.text()) > 0 and len(completion_prefix) > 0:
self._completer.complete()
if len(completion_prefix) == 0:
self._completer.popup().hide()
if popup is not None and len(completion_prefix) == 0:
popup.hide()

def __updateCompleterPopupItems(self, completionPrefix):
def __updateCompleterPopupItems(self, completionPrefix: Optional[str]) -> None:
self._completer.setCompletionPrefix(completionPrefix)
self._completer.popup().setCurrentIndex(
self._completer.completionModel().index(0, 0)
)
popup = self._completer.popup()
assert popup is not None
model = self._completer.completionModel()
assert model is not None
popup.setCurrentIndex(model.index(0, 0))


class ListEditBox(QWidget):
Expand Down
6 changes: 4 additions & 2 deletions src/ert/gui/ertwidgets/message_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def __init__(
super().__init__(parent)
self.box = QDialogButtonBox(
QDialogButtonBox.Ok,
centerButtons=True,
)
self.box.setCenterButtons(True)
self.box.accepted.connect(self.accept)

self.details_text = QTextEdit()
Expand All @@ -39,7 +39,9 @@ def __init__(

self.label_text = QLabel(text)
self.label_icon = QLabel()
icon = self.style().standardIcon(QStyle.SP_MessageBoxCritical)
style = self.style()
assert style is not None
icon = style.standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical)
self.label_icon.setPixmap(icon.pixmap(32))

lay = QGridLayout(self)
Expand Down
Loading

0 comments on commit faeebf8

Please sign in to comment.