# -*- coding: utf-8 -*-
# pylint: disable=too-few-public-methods
"""Common widgets and their bases."""
__all__ = ['IconButton']
import typing
from qtpy import QtWidgets, QtCore
from anaconda_navigator.static import images
from anaconda_navigator import widgets
if typing.TYPE_CHECKING:
import typing_extensions
class IconButton(QtWidgets.QPushButton):
"""Common control for icon-only buttons."""
class WarningIcon(QtWidgets.QLabel):
"""
Icon with exclamation sign.
Used by :class:`~WarningLabel` and its derivatives.
"""
class ErrorIcon(QtWidgets.QLabel):
"""
Icon with exclamation sign in circle.
"""
class InfoIcon(QtWidgets.QLabel):
"""
Icon with exclamation sign in circle.
"""
class LabelWithIcon(QtWidgets.QFrame):
"""
Combined label with icon at the beginning.
Icon is shown only when the main text is not empty.
"""
sig_button_clicked = QtCore.Signal()
def __init__( # pylint: disable=too-many-arguments
self,
icon: typing.Optional[widgets.QLabel] = None,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~WarningLabel` instance."""
super().__init__()
self.__icon: 'typing_extensions.Final[widgets.QLabel]' = icon
self.__icon.setVisible(bool(text))
self.__content: 'typing_extensions.Final[widgets.LabelBase]' = widgets.LabelBase()
self.__content.setText(text)
self.__content.setToolTip(tooltip)
self.__content.setWordWrap(True)
self.__button: 'typing_extensions.Final[widgets.LabelBase]' = widgets.LabelBase()
self.__button.setText(button)
self.__button.sig_clicked.connect(self.sig_button_clicked)
self.__layout: 'typing_extensions.Final[QtWidgets.QHBoxLayout]' = QtWidgets.QHBoxLayout()
self.__layout.addWidget(self.__icon, 0, alignment)
self.__layout.addWidget(self.__content, 1, alignment)
if button:
self.__layout.addWidget(self.__button, 0, alignment)
self.__layout.setContentsMargins(0, 0, 0, 0)
self.__layout.setSpacing(4)
self.setLayout(self.__layout)
@property
def text(self) -> str: # noqa: D401
"""Content of the main label."""
return self.__content.text()
@text.setter
def text(self, value: str) -> None:
"""Update `text` value."""
self.__content.setText(value)
self.__icon.setVisible(bool(value))
class WarningLabel(LabelWithIcon):
"""
Combined label with warning icon at the beginning.
Icon is shown only when the main text is not empty.
"""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~WarningLabel` instance."""
super().__init__(icon=WarningIcon(), text=text, tooltip=tooltip, button=button, alignment=alignment)
class WarningBlock(WarningLabel):
"""Same as :class:`~WarningLabel`, but with colored background."""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~WarningBlock` instance."""
super().__init__(text=text, tooltip=tooltip, button=button, alignment=alignment)
class ErrorLabel(LabelWithIcon):
"""
Combined label with error icon at the beginning.
Icon is shown only when the main text is not empty.
"""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~ErrorLabel` instance."""
super().__init__(icon=ErrorIcon(), text=text, tooltip=tooltip, button=button, alignment=alignment)
class ErrorBlock(ErrorLabel):
"""Same as :class:`~ErrorLabel`, but with colored background."""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~ErrorBlock` instance."""
super().__init__(text=text, tooltip=tooltip, button=button, alignment=alignment)
class InfoLabel(LabelWithIcon):
"""
Combined label with info icon at the beginning.
Icon is shown only when the main text is not empty.
"""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~InfoLabel` instance."""
super().__init__(icon=InfoIcon(), text=text, tooltip=tooltip, button=button, alignment=alignment)
class InfoBlock(InfoLabel):
"""Same as :class:`~InfoLabel`, but with colored background."""
def __init__(
self,
text: str = '',
tooltip: str = '',
button: str = '',
alignment: typing.Any = QtCore.Qt.AlignTop,
) -> None:
"""Initialize new :class:`~InfoBlock` instance."""
super().__init__(text=text, tooltip=tooltip, button=button, alignment=alignment)
class TeamEditionServerAlert(QtWidgets.QWidget):
"""Show combined labels with icon about connectivity problems to TE Server."""
def __init__(self) -> None:
super().__init__()
self.error_label: 'typing_extensions.Final[ErrorBlock]' = ErrorBlock(
text=(
'Anaconda Anaconda Server server cannot be reached. '
'Some actions may not work as expected until connection is restored.'
),
alignment=QtCore.Qt.AlignVCenter,
)
self.info_label: 'typing_extensions.Final[InfoBlock]' = InfoBlock(
text='Connection to Anaconda Anaconda Server server restored.',
button=f'',
alignment=QtCore.Qt.AlignVCenter,
)
self.__timer: 'typing_extensions.Final[QtCore.QTimer]' = QtCore.QTimer()
layout: 'typing_extensions.Final[QtWidgets.QVBoxLayout]' = QtWidgets.QVBoxLayout()
layout.addWidget(self.error_label)
layout.addWidget(self.info_label)
self.info_label.sig_button_clicked.connect(self.hide_all)
self.setLayout(layout)
self.hide_all()
def show_info(self, limit: typing.Optional[int] = 5000) -> None:
"""Show info label for `limit` seconds"""
if not self.error_label.isVisible():
self.error_label.hide()
return
self.show()
self.error_label.hide()
self.info_label.show()
if limit:
self.__timer.singleShot(limit, self.hide_all)
def show_error(self) -> None:
"""Show error label"""
self.show()
self.error_label.show()
self.info_label.hide()
def hide_all(self) -> None:
"""Hide all labels."""
self.hide()
self.error_label.hide()
self.info_label.hide()