diff --git a/spyder/plugins/application/container.py b/spyder/plugins/application/container.py index f3dd0d7a43b..86e1d2029db 100644 --- a/spyder/plugins/application/container.py +++ b/spyder/plugins/application/container.py @@ -15,8 +15,8 @@ import sys # Third party imports -from qtpy.QtCore import Qt, QThread, Slot -from qtpy.QtWidgets import QMessageBox, QAction +from qtpy.QtCore import Qt, QThread, QTimer, Slot +from qtpy.QtWidgets import QAction, QMessageBox # Local imports from spyder import ( @@ -24,7 +24,6 @@ from spyder import dependencies from spyder.api.translations import get_translation from spyder.api.widgets.main_container import PluginMainContainer -from spyder.config.base import DEV from spyder.config.utils import is_anaconda from spyder.utils.qthelpers import start_file, DialogManager from spyder.widgets.about import AboutDialog @@ -64,7 +63,11 @@ class ApplicationActions: class ApplicationContainer(PluginMainContainer): + def setup(self): + # Compute dependencies in a thread to not block the interface. + self.dependencies_thread = QThread() + # Attributes self.dialog_manager = DialogManager() self.give_updates_feedback = False @@ -142,11 +145,6 @@ def setup(self): shortcut_context="_", register_shortcut=True) - # Initialize - if DEV is None and self.get_conf('check_updates_on_startup'): - self.give_updates_feedback = False - self.check_updates(startup=True) - def update_actions(self): pass @@ -174,6 +172,7 @@ def _check_updates_ready(self): box = MessageCheckBox(icon=QMessageBox.Information, parent=self) box.setWindowTitle(_("New Spyder version")) + box.setAttribute(Qt.WA_ShowWithoutActivating) box.set_checkbox_text(_("Check for updates at startup")) box.setStandardButtons(QMessageBox.Ok) box.setDefaultButton(QMessageBox.Ok) @@ -216,7 +215,7 @@ def _check_updates_ready(self): msg = header + content + footer box.setText(msg) box.set_check_visible(True) - box.exec_() + box.show() check_updates = box.is_checked() elif feedback: msg = _("Spyder is up to date.") @@ -249,7 +248,15 @@ def check_updates(self, startup=False): self.worker_updates.sig_ready.connect(self.thread_updates.quit) self.worker_updates.moveToThread(self.thread_updates) self.thread_updates.started.connect(self.worker_updates.start) - self.thread_updates.start() + + # Delay starting this check to avoid blocking the main window + # while loading. + # Fixes spyder-ide/spyder#15839 + updates_timer = QTimer(self) + updates_timer.setInterval(3000) + updates_timer.setSingleShot(True) + updates_timer.timeout.connect(self.thread_updates.start) + updates_timer.start() @Slot() def show_dependencies(self): @@ -271,7 +278,16 @@ def show_windows_env_variables(self): def compute_dependencies(self): """Compute dependencies""" - dependencies.declare_dependencies() + self.dependencies_thread.run = dependencies.declare_dependencies + self.dependencies_thread.finished.connect( + self.report_missing_dependencies) + + # This avoids computing missing deps before the window is fully up + dependencies_timer = QTimer(self) + dependencies_timer.setInterval(10000) + dependencies_timer.setSingleShot(True) + dependencies_timer.timeout.connect(self.dependencies_thread.start) + dependencies_timer.start() @Slot() def report_missing_dependencies(self): @@ -304,6 +320,7 @@ def report_missing_dependencies(self): message_box = QMessageBox(self) message_box.setIcon(QMessageBox.Critical) message_box.setAttribute(Qt.WA_DeleteOnClose) + message_box.setAttribute(Qt.WA_ShowWithoutActivating) message_box.setStandardButtons(QMessageBox.Ok) message_box.setWindowModality(Qt.NonModal) message_box.setWindowTitle(_('Error')) diff --git a/spyder/plugins/application/plugin.py b/spyder/plugins/application/plugin.py index 1a9877a0dbd..662db07f7d7 100644 --- a/spyder/plugins/application/plugin.py +++ b/spyder/plugins/application/plugin.py @@ -14,7 +14,7 @@ import sys # Third party imports -from qtpy.QtCore import Qt, QThread, QTimer, Slot +from qtpy.QtCore import Slot from qtpy.QtWidgets import QMenu # Local imports @@ -43,12 +43,6 @@ class Application(SpyderPluginV2): CONF_FILE = False CONF_WIDGET_CLASS = ApplicationConfigPage - def __init__(self, parent, configuration=None): - super().__init__(parent, configuration) - - # Compute dependencies in a thread to not block the interface. - self.dependencies_thread = QThread() - def get_name(self): return _('Application') @@ -92,23 +86,19 @@ def on_close(self): def on_mainwindow_visible(self): """Actions after the mainwindow in visible.""" + container = self.get_container() + # Show dialog with missing dependencies if not running_under_pytest(): - container = self.get_container() - self.dependencies_thread.run = container.compute_dependencies - self.dependencies_thread.finished.connect( - container.report_missing_dependencies) - - # This avoids computing missing deps before the window is fully up - dependencies_timer = QTimer(self) - dependencies_timer.setInterval(10000) - dependencies_timer.setSingleShot(True) - dependencies_timer.timeout.connect(self.dependencies_thread.start) - dependencies_timer.start() - - # --- Private methods - # ------------------------------------------------------------------------ + container.compute_dependencies() + + # Check for updates + if DEV is None and self.get_conf('check_updates_on_startup'): + container.give_updates_feedback = False + container.check_updates(startup=True) + # ---- Private methods + # ------------------------------------------------------------------------ def _populate_file_menu(self): mainmenu = self.get_plugin(Plugins.MainMenu) if mainmenu: @@ -172,7 +162,7 @@ def _populate_help_menu_about_section(self, mainmenu): menu_id=ApplicationMenus.Help, section=HelpMenuSections.About) - # --- Public API + # ---- Public API # ------------------------------------------------------------------------ def get_application_context_menu(self, parent=None): """ diff --git a/spyder/plugins/ipythonconsole/widgets/shell.py b/spyder/plugins/ipythonconsole/widgets/shell.py index 55be657ab5b..d8125d10bc4 100644 --- a/spyder/plugins/ipythonconsole/widgets/shell.py +++ b/spyder/plugins/ipythonconsole/widgets/shell.py @@ -480,7 +480,7 @@ def reset_namespace(self, warning=False, message=False): box.set_check_visible(True) box.setText(warn_str) - answer = box.exec_() + answer = box.show() # Update checkbox based on user interaction self.set_conf( diff --git a/spyder/widgets/helperwidgets.py b/spyder/widgets/helperwidgets.py index f2706c765b1..2a04be3c9d9 100644 --- a/spyder/widgets/helperwidgets.py +++ b/spyder/widgets/helperwidgets.py @@ -67,7 +67,8 @@ class MessageCheckBox(QMessageBox): def __init__(self, *args, **kwargs): super(MessageCheckBox, self).__init__(*args, **kwargs) - self._checkbox = QCheckBox() + self.setWindowModality(Qt.NonModal) + self._checkbox = QCheckBox(self) # Set layout to include checkbox size = 9