From 8bc980d67d8df2320aa3204660ee1d9553b56bd0 Mon Sep 17 00:00:00 2001 From: DaffyTheDuck <34976093+DaffyTheDuck@users.noreply.github.com> Date: Sun, 5 Mar 2023 13:23:22 +0530 Subject: [PATCH] [Enhancement] Added setting to run vorta in background - Added setting to run vorta in background - Added option in the mics tab to enable/disable the background question popup --- src/vorta/application.py | 2 +- src/vorta/store/settings.py | 4 ++- src/vorta/views/main_window.py | 45 +++++++++++++++++----------------- src/vorta/views/misc_tab.py | 41 ++++++++++++++++++++++++++++++- tests/conftest.py | 8 ++++++ 5 files changed, 74 insertions(+), 26 deletions(-) diff --git a/src/vorta/application.py b/src/vorta/application.py index 6d8210e051..8ac0800fc9 100644 --- a/src/vorta/application.py +++ b/src/vorta/application.py @@ -128,7 +128,7 @@ def open_main_window_action(self): def toggle_main_window_visibility(self): if self.main_window.isVisible(): - self.main_window.close() + self.main_window.hide() else: self.open_main_window_action() diff --git a/src/vorta/store/settings.py b/src/vorta/store/settings.py index 3bcac86530..d53488308e 100644 --- a/src/vorta/store/settings.py +++ b/src/vorta/store/settings.py @@ -17,6 +17,7 @@ def get_misc_settings() -> List[Dict[str, str]]: startup = trans_late('settings', 'Startup') information = trans_late('settings', 'Information') security = trans_late('settings', 'Security') + background = trans_late('settings', 'Background') # Default settings for all platforms. settings = [ @@ -122,9 +123,10 @@ def get_misc_settings() -> List[Dict[str, str]]: 'key': 'enable_background_question', 'value': True, 'type': 'checkbox', + 'group': background, 'label': trans_late( 'settings', - "If the system tray isn't available, " "ask whether to continue in the background " "on exit", + "When closing the window, ask whether to continue in the background", ), }, { diff --git a/src/vorta/views/main_window.py b/src/vorta/views/main_window.py index 95439842be..ccdf05583f 100644 --- a/src/vorta/views/main_window.py +++ b/src/vorta/views/main_window.py @@ -6,7 +6,7 @@ from PyQt5.QtWidgets import QApplication, QCheckBox, QFileDialog, QMenu, QMessageBox, QShortcut, QToolTip from vorta.profile_export import ImportFailedException, ProfileExport from vorta.store.models import BackupProfileModel, SettingsModel -from vorta.utils import borg_compat, get_asset, get_network_status_monitor, is_system_tray_available +from vorta.utils import borg_compat, get_asset, get_network_status_monitor from vorta.views.partials.loading_button import LoadingButton from vorta.views.utils import get_colored_icon from .archive_tab import ArchiveTab @@ -277,27 +277,26 @@ def closeEvent(self, event): SettingsModel.key == 'previous_window_height' ).execute() - if not is_system_tray_available(): - if SettingsModel.get(key="enable_background_question").value: - msg = QMessageBox() - msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) - msg.setParent(self, QtCore.Qt.Sheet) - msg.setText(self.tr("Should Vorta continue to run in the background?")) - msg.button(QMessageBox.Yes).clicked.connect( - lambda: self.miscTab.save_setting("disable_background_state", True) - ) - msg.button(QMessageBox.No).clicked.connect( - lambda: ( - self.miscTab.save_setting("disable_background_state", False), - self.app.quit(), - ) + if SettingsModel.get(key="enable_background_question").value: + msg = QMessageBox() + msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) + msg.setParent(self, QtCore.Qt.Sheet) + msg.setText(self.tr("Should Vorta continue to run in the background?")) + msg.button(QMessageBox.Yes).clicked.connect( + lambda: self.miscTab.save_setting("disable_background_state", True) + ) + msg.button(QMessageBox.No).clicked.connect( + lambda: ( + self.miscTab.save_setting("disable_background_state", False), + self.app.quit(), ) - msg.setWindowTitle(self.tr("Quit")) - dont_show_box = QCheckBox(self.tr("Don't show this again")) - dont_show_box.clicked.connect(lambda x: self.miscTab.save_setting("enable_background_question", not x)) - dont_show_box.setTristate(False) - msg.setCheckBox(dont_show_box) - msg.exec() - elif not SettingsModel.get(key="disable_background_state").value: - self.app.quit() + ) + msg.setWindowTitle(self.tr("Quit")) + dont_show_box = QCheckBox(self.tr("Don't show this again")) + dont_show_box.clicked.connect(lambda x: self.miscTab.save_setting("enable_background_question", not x)) + dont_show_box.setTristate(False) + msg.setCheckBox(dont_show_box) + msg.exec() + elif not SettingsModel.get(key="disable_background_state").value: + self.app.quit() event.accept() diff --git a/src/vorta/views/misc_tab.py b/src/vorta/views/misc_tab.py index a94b4d2862..53276aa0e4 100644 --- a/src/vorta/views/misc_tab.py +++ b/src/vorta/views/misc_tab.py @@ -1,4 +1,6 @@ import logging +from typing import Dict +from playhouse import signals from PyQt5 import uic from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QApplication, QCheckBox, QFormLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem @@ -22,6 +24,8 @@ def __init__(self, parent=None): """Init.""" super().__init__(parent) self.setupUi(parent) + self.settings_checkboxes: Dict[str, QCheckBox] = {} + self.versionLabel.setText(__version__) self.logLink.setText( f'Log' @@ -34,6 +38,7 @@ def __init__(self, parent=None): self.checkboxLayout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.FieldsStayAtSizeHint) self.checkboxLayout.setFormAlignment(Qt.AlignmentFlag.AlignHCenter) self.tooltip_buttons = [] + signals.post_save.connect(self.on_setting_update, sender=SettingsModel) self.populate() @@ -86,8 +91,8 @@ def populate(self): # create widget cb = QCheckBox(translate('settings', setting.label)) + cb.setChecked(setting.value) cb.setToolTip(setting.tooltip) - cb.setCheckState(setting.value) cb.setTristate(False) cb.stateChanged.connect(lambda v, key=setting.key: self.save_setting(key, v)) @@ -101,6 +106,7 @@ def populate(self): cbl.addItem(QSpacerItem(0, 0, hPolicy=QSizePolicy.Policy.Expanding)) # add widget + self.settings_checkboxes[setting.key] = cb self.checkboxLayout.setLayout(i, QFormLayout.ItemRole.FieldRole, cbl) self.tooltip_buttons.append(tb) @@ -109,6 +115,39 @@ def populate(self): self.set_icons() + def on_setting_update(self, sender, instance: SettingsModel, created=False): + """ + Handle a update of the settings db. + Non-PyQt slot for peewee's `playhouse.signals` api. + It calls `update_checkbox`. + + Parameters + ---------- + sender : Type[SettingsModel] + table sending model + instance : SettingsModel + The model instance (row) saved. + created : bool, optional + Whether it was newly created, by default False + """ + if not created and instance.type == 'checkbox': + self.update_checkbox(instance.key, instance.value) + + def update_checkbox(self, key, value): + """ + Update the checkbox for a setting with a given key. + + Parameters + ---------- + key : str + The key of the setting to update. + value : bool + The value to set the checkbox to. + """ + checkbox = self.settings_checkboxes.get(key) + if checkbox: + checkbox.setChecked(value) + def set_icons(self): """Set or update the icons in this view.""" for button in self.tooltip_buttons: diff --git a/tests/conftest.py b/tests/conftest.py index 9350489c24..0b415ef928 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,9 +4,11 @@ from unittest.mock import MagicMock import pytest from peewee import SqliteDatabase +from playhouse import signals import vorta import vorta.application import vorta.borg.jobs_manager +from vorta.store.connection import setup_autostart from vorta.store.models import ( ArchiveModel, BackupProfileModel, @@ -90,6 +92,12 @@ def init_db(qapp, qtbot, tmpdir_factory): source_dir = SourceFileModel(dir='/tmp/another', repo=new_repo, dir_size=100, dir_files_count=18, path_isdir=True) source_dir.save() + # disconnect all signals because of bug coleifer/peewee#2687 (https://github.com/coleifer/peewee/issues/2687) + signals.post_save.disconnect(receiver=qapp.main_window.miscTab.on_setting_update, sender=SettingsModel) + # reconnect autostart signal + signals.post_save.disconnect(setup_autostart, sender=SettingsModel) + signals.post_save.connect(setup_autostart, sender=SettingsModel) + qapp.main_window.deleteLater() del qapp.main_window qapp.main_window = MainWindow(qapp) # Re-open main window to apply mock data in UI