diff --git a/.github/scripts/modules_test.sh b/.github/scripts/modules_test.sh index 494d1901d44..7f2aa98e1c6 100755 --- a/.github/scripts/modules_test.sh +++ b/.github/scripts/modules_test.sh @@ -115,6 +115,9 @@ for f in spyder/*/*/*/*.py; do if [[ $f == spyder/plugins/editor/panels/__init__.py ]]; then continue fi + if [[ $f == spyder/plugins/findinfiles/widgets/main_widget.py ]]; then + continue + fi python "$f" if [ $? -ne 0 ]; then exit 1 diff --git a/binder/environment.yml b/binder/environment.yml index 1d0592ec524..353b9fae20a 100644 --- a/binder/environment.yml +++ b/binder/environment.yml @@ -40,7 +40,7 @@ dependencies: - pyzmq >=22.1.0 - qdarkstyle >=3.2.0,<3.3.0 - qstylizer >=0.2.2 -- qtawesome >=1.2.1 +- qtawesome >=1.3.0 - qtconsole >=5.5.0,<5.6.0 - qtpy >=2.4.0 - rtree >=0.9.7 diff --git a/requirements/main.yml b/requirements/main.yml index 92e2839b06b..6aa9e87d4ac 100644 --- a/requirements/main.yml +++ b/requirements/main.yml @@ -36,7 +36,7 @@ dependencies: - pyzmq >=22.1.0 - qdarkstyle >=3.2.0,<3.3.0 - qstylizer >=0.2.2 - - qtawesome >=1.2.1 + - qtawesome >=1.3.0 - qtconsole >=5.5.0,<5.6.0 - qtpy >=2.4.0 - rtree >=0.9.7 diff --git a/setup.py b/setup.py index f7f5dc3b908..516658bd0c0 100644 --- a/setup.py +++ b/setup.py @@ -237,7 +237,7 @@ def run(self): 'pyzmq>=22.1.0', 'qdarkstyle>=3.2.0,<3.3.0', 'qstylizer>=0.2.2', - 'qtawesome>=1.2.1', + 'qtawesome>=1.3.0', 'qtconsole>=5.5.0,<5.6.0', 'qtpy>=2.4.0', 'rtree>=0.9.7', diff --git a/spyder/dependencies.py b/spyder/dependencies.py index cebac0e872c..e60002c80e6 100644 --- a/spyder/dependencies.py +++ b/spyder/dependencies.py @@ -64,7 +64,7 @@ PYZMQ_REQVER = '>=22.1.0' QDARKSTYLE_REQVER = '>=3.2.0,<3.3.0' QSTYLIZER_REQVER = '>=0.2.2' -QTAWESOME_REQVER = '>=1.2.1' +QTAWESOME_REQVER = '>=1.3.0' QTCONSOLE_REQVER = '>=5.5.0,<5.6.0' QTPY_REQVER = '>=2.4.0' RTREE_REQVER = '>=0.9.7' diff --git a/spyder/utils/icon_manager.py b/spyder/utils/icon_manager.py index 899cc5d5c3b..24b41f8bf0b 100644 --- a/spyder/utils/icon_manager.py +++ b/spyder/utils/icon_manager.py @@ -352,7 +352,7 @@ def __init__(self): 'folding.arrow_down_on': [('mdi.menu-down',), {'color': self.MAIN_FG_COLOR}], 'lspserver.down': [('mdi.close',), {'color': self.MAIN_FG_COLOR}], 'lspserver.ready': [('mdi.check',), {'color': self.MAIN_FG_COLOR}], - 'dependency_ok': [('mdi.check',), {'color': self.MAIN_FG_COLOR}], + 'dependency_ok': [('mdi.check',), {'color': SpyderPalette.COLOR_SUCCESS_2}], 'dependency_warning': [('mdi.alert',), {'color': SpyderPalette.COLOR_WARN_2}], 'dependency_error': [('mdi.alert',), {'color': SpyderPalette.COLOR_ERROR_1}], 'broken_image': [('mdi.image-broken-variant',), {'color': self.MAIN_FG_COLOR}], diff --git a/spyder/utils/stylesheet.py b/spyder/utils/stylesheet.py index 969444b42f5..564eabb45a4 100644 --- a/spyder/utils/stylesheet.py +++ b/spyder/utils/stylesheet.py @@ -232,9 +232,10 @@ def _customize_stylesheet(self): ) # Adjust padding of QPushButton's in QDialog's - css["QDialog QPushButton"].setValues( - padding='3px 15px 3px 15px', - ) + for widget in ["QPushButton", "QPushButton:disabled"]: + css[f"QDialog {widget}"].setValues( + padding='3px 15px 3px 15px', + ) css["QDialogButtonBox QPushButton:!default"].setValues( padding='3px 0px 3px 0px', diff --git a/spyder/widgets/dependencies.py b/spyder/widgets/dependencies.py index 1905d951d83..96fe1e5a518 100644 --- a/spyder/widgets/dependencies.py +++ b/spyder/widgets/dependencies.py @@ -10,7 +10,6 @@ import sys # Third party imports -from qtpy.QtCore import Qt from qtpy.QtGui import QColor from qtpy.QtWidgets import (QApplication, QDialog, QDialogButtonBox, QHBoxLayout, QVBoxLayout, QLabel, QPushButton, @@ -19,9 +18,11 @@ # Local imports from spyder import __version__ from spyder.config.base import _ -from spyder.dependencies import MANDATORY, OPTIONAL, PLUGIN +from spyder.config.gui import is_dark_interface +from spyder.dependencies import OPTIONAL, PLUGIN from spyder.utils.icon_manager import ima -from spyder.utils.palette import SpyderPalette +from spyder.utils.palette import QStylePalette, SpyderPalette +from spyder.utils.stylesheet import AppStyle, MAC, WIN from spyder.widgets.helperwidgets import PaneEmptyWidget @@ -56,16 +57,29 @@ def update_dependencies(self, dependencies): dependency.required_version, dependency.installed_version, dependency.features]) + # Format content if dependency.check(): item.setIcon(0, ima.icon('dependency_ok')) elif dependency.kind == OPTIONAL: item.setIcon(0, ima.icon('dependency_warning')) item.setBackground(2, QColor(SpyderPalette.COLOR_WARN_1)) + + # Fix foreground color in the light theme + if not is_dark_interface(): + item.setForeground( + 2, QColor(QStylePalette.COLOR_BACKGROUND_1) + ) else: item.setIcon(0, ima.icon('dependency_error')) item.setBackground(2, QColor(SpyderPalette.COLOR_ERROR_1)) + # Fix foreground color in the light theme + if not is_dark_interface(): + item.setForeground( + 2, QColor(QStylePalette.COLOR_BACKGROUND_1) + ) + # Add to tree if dependency.kind == OPTIONAL: optional_item.addChild(item) @@ -87,20 +101,40 @@ def __init__(self, parent): QDialog.__init__(self, parent) # Widgets - self.label = QLabel(_("Optional modules are not required to run " - "Spyder but enhance its functions.")) - self.label2 = QLabel(_("Note: New dependencies or changed ones " - "will be correctly detected only after Spyder " - "is restarted.")) + note1 = _( + "Optional modules are not required to run Spyder but enhance " + "its functions." + ) + + note2 = _( + "New dependencies or changed ones will be correctly detected only " + "after Spyder is restarted." + ) + + notes_vmargin = "0.4em" if WIN else "0.3em" + label = QLabel( + ( + "" + "" + ).format(notes_vmargin, note1, note2) + ) + self.treewidget = DependenciesTreeWidget(self) - btn = QPushButton(_("Copy to clipboard"), ) - bbox = QDialogButtonBox(QDialogButtonBox.Ok) + self.copy_btn = QPushButton(_("Copy to clipboard")) + ok_btn = QDialogButtonBox(QDialogButtonBox.Ok) # Widget setup - self.setWindowTitle("Spyder %s: %s" % (__version__, - _("Dependencies"))) - self.setWindowIcon(ima.icon('tooloptions')) + self.setWindowTitle( + _("Dependencies for Spyder {}").format(__version__) + ) self.setModal(False) + self.copy_btn.setEnabled(False) # Create a QStackedWidget self.stacked_widget = QStackedWidget() @@ -109,7 +143,8 @@ def __init__(self, parent): self.loading_pane = PaneEmptyWidget( self, "dependencies", - _("Please wait while we prepare your dependencies..."), + _("Dependency information will be retrieved shortly. " + "Please wait..."), bottom_stretch=1, spinner=True, ) @@ -123,22 +158,24 @@ def __init__(self, parent): # Layout hlayout = QHBoxLayout() - hlayout.addWidget(btn) + hlayout.addWidget(self.copy_btn) hlayout.addStretch() - hlayout.addWidget(bbox) + hlayout.addWidget(ok_btn) vlayout = QVBoxLayout() + vlayout.setContentsMargins(*((5 * AppStyle.MarginSize,) * 4)) vlayout.addWidget(self.stacked_widget) - vlayout.addWidget(self.label) - vlayout.addWidget(self.label2) + vlayout.addSpacing(AppStyle.MarginSize) + vlayout.addWidget(label) + vlayout.addSpacing((-2 if MAC else 1) * AppStyle.MarginSize) vlayout.addLayout(hlayout) self.setLayout(vlayout) - self.resize(860, 560) + self.setFixedSize(860, 560) # Signals - btn.clicked.connect(self.copy_to_clipboard) - bbox.accepted.connect(self.accept) + self.copy_btn.clicked.connect(self.copy_to_clipboard) + ok_btn.accepted.connect(self.accept) def set_data(self, dependencies): self.treewidget.update_dependencies(dependencies) @@ -147,6 +184,9 @@ def set_data(self, dependencies): # Once data is loaded, switch to the tree widget self.stacked_widget.setCurrentWidget(self.treewidget) + # Enable copy button + self.copy_btn.setEnabled(True) + def copy_to_clipboard(self): from spyder.dependencies import status @@ -169,7 +209,7 @@ def test(): ">=0.10", kind=OPTIONAL) from spyder.utils.qthelpers import qapplication - app = qapplication() + app = qapplication() # noqa dlg = DependenciesDialog(None) dlg.set_data(dependencies.DEPENDENCIES) dlg.show() diff --git a/spyder/widgets/helperwidgets.py b/spyder/widgets/helperwidgets.py index ad0033d406c..581e743499e 100644 --- a/spyder/widgets/helperwidgets.py +++ b/spyder/widgets/helperwidgets.py @@ -37,8 +37,7 @@ from spyder.utils.stringmatching import get_search_regex from spyder.utils.palette import QStylePalette, SpyderPalette from spyder.utils.image_path_manager import get_image_path -from spyder.utils.stylesheet import AppStyle, DialogStyle -from spyder.utils.qthelpers import create_waitspinner +from spyder.utils.stylesheet import AppStyle # Valid finder chars. To be improved @@ -579,6 +578,10 @@ def __init__( ): super().__init__(parent) + # Attributes + self._is_shown = False + self._spin = None + interface_font_size = self.get_font( SpyderFontType.Interface).pointSize() @@ -625,17 +628,20 @@ def __init__( pane_empty_layout.addWidget(image_label) # Display spinner if requested - if spinner is not False: + if spinner: spin_widget = qta.IconWidget() + self._spin = qta.Spin(spin_widget, interval=3, autostart=False) spin_icon = qta.icon( "mdi.loading", - color="white", - animation=qta.Spin(spin_widget, interval=3), + color=ima.MAIN_FG_COLOR, + animation=self._spin ) + spin_widget.setIconSize(QSize(32, 32)) spin_widget.setIcon(spin_icon) spin_widget.setStyleSheet(image_label_qss.toString()) spin_widget.setAlignment(Qt.AlignCenter) + pane_empty_layout.addWidget(spin_widget) pane_empty_layout.addItem(QSpacerItem(20, 20)) @@ -656,6 +662,8 @@ def __init__( self.setFocusPolicy(Qt.StrongFocus) self._apply_stylesheet(False) + # ---- Public methods + # ------------------------------------------------------------------------- def setup(self, *args, **kwargs): """ This method is needed when using this widget to show a "no connected @@ -711,6 +719,22 @@ def get_icon(self, icon_filename): return final_pm + # ---- Qt methods + # ------------------------------------------------------------------------- + def showEvent(self, event): + """Adjustments when the widget is shown.""" + if not self._is_shown: + self._start_spinner() + self._is_shown = True + + super().showEvent(event) + + def hideEvent(self, event): + """Adjustments when the widget is hidden.""" + self._stop_spinner() + self._is_shown = False + super().hideEvent(event) + def focusInEvent(self, event): self._apply_stylesheet(True) super().focusOutEvent(event) @@ -719,6 +743,8 @@ def focusOutEvent(self, event): self._apply_stylesheet(False) super().focusOutEvent(event) + # ---- Private methods + # ------------------------------------------------------------------------- def _apply_stylesheet(self, focus): if focus: border_color = QStylePalette.COLOR_ACCENT_3 @@ -735,6 +761,19 @@ def _apply_stylesheet(self, focus): self.setStyleSheet(qss.toString()) + def _start_spinner(self): + """ + Start spinner when requested, in case the widget has one (it's stopped + by default). + """ + if self._spin is not None: + self._spin.start() + + def _stop_spinner(self): + """Stop spinner when requested, in case the widget has one.""" + if self._spin is not None: + self._spin.stop() + class HoverRowsTableView(QTableView): """