mirror of https://github.com/borgbase/vorta
PyQt6 Upgrade (#1685)
This puts Vorta on PyQt6 and starts a new main branch 0.9. --------- Co-authored-by: real-yfprojects <real-yfprojects@users.noreply.github.com> Co-authored-by: Manu <3916435+m3nu@users.noreply.github.com> Co-authored-by: yfprojects <62463991+real-yfprojects@users.noreply.github.com>
This commit is contained in:
parent
8571ef6cb8
commit
7535f92ac8
|
@ -65,7 +65,8 @@ jobs:
|
||||||
sudo apt update && sudo apt install -y \
|
sudo apt update && sudo apt install -y \
|
||||||
xvfb libssl-dev openssl libacl1-dev libacl1 build-essential borgbackup \
|
xvfb libssl-dev openssl libacl1-dev libacl1 build-essential borgbackup \
|
||||||
libxkbcommon-x11-0 dbus-x11 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
|
libxkbcommon-x11-0 dbus-x11 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 \
|
||||||
libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0
|
libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0 \
|
||||||
|
libegl1 libxcb-cursor0
|
||||||
- name: Install system dependencies (macOS)
|
- name: Install system dependencies (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -20,11 +20,11 @@ def create_symlink(folder: Path) -> None:
|
||||||
"""
|
"""
|
||||||
sibbling = Path(str(folder).replace("MacOS", ""))
|
sibbling = Path(str(folder).replace("MacOS", ""))
|
||||||
|
|
||||||
# PyQt5/Qt/qml/QtQml/Models.2
|
# PyQt6/Qt/qml/QtQml/Models.2
|
||||||
root = str(sibbling).partition("Contents")[2].lstrip("/")
|
root = str(sibbling).partition("Contents")[2].lstrip("/")
|
||||||
# ../../../../
|
# ../../../../
|
||||||
backward = "../" * (root.count("/") + 1)
|
backward = "../" * (root.count("/") + 1)
|
||||||
# ../../../../Resources/PyQt5/Qt/qml/QtQml/Models.2
|
# ../../../../Resources/PyQt6/Qt/qml/QtQml/Models.2
|
||||||
good_path = f"{backward}Resources/{root}"
|
good_path = f"{backward}Resources/{root}"
|
||||||
|
|
||||||
folder.symlink_to(good_path)
|
folder.symlink_to(good_path)
|
||||||
|
@ -51,7 +51,7 @@ def fix_dll(dll: Path) -> None:
|
||||||
return None
|
return None
|
||||||
return f"@loader_path{good_path}/{basename}"
|
return f"@loader_path{good_path}/{basename}"
|
||||||
|
|
||||||
# Resources/PyQt5/Qt/qml/QtQuick/Controls.2/Fusion
|
# Resources/PyQt6/Qt/qml/QtQuick/Controls.2/Fusion
|
||||||
root = str(dll.parent).partition("Contents")[2][1:]
|
root = str(dll.parent).partition("Contents")[2][1:]
|
||||||
# /../../../../../../..
|
# /../../../../../../..
|
||||||
backward = "/.." * (root.count("/") + 1)
|
backward = "/.." * (root.count("/") + 1)
|
||||||
|
|
10
setup.cfg
10
setup.cfg
|
@ -39,14 +39,14 @@ python_requires = >=3.7
|
||||||
install_requires =
|
install_requires =
|
||||||
platformdirs >=3.0.0, <4.0.0; sys_platform == 'darwin' # for macOS: breaking changes in 3.0.0,
|
platformdirs >=3.0.0, <4.0.0; sys_platform == 'darwin' # for macOS: breaking changes in 3.0.0,
|
||||||
platformdirs >=2.6.0, <4.0.0; sys_platform != 'darwin' # for others: 2.6+ works consistently.
|
platformdirs >=2.6.0, <4.0.0; sys_platform != 'darwin' # for others: 2.6+ works consistently.
|
||||||
pyqt5
|
pyqt6
|
||||||
peewee
|
peewee
|
||||||
psutil
|
psutil
|
||||||
setuptools
|
setuptools
|
||||||
secretstorage; sys_platform != 'darwin'
|
secretstorage; sys_platform != 'darwin'
|
||||||
pyobjc-core; sys_platform == 'darwin'
|
pyobjc-core < 9.1; sys_platform == 'darwin'
|
||||||
pyobjc-framework-Cocoa; sys_platform == 'darwin'
|
pyobjc-framework-Cocoa < 9.1; sys_platform == 'darwin'
|
||||||
pyobjc-framework-LaunchServices; sys_platform == 'darwin'
|
pyobjc-framework-LaunchServices < 9.1; sys_platform == 'darwin'
|
||||||
tests_require =
|
tests_require =
|
||||||
pytest
|
pytest
|
||||||
pytest-qt
|
pytest-qt
|
||||||
|
@ -100,7 +100,7 @@ commands=flake8 src tests
|
||||||
max_line_length = 120
|
max_line_length = 120
|
||||||
|
|
||||||
[pylint.master]
|
[pylint.master]
|
||||||
extension-pkg-whitelist=PyQt5
|
extension-pkg-whitelist=PyQt6
|
||||||
load-plugins=
|
load-plugins=
|
||||||
|
|
||||||
[pylint.messages control]
|
[pylint.messages control]
|
||||||
|
|
|
@ -14,7 +14,7 @@ from vorta.utils import parse_args
|
||||||
def main():
|
def main():
|
||||||
def exception_handler(type, value, tb):
|
def exception_handler(type, value, tb):
|
||||||
from traceback import format_exception
|
from traceback import format_exception
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt6.QtWidgets import QMessageBox
|
||||||
|
|
||||||
logger.critical(
|
logger.critical(
|
||||||
"Uncaught exception, file a report at https://github.com/borgbase/vorta/issues/new/choose",
|
"Uncaught exception, file a report at https://github.com/borgbase/vorta/issues/new/choose",
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = '0.8.11'
|
__version__ = '0.9.0'
|
||||||
|
|
|
@ -3,8 +3,8 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any, Dict, List, Tuple
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt6.QtWidgets import QMessageBox
|
||||||
from vorta.borg.break_lock import BorgBreakJob
|
from vorta.borg.break_lock import BorgBreakJob
|
||||||
from vorta.borg.create import BorgCreateJob
|
from vorta.borg.create import BorgCreateJob
|
||||||
from vorta.borg.jobs_manager import JobsManager
|
from vorta.borg.jobs_manager import JobsManager
|
||||||
|
@ -179,10 +179,10 @@ class VortaApp(QtSingleApplication):
|
||||||
|
|
||||||
def _alert_missing_borg(self):
|
def _alert_missing_borg(self):
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setIcon(QMessageBox.Critical)
|
msg.setIcon(QMessageBox.Icon.Critical)
|
||||||
msg.setText(self.tr("No Borg Binary Found"))
|
msg.setText(self.tr("No Borg Binary Found"))
|
||||||
msg.setInformativeText(self.tr("Vorta was unable to locate a usable Borg Backup binary."))
|
msg.setInformativeText(self.tr("Vorta was unable to locate a usable Borg Backup binary."))
|
||||||
msg.setStandardButtons(QMessageBox.Ok)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
def check_darwin_permissions(self):
|
def check_darwin_permissions(self):
|
||||||
|
@ -201,8 +201,8 @@ class VortaApp(QtSingleApplication):
|
||||||
test_path = Path('~/Library/Cookies').expanduser()
|
test_path = Path('~/Library/Cookies').expanduser()
|
||||||
if test_path.exists() and not os.access(test_path, os.R_OK):
|
if test_path.exists() and not os.access(test_path, os.R_OK):
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setIcon(QMessageBox.Warning)
|
msg.setIcon(QMessageBox.Icon.Warning)
|
||||||
msg.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse)
|
msg.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse)
|
||||||
msg.setText(self.tr("Vorta needs Full Disk Access for complete Backups"))
|
msg.setText(self.tr("Vorta needs Full Disk Access for complete Backups"))
|
||||||
msg.setInformativeText(
|
msg.setInformativeText(
|
||||||
self.tr(
|
self.tr(
|
||||||
|
@ -212,7 +212,7 @@ class VortaApp(QtSingleApplication):
|
||||||
"System Preferences > Security & Privacy</a>."
|
"System Preferences > Security & Privacy</a>."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
msg.setStandardButtons(QMessageBox.Ok)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
def react_to_log(self, mgs, context):
|
def react_to_log(self, mgs, context):
|
||||||
|
@ -225,9 +225,9 @@ class VortaApp(QtSingleApplication):
|
||||||
repo_url = context.get('repo_url')
|
repo_url = context.get('repo_url')
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setWindowTitle(self.tr("Repository In Use"))
|
msg.setWindowTitle(self.tr("Repository In Use"))
|
||||||
msg.setIcon(QMessageBox.Critical)
|
msg.setIcon(QMessageBox.Icon.Critical)
|
||||||
abortButton = msg.addButton(self.tr("Abort"), QMessageBox.RejectRole)
|
abortButton = msg.addButton(self.tr("Abort"), QMessageBox.ButtonRole.RejectRole)
|
||||||
msg.addButton(self.tr("Continue"), QMessageBox.AcceptRole)
|
msg.addButton(self.tr("Continue"), QMessageBox.ButtonRole.AcceptRole)
|
||||||
msg.setDefaultButton(abortButton)
|
msg.setDefaultButton(abortButton)
|
||||||
msg.setText(self.tr(f"The repository at {repo_url} might be in use elsewhere."))
|
msg.setText(self.tr(f"The repository at {repo_url} might be in use elsewhere."))
|
||||||
msg.setInformativeText(
|
msg.setInformativeText(
|
||||||
|
@ -324,7 +324,7 @@ class VortaApp(QtSingleApplication):
|
||||||
# Create QMessageBox
|
# Create QMessageBox
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setIcon(QMessageBox.Icon.Critical) # changed for warning
|
msg.setIcon(QMessageBox.Icon.Critical) # changed for warning
|
||||||
msg.setStandardButtons(QMessageBox.Ok)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||||
msg.setWindowTitle(self.tr('Repo Check Failed'))
|
msg.setWindowTitle(self.tr('Repo Check Failed'))
|
||||||
|
|
||||||
if returncode == 1:
|
if returncode == 1:
|
||||||
|
|
|
@ -11,8 +11,8 @@ from collections import namedtuple
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
from subprocess import PIPE, Popen, TimeoutExpired
|
from subprocess import PIPE, Popen, TimeoutExpired
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
from vorta import application
|
from vorta import application
|
||||||
from vorta.borg.jobs_manager import JobInterface
|
from vorta.borg.jobs_manager import JobInterface
|
||||||
from vorta.i18n import trans_late, translate
|
from vorta.i18n import trans_late, translate
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import tempfile
|
import tempfile
|
||||||
from PyQt5.QtCore import QModelIndex, Qt
|
from PyQt6.QtCore import QModelIndex, Qt
|
||||||
from vorta.utils import borg_compat
|
from vorta.utils import borg_compat
|
||||||
from vorta.views.extract_dialog import ExtractTree, FileData
|
from vorta.views.extract_dialog import ExtractTree, FileData
|
||||||
from vorta.views.partials.treemodel import FileSystemItem, path_to_str
|
from vorta.views.partials.treemodel import FileSystemItem, path_to_str
|
||||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
||||||
import queue
|
import queue
|
||||||
import threading
|
import threading
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from PyQt5.QtCore import QObject
|
from PyQt6.QtCore import QObject
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ internationalisation (i18n) support code
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from PyQt5.QtCore import QLocale, QTranslator
|
from PyQt6.QtCore import QLocale, QTranslator
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from PyQt5 import QtDBus
|
from PyQt6 import QtDBus
|
||||||
from PyQt5.QtCore import QVariant
|
from PyQt6.QtCore import QMetaType, QVariant
|
||||||
from vorta.keyring.abc import VortaKeyring
|
from vorta.keyring.abc import VortaKeyring
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -47,9 +47,9 @@ class VortaKWallet5Keyring(VortaKeyring):
|
||||||
|
|
||||||
def get_result(self, method, args=[]):
|
def get_result(self, method, args=[]):
|
||||||
if args:
|
if args:
|
||||||
result = self.iface.callWithArgumentList(QtDBus.QDBus.AutoDetect, method, args)
|
result = self.iface.callWithArgumentList(QtDBus.QDBus.CallMode.AutoDetect, method, args)
|
||||||
else:
|
else:
|
||||||
result = self.iface.call(QtDBus.QDBus.AutoDetect, method)
|
result = self.iface.call(QtDBus.QDBus.CallMode.AutoDetect, method)
|
||||||
return result.arguments()[0]
|
return result.arguments()[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -60,7 +60,7 @@ class VortaKWallet5Keyring(VortaKeyring):
|
||||||
def try_unlock(self):
|
def try_unlock(self):
|
||||||
wallet_name = self.get_result("networkWallet")
|
wallet_name = self.get_result("networkWallet")
|
||||||
wId = QVariant(0)
|
wId = QVariant(0)
|
||||||
wId.convert(4)
|
wId.convert(QMetaType(QMetaType.Type.LongLong.value))
|
||||||
output = self.get_result("open", args=[wallet_name, wId, 'vorta-repo'])
|
output = self.get_result("open", args=[wallet_name, wId, 'vorta-repo'])
|
||||||
try:
|
try:
|
||||||
self.handle = int(output)
|
self.handle = int(output)
|
||||||
|
|
|
@ -16,7 +16,7 @@ logger = logging.getLogger()
|
||||||
def init_logger(background=False):
|
def init_logger(background=False):
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
logging.getLogger('peewee').setLevel(logging.INFO)
|
logging.getLogger('peewee').setLevel(logging.INFO)
|
||||||
logging.getLogger('PyQt5').setLevel(logging.INFO)
|
logging.getLogger('PyQt6').setLevel(logging.INFO)
|
||||||
|
|
||||||
# create logging format
|
# create logging format
|
||||||
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
|
|
@ -2,8 +2,8 @@ import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, List, Mapping, NamedTuple, Optional
|
from typing import Any, List, Mapping, NamedTuple, Optional
|
||||||
from PyQt5 import QtDBus
|
from PyQt6 import QtDBus
|
||||||
from PyQt5.QtCore import QObject, QVersionNumber
|
from PyQt6.QtCore import QObject, QVersionNumber
|
||||||
from vorta.network_status.abc import NetworkStatusMonitor, SystemWifiInfo
|
from vorta.network_status.abc import NetworkStatusMonitor, SystemWifiInfo
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from PyQt5 import QtCore, QtDBus
|
from PyQt6 import QtCore, QtDBus
|
||||||
from vorta.store.models import SettingsModel
|
from vorta.store.models import SettingsModel
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -77,13 +77,12 @@ class DBusNotifications(VortaNotifications):
|
||||||
path = "/org/freedesktop/Notifications"
|
path = "/org/freedesktop/Notifications"
|
||||||
interface = "org.freedesktop.Notifications"
|
interface = "org.freedesktop.Notifications"
|
||||||
app_name = "vorta"
|
app_name = "vorta"
|
||||||
v = QtCore.QVariant(12321) # random int to identify all notifications
|
id_replace = QtCore.QVariant(12321)
|
||||||
if v.convert(QtCore.QVariant.UInt):
|
id_replace.convert(QtCore.QMetaType(QtCore.QMetaType.Type.UInt.value))
|
||||||
id_replace = v
|
|
||||||
icon = "com.borgbase.Vorta-symbolic"
|
icon = "com.borgbase.Vorta-symbolic"
|
||||||
title = header
|
title = header
|
||||||
text = msg
|
text = msg
|
||||||
actions_list = QtDBus.QDBusArgument([], QtCore.QMetaType.QStringList)
|
actions_list = QtDBus.QDBusArgument([], QtCore.QMetaType.Type.QStringList.value)
|
||||||
hint = {'urgency': self.URGENCY[level]}
|
hint = {'urgency': self.URGENCY[level]}
|
||||||
time = 5000 # milliseconds for display timeout
|
time = 5000 # milliseconds for display timeout
|
||||||
|
|
||||||
|
@ -91,7 +90,9 @@ class DBusNotifications(VortaNotifications):
|
||||||
notify = QtDBus.QDBusInterface(item, path, interface, bus)
|
notify = QtDBus.QDBusInterface(item, path, interface, bus)
|
||||||
if notify.isValid():
|
if notify.isValid():
|
||||||
x = notify.call(
|
x = notify.call(
|
||||||
QtDBus.QDBus.AutoDetect,
|
# Call arguments for Notify interface need to match exactly:
|
||||||
|
# https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html#command-notify
|
||||||
|
QtDBus.QDBus.CallMode.AutoDetect,
|
||||||
"Notify",
|
"Notify",
|
||||||
app_name,
|
app_name,
|
||||||
id_replace,
|
id_replace,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from PyQt5.QtCore import QTextStream, pyqtSignal
|
from PyQt6.QtCore import QTextStream, pyqtSignal
|
||||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
|
from PyQt6.QtNetwork import QLocalServer, QLocalSocket
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
|
||||||
class QtSingleApplication(QApplication):
|
class QtSingleApplication(QApplication):
|
||||||
|
@ -52,7 +52,6 @@ class QtSingleApplication(QApplication):
|
||||||
if self._isRunning:
|
if self._isRunning:
|
||||||
# Yes, there is.
|
# Yes, there is.
|
||||||
self._outStream = QTextStream(self._outSocket)
|
self._outStream = QTextStream(self._outSocket)
|
||||||
self._outStream.setCodec('UTF-8')
|
|
||||||
else:
|
else:
|
||||||
# No, there isn't.
|
# No, there isn't.
|
||||||
self._outSocket = None
|
self._outSocket = None
|
||||||
|
@ -84,7 +83,6 @@ class QtSingleApplication(QApplication):
|
||||||
if not self._inSocket:
|
if not self._inSocket:
|
||||||
return
|
return
|
||||||
self._inStream = QTextStream(self._inSocket)
|
self._inStream = QTextStream(self._inSocket)
|
||||||
self._inStream.setCodec('UTF-8')
|
|
||||||
self._inSocket.readyRead.connect(self._onReadyRead)
|
self._inSocket.readyRead.connect(self._onReadyRead)
|
||||||
|
|
||||||
def _onReadyRead(self):
|
def _onReadyRead(self):
|
||||||
|
|
|
@ -4,9 +4,9 @@ import threading
|
||||||
from datetime import datetime as dt
|
from datetime import datetime as dt
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Dict, NamedTuple, Optional, Tuple, Union
|
from typing import Dict, NamedTuple, Optional, Tuple, Union
|
||||||
from PyQt5 import QtCore, QtDBus
|
from PyQt6 import QtCore, QtDBus
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt6.QtCore import QTimer
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
from vorta import application
|
from vorta import application
|
||||||
from vorta.borg.check import BorgCheckJob
|
from vorta.borg.check import BorgCheckJob
|
||||||
from vorta.borg.create import BorgCreateJob
|
from vorta.borg.create import BorgCreateJob
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import os
|
import os
|
||||||
from PyQt5.QtGui import QIcon
|
from PyQt6.QtGui import QIcon
|
||||||
from PyQt5.QtWidgets import QApplication, QMenu, QSystemTrayIcon
|
from PyQt6.QtWidgets import QApplication, QMenu, QSystemTrayIcon
|
||||||
from vorta.store.models import BackupProfileModel
|
from vorta.store.models import BackupProfileModel
|
||||||
from vorta.utils import get_asset
|
from vorta.utils import get_asset
|
||||||
|
|
||||||
|
@ -31,8 +31,8 @@ class TrayMenu(QSystemTrayIcon):
|
||||||
If XDG_CURRENT_DESKTOP isn't set, always open the tray menu (macOS)
|
If XDG_CURRENT_DESKTOP isn't set, always open the tray menu (macOS)
|
||||||
"""
|
"""
|
||||||
if reason in [
|
if reason in [
|
||||||
QSystemTrayIcon.Trigger,
|
QSystemTrayIcon.ActivationReason.Trigger,
|
||||||
QSystemTrayIcon.DoubleClick,
|
QSystemTrayIcon.ActivationReason.DoubleClick,
|
||||||
] and os.environ.get('XDG_CURRENT_DESKTOP'):
|
] and os.environ.get('XDG_CURRENT_DESKTOP'):
|
||||||
self.app.toggle_main_window_visibility()
|
self.app.toggle_main_window_visibility()
|
||||||
|
|
||||||
|
|
|
@ -12,17 +12,14 @@ from datetime import datetime as dt
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from typing import Any, Callable, Iterable, List, Optional, Tuple, TypeVar
|
from typing import Any, Callable, Iterable, List, Optional, Tuple, TypeVar
|
||||||
import psutil
|
import psutil
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtCore import QFileInfo, QThread, pyqtSignal
|
from PyQt6.QtCore import QFileInfo, QThread, pyqtSignal
|
||||||
from PyQt5.QtWidgets import QApplication, QFileDialog, QSystemTrayIcon
|
from PyQt6.QtWidgets import QApplication, QFileDialog, QSystemTrayIcon
|
||||||
from vorta.borg._compatibility import BorgCompatibility
|
from vorta.borg._compatibility import BorgCompatibility
|
||||||
from vorta.i18n import trans_late
|
from vorta.i18n import trans_late
|
||||||
from vorta.log import logger
|
from vorta.log import logger
|
||||||
from vorta.network_status.abc import NetworkStatusMonitor
|
from vorta.network_status.abc import NetworkStatusMonitor
|
||||||
|
|
||||||
QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) # enable highdpi scaling
|
|
||||||
QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) # use highdpi icons
|
|
||||||
|
|
||||||
borg_compat = BorgCompatibility()
|
borg_compat = BorgCompatibility()
|
||||||
_network_status_monitor = None
|
_network_status_monitor = None
|
||||||
|
|
||||||
|
@ -168,10 +165,10 @@ def get_dict_from_list(dataDict, mapList):
|
||||||
|
|
||||||
def choose_file_dialog(parent, title, want_folder=True):
|
def choose_file_dialog(parent, title, want_folder=True):
|
||||||
dialog = QFileDialog(parent, title, os.path.expanduser('~'))
|
dialog = QFileDialog(parent, title, os.path.expanduser('~'))
|
||||||
dialog.setFileMode(QFileDialog.Directory if want_folder else QFileDialog.ExistingFiles)
|
dialog.setFileMode(QFileDialog.FileMode.Directory if want_folder else QFileDialog.FileMode.ExistingFiles)
|
||||||
dialog.setParent(parent, QtCore.Qt.Sheet)
|
dialog.setParent(parent, QtCore.Qt.WindowType.Sheet)
|
||||||
if want_folder:
|
if want_folder:
|
||||||
dialog.setOption(QFileDialog.ShowDirsOnly)
|
dialog.setOption(QFileDialog.Option.ShowDirsOnly)
|
||||||
return dialog
|
return dialog
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,17 @@ import logging
|
||||||
import sys
|
import sys
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, pyqtSlot
|
from PyQt6.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, pyqtSlot
|
||||||
from PyQt5.QtGui import QDesktopServices, QKeySequence
|
from PyQt6.QtGui import QAction, QDesktopServices, QKeySequence, QShortcut
|
||||||
from PyQt5.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QAction,
|
QAbstractItemView,
|
||||||
QApplication,
|
QApplication,
|
||||||
QHeaderView,
|
QHeaderView,
|
||||||
QInputDialog,
|
QInputDialog,
|
||||||
QLayout,
|
QLayout,
|
||||||
QMenu,
|
QMenu,
|
||||||
QMessageBox,
|
QMessageBox,
|
||||||
QShortcut,
|
|
||||||
QTableView,
|
QTableView,
|
||||||
QTableWidgetItem,
|
QTableWidgetItem,
|
||||||
QWidget,
|
QWidget,
|
||||||
|
@ -77,20 +76,20 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
||||||
|
|
||||||
header = self.archiveTable.horizontalHeader()
|
header = self.archiveTable.horizontalHeader()
|
||||||
header.setVisible(True)
|
header.setVisible(True)
|
||||||
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(3, QHeaderView.Interactive)
|
header.setSectionResizeMode(3, QHeaderView.ResizeMode.Interactive)
|
||||||
header.setSectionResizeMode(4, QHeaderView.Stretch)
|
header.setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
|
||||||
header.setStretchLastSection(True)
|
header.setStretchLastSection(True)
|
||||||
|
|
||||||
if sys.platform != 'darwin':
|
if sys.platform != 'darwin':
|
||||||
self._set_status('') # Set platform-specific hints.
|
self._set_status('') # Set platform-specific hints.
|
||||||
|
|
||||||
self.archiveTable.setSelectionBehavior(QTableView.SelectRows)
|
self.archiveTable.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.archiveTable.setEditTriggers(QTableView.NoEditTriggers)
|
self.archiveTable.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||||
self.archiveTable.setWordWrap(False)
|
self.archiveTable.setWordWrap(False)
|
||||||
self.archiveTable.setTextElideMode(QtCore.Qt.ElideLeft)
|
self.archiveTable.setTextElideMode(QtCore.Qt.TextElideMode.ElideLeft)
|
||||||
self.archiveTable.setAlternatingRowColors(True)
|
self.archiveTable.setAlternatingRowColors(True)
|
||||||
self.archiveTable.cellDoubleClicked.connect(self.cell_double_clicked)
|
self.archiveTable.cellDoubleClicked.connect(self.cell_double_clicked)
|
||||||
self.archiveTable.setSortingEnabled(True)
|
self.archiveTable.setSortingEnabled(True)
|
||||||
|
@ -757,7 +756,7 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
||||||
|
|
||||||
window = ExtractDialog(archive, model)
|
window = ExtractDialog(archive, model)
|
||||||
self._toggle_all_buttons(True)
|
self._toggle_all_buttons(True)
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
self._window = window # for testing
|
self._window = window # for testing
|
||||||
window.show()
|
window.show()
|
||||||
window.accepted.connect(process_result)
|
window.accepted.connect(process_result)
|
||||||
|
@ -778,19 +777,19 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
||||||
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
|
QDesktopServices.openUrl(QtCore.QUrl(f'file:///{mount_point}'))
|
||||||
|
|
||||||
def row_of_archive(self, archive_name):
|
def row_of_archive(self, archive_name):
|
||||||
items = self.archiveTable.findItems(archive_name, QtCore.Qt.MatchExactly)
|
items = self.archiveTable.findItems(archive_name, QtCore.Qt.MatchFlag.MatchExactly)
|
||||||
rows = [item.row() for item in items if item.column() == 4]
|
rows = [item.row() for item in items if item.column() == 4]
|
||||||
return rows[0] if rows else None
|
return rows[0] if rows else None
|
||||||
|
|
||||||
def confirm_dialog(self, title, text):
|
def confirm_dialog(self, title, text):
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setIcon(QMessageBox.Information)
|
msg.setIcon(QMessageBox.Icon.Information)
|
||||||
msg.setText(text)
|
msg.setText(text)
|
||||||
msg.setWindowTitle(title)
|
msg.setWindowTitle(title)
|
||||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.Cancel)
|
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel)
|
||||||
msg.button(msg.Yes).setText(self.tr("Yes"))
|
msg.button(QMessageBox.StandardButton.Yes).setText(self.tr("Yes"))
|
||||||
msg.button(msg.Cancel).setText(self.tr("Cancel"))
|
msg.button(QMessageBox.StandardButton.Cancel).setText(self.tr("Cancel"))
|
||||||
return msg.exec_() == QMessageBox.Yes
|
return msg.exec() == QMessageBox.StandardButton.Yes
|
||||||
|
|
||||||
def delete_action(self):
|
def delete_action(self):
|
||||||
# Since this function modify the UI, we can't put the whole function in a JobQUeue.
|
# Since this function modify the UI, we can't put the whole function in a JobQUeue.
|
||||||
|
@ -835,7 +834,7 @@ class ArchiveTab(ArchiveTabBase, ArchiveTabUI, BackupProfileMixin):
|
||||||
|
|
||||||
# remove rows from list and database
|
# remove rows from list and database
|
||||||
for archive in archives:
|
for archive in archives:
|
||||||
for entry in self.archiveTable.findItems(archive, QtCore.Qt.MatchExactly):
|
for entry in self.archiveTable.findItems(archive, QtCore.Qt.MatchFlag.MatchExactly):
|
||||||
self.archiveTable.removeRow(entry.row())
|
self.archiveTable.removeRow(entry.row())
|
||||||
ArchiveModel.get(name=archive).delete_instance()
|
ArchiveModel.get(name=archive).delete_instance()
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,10 @@ import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
from PyQt5 import uic
|
from PyQt6 import uic
|
||||||
from PyQt5.QtCore import QDateTime, QLocale, QMimeData, QModelIndex, QPoint, Qt, QThread, QUrl
|
from PyQt6.QtCore import QDateTime, QLocale, QMimeData, QModelIndex, QPoint, Qt, QThread, QUrl
|
||||||
from PyQt5.QtGui import QColor, QKeySequence
|
from PyQt6.QtGui import QColor, QKeySequence, QShortcut
|
||||||
from PyQt5.QtWidgets import QApplication, QHeaderView, QMenu, QShortcut, QTreeView
|
from PyQt6.QtWidgets import QApplication, QHeaderView, QMenu, QTreeView
|
||||||
from vorta.store.models import SettingsModel
|
from vorta.store.models import SettingsModel
|
||||||
from vorta.utils import get_asset, pretty_bytes, uses_dark_mode
|
from vorta.utils import get_asset, pretty_bytes, uses_dark_mode
|
||||||
from vorta.views.partials.treemodel import (
|
from vorta.views.partials.treemodel import (
|
||||||
|
@ -89,9 +89,9 @@ class DiffResultDialog(DiffResultBase, DiffResultUI):
|
||||||
# header
|
# header
|
||||||
header = self.treeView.header()
|
header = self.treeView.header()
|
||||||
header.setStretchLastSection(False) # stretch only first section
|
header.setStretchLastSection(False) # stretch only first section
|
||||||
header.setSectionResizeMode(0, QHeaderView.Stretch)
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
|
|
||||||
# signals
|
# signals
|
||||||
|
|
||||||
|
@ -824,11 +824,11 @@ class DiffTree(FileTreeModel[DiffData]):
|
||||||
if role == Qt.ItemDataRole.ForegroundRole:
|
if role == Qt.ItemDataRole.ForegroundRole:
|
||||||
# colour
|
# colour
|
||||||
if item.data.change_type == ChangeType.ADDED:
|
if item.data.change_type == ChangeType.ADDED:
|
||||||
return QColor(Qt.green) if uses_dark_mode() else QColor(Qt.darkGreen)
|
return QColor(Qt.GlobalColor.green) if uses_dark_mode() else QColor(Qt.GlobalColor.darkGreen)
|
||||||
if item.data.change_type == ChangeType.MODIFIED:
|
if item.data.change_type == ChangeType.MODIFIED:
|
||||||
return QColor(Qt.yellow) if uses_dark_mode() else QColor(Qt.darkYellow)
|
return QColor(Qt.GlobalColor.yellow) if uses_dark_mode() else QColor(Qt.GlobalColor.darkYellow)
|
||||||
if item.data.change_type == ChangeType.REMOVED:
|
if item.data.change_type == ChangeType.REMOVED:
|
||||||
return QColor(Qt.red) if uses_dark_mode() else QColor(Qt.darkRed)
|
return QColor(Qt.GlobalColor.red) if uses_dark_mode() else QColor(Qt.GlobalColor.darkRed)
|
||||||
return None # no change
|
return None # no change
|
||||||
|
|
||||||
if role == Qt.ItemDataRole.ToolTipRole:
|
if role == Qt.ItemDataRole.ToolTipRole:
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PyQt5 import uic
|
from PyQt6 import uic
|
||||||
from PyQt5.QtWidgets import QFileDialog, QMessageBox
|
from PyQt6.QtCore import Qt
|
||||||
|
from PyQt6.QtWidgets import QFileDialog, QMessageBox
|
||||||
from vorta.keyring.abc import VortaKeyring
|
from vorta.keyring.abc import VortaKeyring
|
||||||
from vorta.store.models import BackupProfileModel # noqa: F401
|
from vorta.store.models import BackupProfileModel # noqa: F401
|
||||||
from vorta.utils import get_asset
|
from vorta.utils import get_asset
|
||||||
|
@ -31,7 +32,7 @@ class ExportWindow(ExportWindowBase, ExportWindowUI):
|
||||||
self.keyring = VortaKeyring.get_keyring()
|
self.keyring = VortaKeyring.get_keyring()
|
||||||
profile = self.profile
|
profile = self.profile
|
||||||
if profile.repo is None or self.keyring.get_password('vorta-repo', profile.repo.url) is None:
|
if profile.repo is None or self.keyring.get_password('vorta-repo', profile.repo.url) is None:
|
||||||
self.storePassword.setCheckState(False)
|
self.storePassword.setCheckState(Qt.CheckState(False))
|
||||||
self.storePassword.setDisabled(True)
|
self.storePassword.setDisabled(True)
|
||||||
self.storePassword.setToolTip(self.tr('Disclose your borg passphrase (No passphrase set)'))
|
self.storePassword.setToolTip(self.tr('Disclose your borg passphrase (No passphrase set)'))
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Optional
|
from typing import Optional, Union
|
||||||
from PyQt5 import uic
|
from PyQt6 import uic
|
||||||
from PyQt5.QtCore import QDateTime, QLocale, QMimeData, QModelIndex, QPoint, Qt, QThread, QUrl
|
from PyQt6.QtCore import QDateTime, QLocale, QMimeData, QModelIndex, QPoint, Qt, QThread, QUrl
|
||||||
from PyQt5.QtGui import QColor, QKeySequence
|
from PyQt6.QtGui import QColor, QKeySequence, QShortcut
|
||||||
from PyQt5.QtWidgets import QApplication, QDialogButtonBox, QHeaderView, QMenu, QPushButton, QShortcut
|
from PyQt6.QtWidgets import QApplication, QDialogButtonBox, QHeaderView, QMenu, QPushButton
|
||||||
from vorta.store.models import SettingsModel
|
from vorta.store.models import SettingsModel
|
||||||
from vorta.utils import borg_compat, get_asset, pretty_bytes, uses_dark_mode
|
from vorta.utils import borg_compat, get_asset, pretty_bytes, uses_dark_mode
|
||||||
from vorta.views.utils import get_colored_icon
|
from vorta.views.utils import get_colored_icon
|
||||||
|
@ -72,10 +72,10 @@ class ExtractDialog(ExtractDialogBase, ExtractDialogUI):
|
||||||
# header
|
# header
|
||||||
header = view.header()
|
header = view.header()
|
||||||
header.setStretchLastSection(False)
|
header.setStretchLastSection(False)
|
||||||
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(1, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(2, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(0, QHeaderView.Stretch)
|
header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
|
||||||
|
|
||||||
# shortcuts
|
# shortcuts
|
||||||
shortcut_copy = QShortcut(QKeySequence.StandardKey.Copy, self.treeView)
|
shortcut_copy = QShortcut(QKeySequence.StandardKey.Copy, self.treeView)
|
||||||
|
@ -281,7 +281,7 @@ class FileData:
|
||||||
last_modified: QDateTime
|
last_modified: QDateTime
|
||||||
source_path: Optional[str] = None # only relevant for links
|
source_path: Optional[str] = None # only relevant for links
|
||||||
|
|
||||||
checkstate: int = 0 # whether to extract the file (0, 1 or 2)
|
checkstate: Qt.CheckState = Qt.CheckState.Unchecked # whether to extract the file (0, 1 or 2)
|
||||||
checked_children: int = 0 # number of children checked
|
checked_children: int = 0 # number of children checked
|
||||||
|
|
||||||
|
|
||||||
|
@ -378,7 +378,7 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
self,
|
self,
|
||||||
section: int,
|
section: int,
|
||||||
orientation: Qt.Orientation,
|
orientation: Qt.Orientation,
|
||||||
role: int = Qt.ItemDataRole.DisplayRole,
|
role: Union[int, Qt.ItemDataRole] = Qt.ItemDataRole.DisplayRole,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Get the data for the given role and section in the given header.
|
Get the data for the given role and section in the given header.
|
||||||
|
@ -414,7 +414,7 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):
|
def data(self, index: QModelIndex, role: Union[int, Qt.ItemDataRole] = Qt.ItemDataRole.DisplayRole):
|
||||||
"""
|
"""
|
||||||
Get the data for the given role and index.
|
Get the data for the given role and index.
|
||||||
|
|
||||||
|
@ -467,9 +467,9 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
if role == Qt.ItemDataRole.BackgroundRole and column == 3:
|
if role == Qt.ItemDataRole.BackgroundRole and column == 3:
|
||||||
# health indicator
|
# health indicator
|
||||||
if item.data.health:
|
if item.data.health:
|
||||||
return QColor(Qt.green) if uses_dark_mode() else QColor(Qt.darkGreen)
|
return QColor(Qt.GlobalColor.green) if uses_dark_mode() else QColor(Qt.GlobalColor.darkGreen)
|
||||||
else:
|
else:
|
||||||
return QColor(Qt.green) if uses_dark_mode() else QColor(Qt.darkGreen)
|
return QColor(Qt.GlobalColor.green) if uses_dark_mode() else QColor(Qt.GlobalColor.darkGreen)
|
||||||
|
|
||||||
if role == Qt.ItemDataRole.ToolTipRole:
|
if role == Qt.ItemDataRole.ToolTipRole:
|
||||||
if column == 0:
|
if column == 0:
|
||||||
|
@ -532,7 +532,12 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
if role == Qt.ItemDataRole.CheckStateRole and column == 0:
|
if role == Qt.ItemDataRole.CheckStateRole and column == 0:
|
||||||
return item.data.checkstate
|
return item.data.checkstate
|
||||||
|
|
||||||
def setData(self, index: QModelIndex, value, role: int = Qt.ItemDataRole.DisplayRole) -> bool:
|
def setData(
|
||||||
|
self,
|
||||||
|
index: QModelIndex,
|
||||||
|
value: Union[int, Qt.CheckState],
|
||||||
|
role: Union[int, Qt.ItemDataRole] = Qt.ItemDataRole.CheckStateRole,
|
||||||
|
) -> bool:
|
||||||
"""
|
"""
|
||||||
Sets the role data for the item at index to value.
|
Sets the role data for the item at index to value.
|
||||||
|
|
||||||
|
@ -543,6 +548,13 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
if role != Qt.ItemDataRole.CheckStateRole:
|
if role != Qt.ItemDataRole.CheckStateRole:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# convert int to enum member
|
||||||
|
# PyQt6 will pass Ints where there were IntEnums in PyQt5
|
||||||
|
if isinstance(value, int):
|
||||||
|
value = Qt.CheckState(value)
|
||||||
|
if isinstance(role, int):
|
||||||
|
role = Qt.ItemDataRole(role)
|
||||||
|
|
||||||
item: ExtractFileItem = index.internalPointer()
|
item: ExtractFileItem = index.internalPointer()
|
||||||
|
|
||||||
if value == item.data.checkstate:
|
if value == item.data.checkstate:
|
||||||
|
@ -616,7 +628,7 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
|
|
||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
for i in range(number_children):
|
for i in range(number_children):
|
||||||
child = index.child(i, 0)
|
child = self.index(i, 0, index)
|
||||||
child_item: ExtractFileItem = child.internalPointer()
|
child_item: ExtractFileItem = child.internalPointer()
|
||||||
child_item.data.checkstate = value
|
child_item.data.checkstate = value
|
||||||
|
|
||||||
|
@ -633,8 +645,8 @@ class ExtractTree(FileTreeModel[FileData]):
|
||||||
self.set_checkstate_recursively(child, value)
|
self.set_checkstate_recursively(child, value)
|
||||||
|
|
||||||
self.dataChanged.emit(
|
self.dataChanged.emit(
|
||||||
index.child(0, 0),
|
self.index(0, 0, index),
|
||||||
index.child(0, number_children - 1),
|
self.index(0, number_children - 1, index),
|
||||||
(Qt.ItemDataRole.CheckStateRole,),
|
(Qt.ItemDataRole.CheckStateRole,),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QMessageBox
|
from PyQt6.QtWidgets import QMessageBox
|
||||||
from vorta.keyring.abc import VortaKeyring
|
from vorta.keyring.abc import VortaKeyring
|
||||||
from vorta.profile_export import VersionException
|
from vorta.profile_export import VersionException
|
||||||
from vorta.store.connection import SCHEMA_VERSION
|
from vorta.store.connection import SCHEMA_VERSION
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtCore import QPoint
|
from PyQt6.QtCore import QPoint
|
||||||
from PyQt5.QtGui import QFontMetrics, QKeySequence
|
from PyQt6.QtGui import QFontMetrics, QKeySequence, QShortcut
|
||||||
from PyQt5.QtWidgets import QApplication, QCheckBox, QFileDialog, QMenu, QMessageBox, QShortcut, QToolTip
|
from PyQt6.QtWidgets import QApplication, QCheckBox, QFileDialog, QMenu, QMessageBox, QToolTip
|
||||||
from vorta.profile_export import ImportFailedException, ProfileExport
|
from vorta.profile_export import ImportFailedException, ProfileExport
|
||||||
from vorta.store.models import BackupProfileModel, SettingsModel
|
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, is_system_tray_available
|
||||||
|
@ -31,7 +31,7 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
self.setWindowTitle('Vorta for Borg Backup')
|
self.setWindowTitle('Vorta for Borg Backup')
|
||||||
self.app = parent
|
self.app = parent
|
||||||
self.setWindowIcon(get_colored_icon("icon"))
|
self.setWindowIcon(get_colored_icon("icon"))
|
||||||
self.setWindowFlags(QtCore.Qt.WindowCloseButtonHint | QtCore.Qt.WindowMinimizeButtonHint)
|
self.setWindowFlags(QtCore.Qt.WindowType.WindowCloseButtonHint | QtCore.Qt.WindowType.WindowMinimizeButtonHint)
|
||||||
self.createStartBtn = LoadingButton(self.tr("Start Backup"))
|
self.createStartBtn = LoadingButton(self.tr("Start Backup"))
|
||||||
self.gridLayout.addWidget(self.createStartBtn, 0, 0, 1, 1)
|
self.gridLayout.addWidget(self.createStartBtn, 0, 0, 1, 1)
|
||||||
self.createStartBtn.setGif(get_asset("icons/loading"))
|
self.createStartBtn.setGif(get_asset("icons/loading"))
|
||||||
|
@ -156,7 +156,7 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
def profile_rename_action(self):
|
def profile_rename_action(self):
|
||||||
window = EditProfileWindow(rename_existing_id=self.profileSelector.currentData())
|
window = EditProfileWindow(rename_existing_id=self.profileSelector.currentData())
|
||||||
self.window = window # For tests
|
self.window = window # For tests
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.open()
|
window.open()
|
||||||
window.profile_changed.connect(self.profile_add_edit_result)
|
window.profile_changed.connect(self.profile_add_edit_result)
|
||||||
window.rejected.connect(lambda: self.profileSelector.setCurrentIndex(self.profileSelector.currentIndex()))
|
window.rejected.connect(lambda: self.profileSelector.setCurrentIndex(self.profileSelector.currentIndex()))
|
||||||
|
@ -171,11 +171,11 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
self,
|
self,
|
||||||
self.tr("Confirm deletion"),
|
self.tr("Confirm deletion"),
|
||||||
msg,
|
msg,
|
||||||
QMessageBox.Yes | QMessageBox.No,
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
QMessageBox.No,
|
QMessageBox.StandardButton.No,
|
||||||
)
|
)
|
||||||
|
|
||||||
if reply == QMessageBox.Yes:
|
if reply == QMessageBox.StandardButton.Yes:
|
||||||
to_delete.delete_instance(recursive=True)
|
to_delete.delete_instance(recursive=True)
|
||||||
self.app.scheduler.remove_job(to_delete_id) # Remove pending jobs
|
self.app.scheduler.remove_job(to_delete_id) # Remove pending jobs
|
||||||
self.profileSelector.removeItem(self.profileSelector.currentIndex())
|
self.profileSelector.removeItem(self.profileSelector.currentIndex())
|
||||||
|
@ -189,7 +189,7 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
def profile_add_action(self):
|
def profile_add_action(self):
|
||||||
window = AddProfileWindow()
|
window = AddProfileWindow()
|
||||||
self.window = window # For tests
|
self.window = window # For tests
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.open()
|
window.open()
|
||||||
window.profile_changed.connect(self.profile_add_edit_result)
|
window.profile_changed.connect(self.profile_add_edit_result)
|
||||||
window.rejected.connect(lambda: self.profileSelector.setCurrentIndex(self.profileSelector.currentIndex()))
|
window.rejected.connect(lambda: self.profileSelector.setCurrentIndex(self.profileSelector.currentIndex()))
|
||||||
|
@ -201,7 +201,7 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
"""
|
"""
|
||||||
window = ExportWindow(profile=self.current_profile.refresh())
|
window = ExportWindow(profile=self.current_profile.refresh())
|
||||||
self.window = window
|
self.window = window
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
def profile_import_action(self):
|
def profile_import_action(self):
|
||||||
|
@ -236,7 +236,7 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
return
|
return
|
||||||
window = ImportWindow(profile_export=profile_export)
|
window = ImportWindow(profile_export=profile_export)
|
||||||
self.window = window
|
self.window = window
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.profile_imported.connect(profile_imported_event)
|
window.profile_imported.connect(profile_imported_event)
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
|
@ -280,13 +280,13 @@ class MainWindow(MainWindowBase, MainWindowUI):
|
||||||
if not is_system_tray_available():
|
if not is_system_tray_available():
|
||||||
if SettingsModel.get(key="enable_background_question").value:
|
if SettingsModel.get(key="enable_background_question").value:
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
|
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
||||||
msg.setParent(self, QtCore.Qt.Sheet)
|
msg.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
msg.setText(self.tr("Should Vorta continue to run in the background?"))
|
msg.setText(self.tr("Should Vorta continue to run in the background?"))
|
||||||
msg.button(QMessageBox.Yes).clicked.connect(
|
msg.button(QMessageBox.StandardButton.Yes).clicked.connect(
|
||||||
lambda: self.miscTab.save_setting("disable_background_state", True)
|
lambda: self.miscTab.save_setting("disable_background_state", True)
|
||||||
)
|
)
|
||||||
msg.button(QMessageBox.No).clicked.connect(
|
msg.button(QMessageBox.StandardButton.No).clicked.connect(
|
||||||
lambda: (
|
lambda: (
|
||||||
self.miscTab.save_setting("disable_background_state", False),
|
self.miscTab.save_setting("disable_background_state", False),
|
||||||
self.app.quit(),
|
self.app.quit(),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
from PyQt5 import uic
|
from PyQt6 import uic
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
from PyQt5.QtWidgets import QApplication, QCheckBox, QFormLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem
|
from PyQt6.QtWidgets import QApplication, QCheckBox, QFormLayout, QHBoxLayout, QLabel, QSizePolicy, QSpacerItem
|
||||||
from vorta._version import __version__
|
from vorta._version import __version__
|
||||||
from vorta.config import LOG_DIR
|
from vorta.config import LOG_DIR
|
||||||
from vorta.i18n import translate
|
from vorta.i18n import translate
|
||||||
|
@ -87,7 +87,7 @@ class MiscTab(MiscTabBase, MiscTabUI, BackupProfileMixin):
|
||||||
# create widget
|
# create widget
|
||||||
cb = QCheckBox(translate('settings', setting.label))
|
cb = QCheckBox(translate('settings', setting.label))
|
||||||
cb.setToolTip(setting.tooltip)
|
cb.setToolTip(setting.tooltip)
|
||||||
cb.setCheckState(setting.value)
|
cb.setCheckState(Qt.CheckState(setting.value))
|
||||||
cb.setTristate(False)
|
cb.setTristate(False)
|
||||||
cb.stateChanged.connect(lambda v, key=setting.key: self.save_setting(key, v))
|
cb.stateChanged.connect(lambda v, key=setting.key: self.save_setting(key, v))
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Adapted from https://stackoverflow.com/questions/53618971/how-to-make-a-qpushbutton-a-loading-button
|
Adapted from https://stackoverflow.com/questions/53618971/how-to-make-a-qpushbutton-a-loading-button
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
|
||||||
class LoadingButton(QtWidgets.QPushButton):
|
class LoadingButton(QtWidgets.QPushButton):
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from PyQt5.QtCore import QCoreApplication, QEvent, QSize, Qt
|
from PyQt6.QtCore import QCoreApplication, QEvent, QSize, Qt
|
||||||
from PyQt5.QtGui import QHelpEvent, QIcon, QMouseEvent, QPaintEvent
|
from PyQt6.QtGui import QHelpEvent, QIcon, QMouseEvent, QPaintEvent
|
||||||
from PyQt5.QtWidgets import QSizePolicy, QStyle, QStylePainter, QToolTip, QWidget
|
from PyQt6.QtWidgets import QSizePolicy, QStyle, QStylePainter, QToolTip, QWidget
|
||||||
|
|
||||||
|
|
||||||
class ToolTipButton(QWidget):
|
class ToolTipButton(QWidget):
|
||||||
|
@ -24,7 +24,7 @@ class ToolTipButton(QWidget):
|
||||||
"""
|
"""
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setCursor(Qt.CursorShape.WhatsThisCursor)
|
self.setCursor(Qt.CursorShape.WhatsThisCursor)
|
||||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||||
self.setMouseTracking(True)
|
self.setMouseTracking(True)
|
||||||
self._icon = icon or QIcon()
|
self._icon = icon or QIcon()
|
||||||
|
|
||||||
|
@ -98,8 +98,10 @@ class ToolTipButton(QWidget):
|
||||||
https://doc.qt.io/qt-5/qwidget.html#mouseMoveEvent
|
https://doc.qt.io/qt-5/qwidget.html#mouseMoveEvent
|
||||||
"""
|
"""
|
||||||
super().mouseMoveEvent(event)
|
super().mouseMoveEvent(event)
|
||||||
QToolTip.showText(event.globalPos(), self.toolTip(), self)
|
QToolTip.showText(event.globalPosition().toPoint(), self.toolTip(), self)
|
||||||
QCoreApplication.postEvent(self, QHelpEvent(QEvent.Type.ToolTip, event.pos(), event.globalPos()))
|
QCoreApplication.postEvent(
|
||||||
|
self, QHelpEvent(QEvent.Type.ToolTip, event.position().toPoint(), event.globalPosition().toPoint())
|
||||||
|
)
|
||||||
|
|
||||||
def setIcon(self, icon: QIcon):
|
def setIcon(self, icon: QIcon):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -9,7 +9,7 @@ import os.path as osp
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from typing import Generic, List, Optional, Sequence, Tuple, TypeVar, Union, overload
|
from typing import Generic, List, Optional, Sequence, Tuple, TypeVar, Union, overload
|
||||||
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, QObject, QSortFilterProxyModel, Qt, pyqtSignal
|
from PyQt6.QtCore import QAbstractItemModel, QModelIndex, QObject, QSortFilterProxyModel, Qt, pyqtSignal
|
||||||
|
|
||||||
#: A representation of a path
|
#: A representation of a path
|
||||||
Path = Tuple[str, ...]
|
Path = Tuple[str, ...]
|
||||||
|
@ -837,7 +837,7 @@ class FileTreeModel(QAbstractItemModel, Generic[T]):
|
||||||
row, item = parent_item._parent.get(parent_item.subpath)
|
row, item = parent_item._parent.get(parent_item.subpath)
|
||||||
return self.createIndex(row, 0, parent_item)
|
return self.createIndex(row, 0, parent_item)
|
||||||
|
|
||||||
def flags(self, index: QModelIndex) -> Qt.ItemFlags:
|
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
|
||||||
"""
|
"""
|
||||||
Returns the item flags for the given index.
|
Returns the item flags for the given index.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtWidgets import QDialogButtonBox
|
from PyQt6.QtWidgets import QDialogButtonBox
|
||||||
from vorta.i18n import trans_late, translate
|
from vorta.i18n import trans_late, translate
|
||||||
from vorta.store.models import BackupProfileModel
|
from vorta.store.models import BackupProfileModel
|
||||||
from vorta.utils import get_asset
|
from vorta.utils import get_asset
|
||||||
|
@ -14,20 +14,20 @@ class AddProfileWindow(AddProfileBase, AddProfileUI):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
|
||||||
self.edited_profile = None
|
self.edited_profile = None
|
||||||
|
|
||||||
self.buttonBox.rejected.connect(self.close)
|
self.buttonBox.rejected.connect(self.close)
|
||||||
self.buttonBox.accepted.connect(self.save)
|
self.buttonBox.accepted.connect(self.save)
|
||||||
self.profileNameField.textChanged.connect(self.button_validation)
|
self.profileNameField.textChanged.connect(self.button_validation)
|
||||||
|
|
||||||
self.buttonBox.button(QDialogButtonBox.Save).setText(self.tr("Save"))
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setText(self.tr("Save"))
|
||||||
self.buttonBox.button(QDialogButtonBox.Cancel).setText(self.tr("Cancel"))
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(self.tr("Cancel"))
|
||||||
|
|
||||||
self.name_blank = trans_late('AddProfileWindow', 'Please enter a profile name.')
|
self.name_blank = trans_late('AddProfileWindow', 'Please enter a profile name.')
|
||||||
self.name_exists = trans_late('AddProfileWindow', 'A profile with this name already exists.')
|
self.name_exists = trans_late('AddProfileWindow', 'A profile with this name already exists.')
|
||||||
# Call validate to set inital messages
|
# Call validate to set inital messages
|
||||||
self.buttonBox.button(QDialogButtonBox.Save).setEnabled(self.validate())
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(self.validate())
|
||||||
|
|
||||||
def _set_status(self, text):
|
def _set_status(self, text):
|
||||||
self.errorText.setText(text)
|
self.errorText.setText(text)
|
||||||
|
@ -40,7 +40,7 @@ class AddProfileWindow(AddProfileBase, AddProfileUI):
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
def button_validation(self):
|
def button_validation(self):
|
||||||
self.buttonBox.button(QDialogButtonBox.Save).setEnabled(self.validate())
|
self.buttonBox.button(QDialogButtonBox.StandardButton.Save).setEnabled(self.validate())
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
name = self.profileNameField.text()
|
name = self.profileNameField.text()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import re
|
import re
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtWidgets import QAction, QApplication, QDialogButtonBox, QLineEdit
|
from PyQt6.QtGui import QAction
|
||||||
|
from PyQt6.QtWidgets import QApplication, QDialogButtonBox, QLineEdit
|
||||||
from vorta.borg.info_repo import BorgInfoRepoJob
|
from vorta.borg.info_repo import BorgInfoRepoJob
|
||||||
from vorta.borg.init import BorgInitJob
|
from vorta.borg.init import BorgInitJob
|
||||||
from vorta.i18n import translate
|
from vorta.i18n import translate
|
||||||
|
@ -19,7 +20,7 @@ class AddRepoWindow(AddRepoBase, AddRepoUI):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
|
||||||
self.result = None
|
self.result = None
|
||||||
self.is_remote_repo = True
|
self.is_remote_repo = True
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class AddRepoWindow(AddRepoBase, AddRepoUI):
|
||||||
self.showHideAction.setCheckable(True)
|
self.showHideAction.setCheckable(True)
|
||||||
self.showHideAction.toggled.connect(self.set_visibility)
|
self.showHideAction.toggled.connect(self.set_visibility)
|
||||||
|
|
||||||
self.passwordLineEdit.addAction(self.showHideAction, QLineEdit.TrailingPosition)
|
self.passwordLineEdit.addAction(self.showHideAction, QLineEdit.ActionPosition.TrailingPosition)
|
||||||
|
|
||||||
self.tabWidget.setCurrentIndex(0)
|
self.tabWidget.setCurrentIndex(0)
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ class AddRepoWindow(AddRepoBase, AddRepoUI):
|
||||||
self.confirmLineEdit.setText(password)
|
self.confirmLineEdit.setText(password)
|
||||||
|
|
||||||
def set_visibility(self, visible):
|
def set_visibility(self, visible):
|
||||||
visibility = QLineEdit.Normal if visible else QLineEdit.Password
|
visibility = QLineEdit.EchoMode.Normal if visible else QLineEdit.EchoMode.Password
|
||||||
self.passwordLineEdit.setEchoMode(visibility)
|
self.passwordLineEdit.setEchoMode(visibility)
|
||||||
self.confirmLineEdit.setEchoMode(visibility)
|
self.confirmLineEdit.setEchoMode(visibility)
|
||||||
|
|
||||||
|
@ -224,7 +225,7 @@ class ExistingRepoWindow(AddRepoWindow):
|
||||||
del self.confirmLabel
|
del self.confirmLabel
|
||||||
|
|
||||||
def set_visibility(self, visible):
|
def set_visibility(self, visible):
|
||||||
visibility = QLineEdit.Normal if visible else QLineEdit.Password
|
visibility = QLineEdit.EchoMode.Normal if visible else QLineEdit.EchoMode.Password
|
||||||
self.passwordLineEdit.setEchoMode(visibility)
|
self.passwordLineEdit.setEchoMode(visibility)
|
||||||
|
|
||||||
if visible:
|
if visible:
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtCore import QMimeData, QUrl
|
from PyQt6.QtCore import QMimeData, QUrl
|
||||||
from PyQt5.QtWidgets import QApplication, QLayout, QMenu, QMessageBox
|
from PyQt6.QtWidgets import QApplication, QLayout, QMenu, QMessageBox
|
||||||
from vorta.store.models import ArchiveModel, BackupProfileMixin, RepoModel
|
from vorta.store.models import ArchiveModel, BackupProfileMixin, RepoModel
|
||||||
from vorta.utils import borg_compat, get_asset, get_private_keys, pretty_bytes
|
from vorta.utils import borg_compat, get_asset, get_private_keys, pretty_bytes
|
||||||
from .repo_add_dialog import AddRepoWindow, ExistingRepoWindow
|
from .repo_add_dialog import AddRepoWindow, ExistingRepoWindow
|
||||||
|
@ -192,15 +192,15 @@ class RepoTab(RepoBase, RepoUI, BackupProfileMixin):
|
||||||
"""Open a dialog to create an ssh key."""
|
"""Open a dialog to create an ssh key."""
|
||||||
ssh_add_window = SSHAddWindow()
|
ssh_add_window = SSHAddWindow()
|
||||||
self._window = ssh_add_window # For tests
|
self._window = ssh_add_window # For tests
|
||||||
ssh_add_window.setParent(self, QtCore.Qt.Sheet)
|
ssh_add_window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
ssh_add_window.accepted.connect(self.init_ssh)
|
ssh_add_window.accepted.connect(self.init_ssh)
|
||||||
# ssh_add_window.rejected.connect(lambda: self.sshComboBox.setCurrentIndex(0))
|
# ssh_add_window.rejected.connect(lambda: self.sshComboBox.setCurrentIndex(0))
|
||||||
ssh_add_window.open()
|
ssh_add_window.open()
|
||||||
|
|
||||||
def ssh_copy_to_clipboard_action(self):
|
def ssh_copy_to_clipboard_action(self):
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setStandardButtons(QMessageBox.Ok)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||||
msg.setParent(self, QtCore.Qt.Sheet)
|
msg.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
|
|
||||||
index = self.sshComboBox.currentIndex()
|
index = self.sshComboBox.currentIndex()
|
||||||
if index > 0:
|
if index > 0:
|
||||||
|
@ -234,7 +234,7 @@ class RepoTab(RepoBase, RepoUI, BackupProfileMixin):
|
||||||
"""Open a dialog to create a new repo and add it to vorta."""
|
"""Open a dialog to create a new repo and add it to vorta."""
|
||||||
window = AddRepoWindow()
|
window = AddRepoWindow()
|
||||||
self._window = window # For tests
|
self._window = window # For tests
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.added_repo.connect(self.process_new_repo)
|
window.added_repo.connect(self.process_new_repo)
|
||||||
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
|
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
|
||||||
window.open()
|
window.open()
|
||||||
|
@ -243,7 +243,7 @@ class RepoTab(RepoBase, RepoUI, BackupProfileMixin):
|
||||||
"""Open a dialog to add a existing repo to vorta."""
|
"""Open a dialog to add a existing repo to vorta."""
|
||||||
window = ExistingRepoWindow()
|
window = ExistingRepoWindow()
|
||||||
self._window = window # For tests
|
self._window = window # For tests
|
||||||
window.setParent(self, QtCore.Qt.Sheet)
|
window.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
window.added_repo.connect(self.process_new_repo)
|
window.added_repo.connect(self.process_new_repo)
|
||||||
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
|
# window.rejected.connect(lambda: self.repoSelector.setCurrentIndex(0))
|
||||||
window.open()
|
window.open()
|
||||||
|
@ -271,8 +271,8 @@ class RepoTab(RepoBase, RepoUI, BackupProfileMixin):
|
||||||
self.init_repo_stats()
|
self.init_repo_stats()
|
||||||
|
|
||||||
msg = QMessageBox()
|
msg = QMessageBox()
|
||||||
msg.setStandardButtons(QMessageBox.Ok)
|
msg.setStandardButtons(QMessageBox.StandardButton.Ok)
|
||||||
msg.setParent(self, QtCore.Qt.Sheet)
|
msg.setParent(self, QtCore.Qt.WindowType.Sheet)
|
||||||
|
|
||||||
selected_repo_id = self.repoSelector.currentData()
|
selected_repo_id = self.repoSelector.currentData()
|
||||||
selected_repo_index = self.repoSelector.currentIndex()
|
selected_repo_index = self.repoSelector.currentIndex()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from PyQt5 import QtCore, uic
|
from PyQt6 import QtCore, uic
|
||||||
from PyQt5.QtCore import QDateTime, QLocale
|
from PyQt6.QtCore import QDateTime, QLocale
|
||||||
from PyQt5.QtWidgets import QApplication, QHeaderView, QListWidgetItem, QTableView, QTableWidgetItem
|
from PyQt6.QtWidgets import QAbstractItemView, QApplication, QHeaderView, QListWidgetItem, QTableWidgetItem
|
||||||
from vorta import application
|
from vorta import application
|
||||||
from vorta.i18n import get_locale
|
from vorta.i18n import get_locale
|
||||||
from vorta.scheduler import ScheduleStatusType
|
from vorta.scheduler import ScheduleStatusType
|
||||||
|
@ -37,10 +37,10 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
||||||
self.logTableWidget.setAlternatingRowColors(True)
|
self.logTableWidget.setAlternatingRowColors(True)
|
||||||
header = self.logTableWidget.horizontalHeader()
|
header = self.logTableWidget.horizontalHeader()
|
||||||
header.setVisible(True)
|
header.setVisible(True)
|
||||||
[header.setSectionResizeMode(i, QHeaderView.ResizeToContents) for i in range(5)]
|
[header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents) for i in range(5)]
|
||||||
header.setSectionResizeMode(3, QHeaderView.Stretch)
|
header.setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch)
|
||||||
self.logTableWidget.setSelectionBehavior(QTableView.SelectRows)
|
self.logTableWidget.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||||
self.logTableWidget.setEditTriggers(QTableView.NoEditTriggers)
|
self.logTableWidget.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
|
||||||
|
|
||||||
# Scheduler intervals we know
|
# Scheduler intervals we know
|
||||||
self.scheduleIntervalUnit.addItem(self.tr('Minutes'), 'minutes')
|
self.scheduleIntervalUnit.addItem(self.tr('Minutes'), 'minutes')
|
||||||
|
@ -138,17 +138,19 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
||||||
self.scheduleFixedTime.setTime(QtCore.QTime(profile.schedule_fixed_hour, profile.schedule_fixed_minute))
|
self.scheduleFixedTime.setTime(QtCore.QTime(profile.schedule_fixed_hour, profile.schedule_fixed_minute))
|
||||||
|
|
||||||
# Set borg-check options
|
# Set borg-check options
|
||||||
self.validationCheckBox.setCheckState(QtCore.Qt.Checked if profile.validation_on else QtCore.Qt.Unchecked)
|
self.validationCheckBox.setCheckState(
|
||||||
|
QtCore.Qt.CheckState.Checked if profile.validation_on else QtCore.Qt.CheckState.Unchecked
|
||||||
|
)
|
||||||
self.validationWeeksCount.setValue(profile.validation_weeks)
|
self.validationWeeksCount.setValue(profile.validation_weeks)
|
||||||
|
|
||||||
# Other checkbox options
|
# Other checkbox options
|
||||||
self.pruneCheckBox.setCheckState(QtCore.Qt.Checked if profile.prune_on else QtCore.Qt.Unchecked)
|
self.pruneCheckBox.setCheckState(
|
||||||
|
QtCore.Qt.CheckState.Checked if profile.prune_on else QtCore.Qt.CheckState.Unchecked
|
||||||
|
)
|
||||||
self.missedBackupsCheckBox.setCheckState(
|
self.missedBackupsCheckBox.setCheckState(
|
||||||
QtCore.Qt.Checked if profile.schedule_make_up_missed else QtCore.Qt.Unchecked
|
QtCore.Qt.CheckState.Checked if profile.schedule_make_up_missed else QtCore.Qt.CheckState.Unchecked
|
||||||
)
|
|
||||||
self.meteredNetworksCheckBox.setChecked(
|
|
||||||
QtCore.Qt.Unchecked if profile.dont_run_on_metered_networks else QtCore.Qt.Checked
|
|
||||||
)
|
)
|
||||||
|
self.meteredNetworksCheckBox.setChecked(False if profile.dont_run_on_metered_networks else True)
|
||||||
|
|
||||||
self.preBackupCmdLineEdit.setText(profile.pre_backup_cmd)
|
self.preBackupCmdLineEdit.setText(profile.pre_backup_cmd)
|
||||||
self.postBackupCmdLineEdit.setText(profile.post_backup_cmd)
|
self.postBackupCmdLineEdit.setText(profile.post_backup_cmd)
|
||||||
|
@ -183,11 +185,11 @@ class ScheduleTab(ScheduleBase, ScheduleUI, BackupProfileMixin):
|
||||||
for wifi in get_sorted_wifis(self.profile()):
|
for wifi in get_sorted_wifis(self.profile()):
|
||||||
item = QListWidgetItem()
|
item = QListWidgetItem()
|
||||||
item.setText(wifi.ssid)
|
item.setText(wifi.ssid)
|
||||||
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
|
item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
|
||||||
if wifi.allowed:
|
if wifi.allowed:
|
||||||
item.setCheckState(QtCore.Qt.Checked)
|
item.setCheckState(QtCore.Qt.CheckState.Checked)
|
||||||
else:
|
else:
|
||||||
item.setCheckState(QtCore.Qt.Unchecked)
|
item.setCheckState(QtCore.Qt.CheckState.Unchecked)
|
||||||
self.wifiListWidget.addItem(item)
|
self.wifiListWidget.addItem(item)
|
||||||
self.wifiListWidget.itemChanged.connect(self.save_wifi_item)
|
self.wifiListWidget.itemChanged.connect(self.save_wifi_item)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
from PyQt5 import QtCore, QtGui, uic
|
from PyQt6 import QtCore, QtGui, uic
|
||||||
from PyQt5.QtCore import QFileInfo, QMimeData, QPoint, Qt, QUrl, pyqtSlot
|
from PyQt6.QtCore import QFileInfo, QMimeData, QPoint, Qt, QUrl, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QApplication, QHeaderView, QMenu, QMessageBox, QShortcut, QTableWidgetItem
|
from PyQt6.QtGui import QShortcut
|
||||||
|
from PyQt6.QtWidgets import QApplication, QHeaderView, QMenu, QMessageBox, QTableWidgetItem
|
||||||
from vorta.store.models import BackupProfileMixin, SettingsModel, SourceFileModel
|
from vorta.store.models import BackupProfileMixin, SettingsModel, SourceFileModel
|
||||||
from vorta.utils import FilePathInfoAsync, choose_file_dialog, get_asset, pretty_bytes, sort_sizes
|
from vorta.utils import FilePathInfoAsync, choose_file_dialog, get_asset, pretty_bytes, sort_sizes
|
||||||
from vorta.views.utils import get_colored_icon
|
from vorta.views.utils import get_colored_icon
|
||||||
|
@ -23,7 +24,7 @@ class SourceColumn:
|
||||||
class SizeItem(QTableWidgetItem):
|
class SizeItem(QTableWidgetItem):
|
||||||
def __init__(self, s):
|
def __init__(self, s):
|
||||||
super().__init__(s)
|
super().__init__(s)
|
||||||
self.setTextAlignment(Qt.AlignVCenter + Qt.AlignRight)
|
self.setTextAlignment(Qt.AlignmentFlag.AlignVCenter + Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if other.text() == '':
|
if other.text() == '':
|
||||||
|
@ -63,9 +64,9 @@ class SourceTab(SourceBase, SourceUI, BackupProfileMixin):
|
||||||
header.setVisible(True)
|
header.setVisible(True)
|
||||||
header.setSortIndicatorShown(1)
|
header.setSortIndicatorShown(1)
|
||||||
|
|
||||||
header.setSectionResizeMode(SourceColumn.Path, QHeaderView.Stretch)
|
header.setSectionResizeMode(SourceColumn.Path, QHeaderView.ResizeMode.Stretch)
|
||||||
header.setSectionResizeMode(SourceColumn.Size, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(SourceColumn.Size, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
header.setSectionResizeMode(SourceColumn.FilesCount, QHeaderView.ResizeToContents)
|
header.setSectionResizeMode(SourceColumn.FilesCount, QHeaderView.ResizeMode.ResizeToContents)
|
||||||
|
|
||||||
self.sourceFilesWidget.setSortingEnabled(True)
|
self.sourceFilesWidget.setSortingEnabled(True)
|
||||||
self.sourceFilesWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
self.sourceFilesWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||||
|
@ -139,7 +140,7 @@ class SourceTab(SourceBase, SourceUI, BackupProfileMixin):
|
||||||
sorting = self.sourceFilesWidget.isSortingEnabled()
|
sorting = self.sourceFilesWidget.isSortingEnabled()
|
||||||
self.sourceFilesWidget.setSortingEnabled(False)
|
self.sourceFilesWidget.setSortingEnabled(False)
|
||||||
|
|
||||||
items = self.sourceFilesWidget.findItems(path, QtCore.Qt.MatchExactly)
|
items = self.sourceFilesWidget.findItems(path, QtCore.Qt.MatchFlag.MatchExactly)
|
||||||
# Conversion int->str->int needed because QT limits int to 32-bit
|
# Conversion int->str->int needed because QT limits int to 32-bit
|
||||||
data_size = int(data_size)
|
data_size = int(data_size)
|
||||||
files_count = int(files_count)
|
files_count = int(files_count)
|
||||||
|
@ -250,7 +251,7 @@ class SourceTab(SourceBase, SourceUI, BackupProfileMixin):
|
||||||
sourcetab_sort_order = int(SettingsModel.get(key='sourcetab_sort_order').str_value)
|
sourcetab_sort_order = int(SettingsModel.get(key='sourcetab_sort_order').str_value)
|
||||||
|
|
||||||
# Sort items as per settings
|
# Sort items as per settings
|
||||||
self.sourceFilesWidget.sortItems(sourcetab_sort_column, sourcetab_sort_order)
|
self.sourceFilesWidget.sortItems(sourcetab_sort_column, Qt.SortOrder(sourcetab_sort_order))
|
||||||
|
|
||||||
self.excludePatternsField.appendPlainText(profile.exclude_patterns)
|
self.excludePatternsField.appendPlainText(profile.exclude_patterns)
|
||||||
self.excludeIfPresentField.appendPlainText(profile.exclude_if_present)
|
self.excludeIfPresentField.appendPlainText(profile.exclude_if_present)
|
||||||
|
@ -262,7 +263,7 @@ class SourceTab(SourceBase, SourceUI, BackupProfileMixin):
|
||||||
SettingsModel.update({SettingsModel.str_value: str(column)}).where(
|
SettingsModel.update({SettingsModel.str_value: str(column)}).where(
|
||||||
SettingsModel.key == 'sourcetab_sort_column'
|
SettingsModel.key == 'sourcetab_sort_column'
|
||||||
).execute()
|
).execute()
|
||||||
SettingsModel.update({SettingsModel.str_value: str(order)}).where(
|
SettingsModel.update({SettingsModel.str_value: str(order.value)}).where(
|
||||||
SettingsModel.key == 'sourcetab_sort_order'
|
SettingsModel.key == 'sourcetab_sort_order'
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
from PyQt5 import uic
|
from PyQt6 import uic
|
||||||
from PyQt5.QtCore import QProcess, Qt
|
from PyQt6.QtCore import QProcess, Qt
|
||||||
from PyQt5.QtWidgets import QApplication, QDialogButtonBox
|
from PyQt6.QtWidgets import QApplication, QDialogButtonBox
|
||||||
from ..utils import get_asset
|
from ..utils import get_asset
|
||||||
|
|
||||||
uifile = get_asset('UI/sshadd.ui')
|
uifile = get_asset('UI/sshadd.ui')
|
||||||
|
@ -12,7 +12,7 @@ class SSHAddWindow(SSHAddBase, SSHAddUI):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
|
||||||
|
|
||||||
# dialogButtonBox
|
# dialogButtonBox
|
||||||
self.generateButton = self.buttonBox.button(QDialogButtonBox.StandardButton.Ok)
|
self.generateButton = self.buttonBox.button(QDialogButtonBox.StandardButton.Ok)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from PyQt5.QtGui import QIcon, QImage, QPixmap
|
from PyQt6.QtGui import QIcon, QImage, QPixmap
|
||||||
from vorta.utils import get_asset, uses_dark_mode
|
from vorta.utils import get_asset, uses_dark_mode
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,12 @@ def qapp(tmpdir_factory):
|
||||||
mock_db = SqliteDatabase(str(tmp_db))
|
mock_db = SqliteDatabase(str(tmp_db))
|
||||||
vorta.store.connection.init_db(mock_db)
|
vorta.store.connection.init_db(mock_db)
|
||||||
|
|
||||||
|
# Needs to be disabled before calling VortaApp()
|
||||||
|
if sys.platform == 'darwin':
|
||||||
|
cfg = vorta.store.models.SettingsModel.get(key='check_full_disk_access')
|
||||||
|
cfg.value = False
|
||||||
|
cfg.save()
|
||||||
|
|
||||||
from vorta.application import VortaApp
|
from vorta.application import VortaApp
|
||||||
|
|
||||||
VortaApp.set_borg_details_action = MagicMock() # Can't use pytest-mock in session scope
|
VortaApp.set_borg_details_action = MagicMock() # Can't use pytest-mock in session scope
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
import psutil
|
import psutil
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
import vorta.borg
|
import vorta.borg
|
||||||
import vorta.utils
|
import vorta.utils
|
||||||
import vorta.views.archive_tab
|
import vorta.views.archive_tab
|
||||||
|
@ -58,7 +58,7 @@ def test_repo_prune(qapp, qtbot, mocker, borg_json_output):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(tab.bPrune, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.bPrune, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
qtbot.waitUntil(lambda: 'Refreshing archives done.' in main.progressText.text(), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: 'Refreshing archives done.' in main.progressText.text(), **pytest._wait_defaults)
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ def test_repo_compact(qapp, qtbot, mocker, borg_json_output):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(tab.compactButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.compactButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
qtbot.waitUntil(
|
qtbot.waitUntil(
|
||||||
lambda: 'compaction freed about 56.00 kB repository space' in main.logText.text(), **pytest._wait_defaults
|
lambda: 'compaction freed about 56.00 kB repository space' in main.logText.text(), **pytest._wait_defaults
|
||||||
|
@ -91,7 +91,7 @@ def test_check(qapp, mocker, borg_json_output, qtbot):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(tab.bCheck, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.bCheck, QtCore.Qt.MouseButton.LeftButton)
|
||||||
success_text = 'INFO: Archive consistency check complete'
|
success_text = 'INFO: Archive consistency check complete'
|
||||||
qtbot.waitUntil(lambda: success_text in main.logText.text(), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: success_text in main.logText.text(), **pytest._wait_defaults)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5.QtCore import QDateTime, QItemSelectionModel, Qt
|
from PyQt6.QtCore import QDateTime, QItemSelectionModel, Qt
|
||||||
import vorta.borg
|
import vorta.borg
|
||||||
import vorta.utils
|
import vorta.utils
|
||||||
import vorta.views.archive_tab
|
import vorta.views.archive_tab
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from PyQt5.QtCore import QModelIndex, Qt
|
from PyQt6.QtCore import QModelIndex, Qt
|
||||||
import vorta.borg
|
import vorta.borg
|
||||||
from vorta.views.extract_dialog import ExtractTree, FileData, FileType, parse_json_lines
|
from vorta.views.extract_dialog import ExtractTree, FileData, FileType, parse_json_lines
|
||||||
from vorta.views.partials.treemodel import FileSystemItem
|
from vorta.views.partials.treemodel import FileSystemItem
|
||||||
|
@ -92,12 +92,12 @@ def test_selection():
|
||||||
c: FileSystemItem[FileData] = ic.internalPointer()
|
c: FileSystemItem[FileData] = ic.internalPointer()
|
||||||
|
|
||||||
select(model, ic)
|
select(model, ic)
|
||||||
assert c.data.checkstate == 2
|
assert c.data.checkstate == Qt.CheckState(2)
|
||||||
assert c.data.checked_children == 0
|
assert c.data.checked_children == 0
|
||||||
|
|
||||||
# Test deselect
|
# Test deselect
|
||||||
deselect(model, ic)
|
deselect(model, ic)
|
||||||
assert c.data.checkstate == 0
|
assert c.data.checkstate == Qt.CheckState(0)
|
||||||
assert c.data.checked_children == 0
|
assert c.data.checked_children == 0
|
||||||
|
|
||||||
# Test select parent as well as children
|
# Test select parent as well as children
|
||||||
|
@ -121,19 +121,19 @@ def test_selection():
|
||||||
iab = model.indexPath(("a", "b"))
|
iab = model.indexPath(("a", "b"))
|
||||||
deselect(model, iab)
|
deselect(model, iab)
|
||||||
|
|
||||||
assert a.data.checkstate == 1
|
assert a.data.checkstate == Qt.CheckState(1)
|
||||||
assert aa.data.checkstate == 2
|
assert aa.data.checkstate == Qt.CheckState(2)
|
||||||
assert ab.data.checkstate == 0
|
assert ab.data.checkstate == Qt.CheckState(0)
|
||||||
assert abc.data.checkstate == 0
|
assert abc.data.checkstate == Qt.CheckState(0)
|
||||||
assert a.data.checked_children == 1
|
assert a.data.checked_children == 1
|
||||||
assert ab.data.checked_children == 0
|
assert ab.data.checked_children == 0
|
||||||
|
|
||||||
# Test deselect item and children
|
# Test deselect item and children
|
||||||
deselect(model, ia)
|
deselect(model, ia)
|
||||||
|
|
||||||
assert a.data.checkstate == 0
|
assert a.data.checkstate == Qt.CheckState(0)
|
||||||
assert aa.data.checkstate == 0
|
assert aa.data.checkstate == Qt.CheckState(0)
|
||||||
assert ab.data.checkstate == 0
|
assert ab.data.checkstate == Qt.CheckState(0)
|
||||||
assert a.data.checked_children == 0
|
assert a.data.checked_children == 0
|
||||||
assert aa.data.checked_children == 0
|
assert aa.data.checked_children == 0
|
||||||
|
|
||||||
|
@ -146,9 +146,9 @@ def test_selection():
|
||||||
select(model, iab)
|
select(model, iab)
|
||||||
select(model, iaac)
|
select(model, iaac)
|
||||||
|
|
||||||
assert a.data.checkstate == 1
|
assert a.data.checkstate == Qt.CheckState(1)
|
||||||
assert aa.data.checkstate == 1
|
assert aa.data.checkstate == Qt.CheckState(1)
|
||||||
assert ab.data.checkstate == 2
|
assert ab.data.checkstate == Qt.CheckState(2)
|
||||||
|
|
||||||
assert a.data.checked_children == 2
|
assert a.data.checked_children == 2
|
||||||
assert ab.data.checked_children == 2
|
assert ab.data.checked_children == 2
|
||||||
|
@ -159,21 +159,21 @@ def test_selection():
|
||||||
deselect(model, iaa)
|
deselect(model, iaa)
|
||||||
deselect(model, iab)
|
deselect(model, iab)
|
||||||
|
|
||||||
assert a.data.checkstate == 0
|
assert a.data.checkstate == Qt.CheckState(0)
|
||||||
assert a.data.checked_children == 0
|
assert a.data.checked_children == 0
|
||||||
|
|
||||||
# Test select child with deselected parent
|
# Test select child with deselected parent
|
||||||
select(model, iaac)
|
select(model, iaac)
|
||||||
|
|
||||||
assert a.data.checkstate == 1
|
assert a.data.checkstate == Qt.CheckState(1)
|
||||||
assert ab.data.checkstate == 0
|
assert ab.data.checkstate == Qt.CheckState(0)
|
||||||
assert aa.data.checkstate == 1
|
assert aa.data.checkstate == Qt.CheckState(1)
|
||||||
assert a.data.checked_children == 1
|
assert a.data.checked_children == 1
|
||||||
assert ab.data.checked_children == 0
|
assert ab.data.checked_children == 0
|
||||||
assert aa.data.checked_children == 1
|
assert aa.data.checked_children == 1
|
||||||
|
|
||||||
select(model, iaa)
|
select(model, iaa)
|
||||||
assert a.data.checkstate == 1
|
assert a.data.checkstate == Qt.CheckState(1)
|
||||||
|
|
||||||
select(model, iab)
|
select(model, iab)
|
||||||
assert a.data.checkstate == 1
|
assert a.data.checkstate == Qt.CheckState(1)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QDialogButtonBox, QFileDialog, QMessageBox
|
from PyQt6.QtWidgets import QDialogButtonBox, QFileDialog, QMessageBox
|
||||||
from vorta.store.models import BackupProfileModel, SourceFileModel
|
from vorta.store.models import BackupProfileModel, SourceFileModel
|
||||||
from vorta.views.import_window import ImportWindow
|
from vorta.views.import_window import ImportWindow
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ def test_import_success(qapp, qtbot, rootdir, monkeypatch):
|
||||||
import_dialog: ImportWindow = main.window
|
import_dialog: ImportWindow = main.window
|
||||||
import_dialog.overwriteExistingSettings.setChecked(True)
|
import_dialog.overwriteExistingSettings.setChecked(True)
|
||||||
|
|
||||||
qtbot.mouseClick(import_dialog.buttonBox.button(QDialogButtonBox.Ok), QtCore.Qt.LeftButton)
|
qtbot.mouseClick(
|
||||||
|
import_dialog.buttonBox.button(QDialogButtonBox.StandardButton.Ok), QtCore.Qt.MouseButton.LeftButton
|
||||||
|
)
|
||||||
qtbot.waitSignal(import_dialog.profile_imported, **pytest._wait_defaults)
|
qtbot.waitSignal(import_dialog.profile_imported, **pytest._wait_defaults)
|
||||||
|
|
||||||
restored_profile = BackupProfileModel.get_or_none(name="Test Profile Restoration")
|
restored_profile = BackupProfileModel.get_or_none(name="Test Profile Restoration")
|
||||||
|
@ -81,7 +83,9 @@ def test_export_success(qapp, qtbot, tmpdir, monkeypatch):
|
||||||
main.profile_export_action()
|
main.profile_export_action()
|
||||||
export_dialog = main.window
|
export_dialog = main.window
|
||||||
|
|
||||||
qtbot.mouseClick(export_dialog.buttonBox.button(QDialogButtonBox.Save), QtCore.Qt.LeftButton)
|
qtbot.mouseClick(
|
||||||
|
export_dialog.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||||
|
)
|
||||||
qtbot.waitUntil(lambda: os.path.isfile(FILE_PATH))
|
qtbot.waitUntil(lambda: os.path.isfile(FILE_PATH))
|
||||||
|
|
||||||
assert os.path.isfile(FILE_PATH)
|
assert os.path.isfile(FILE_PATH)
|
||||||
|
@ -107,7 +111,9 @@ def test_export_fail_unwritable(qapp, qtbot, tmpdir, monkeypatch):
|
||||||
main.profile_export_action()
|
main.profile_export_action()
|
||||||
export_dialog = main.window
|
export_dialog = main.window
|
||||||
|
|
||||||
qtbot.mouseClick(export_dialog.buttonBox.button(QDialogButtonBox.Save), QtCore.Qt.LeftButton)
|
qtbot.mouseClick(
|
||||||
|
export_dialog.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||||
|
)
|
||||||
|
|
||||||
assert 'could not be created' in alert_message
|
assert 'could not be created' in alert_message
|
||||||
assert not os.path.isfile(FILE_PATH)
|
assert not os.path.isfile(FILE_PATH)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
import vorta.application
|
import vorta.application
|
||||||
import vorta.borg.borg_job
|
import vorta.borg.borg_job
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ def test_create_perm_error(qapp, borg_json_output, mocker, qtbot):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
qtbot.waitUntil(lambda: hasattr(qapp, '_msg'), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: hasattr(qapp, '_msg'), **pytest._wait_defaults)
|
||||||
assert qapp._msg.text().startswith("You do not have permission")
|
assert qapp._msg.text().startswith("You do not have permission")
|
||||||
|
@ -28,7 +28,7 @@ def test_create_lock(qapp, borg_json_output, mocker, qtbot):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
qtbot.waitUntil(lambda: hasattr(qapp, '_msg'), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: hasattr(qapp, '_msg'), **pytest._wait_defaults)
|
||||||
assert "The repository at" in qapp._msg.text()
|
assert "The repository at" in qapp._msg.text()
|
||||||
|
|
|
@ -3,8 +3,8 @@ import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QCheckBox, QFormLayout
|
from PyQt6.QtWidgets import QCheckBox, QFormLayout
|
||||||
import vorta.store.models
|
import vorta.store.models
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,5 +79,7 @@ def _click_toggle_setting(setting, qapp, qtbot):
|
||||||
if checkbox.text() == setting:
|
if checkbox.text() == setting:
|
||||||
# Have to use pos to click checkbox correctly
|
# Have to use pos to click checkbox correctly
|
||||||
# https://stackoverflow.com/questions/19418125/pysides-qtest-not-checking-box/24070484#24070484
|
# https://stackoverflow.com/questions/19418125/pysides-qtest-not-checking-box/24070484#24070484
|
||||||
qtbot.mouseClick(checkbox, QtCore.Qt.LeftButton, pos=QtCore.QPoint(2, int(checkbox.height() / 2)))
|
qtbot.mouseClick(
|
||||||
|
checkbox, QtCore.Qt.MouseButton.LeftButton, pos=QtCore.QPoint(2, int(checkbox.height() / 2))
|
||||||
|
)
|
||||||
break
|
break
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtDBus
|
from PyQt6 import QtDBus
|
||||||
import vorta.borg
|
import vorta.borg
|
||||||
import vorta.notifications
|
import vorta.notifications
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
from PyQt5.QtWidgets import QDialogButtonBox
|
from PyQt6.QtWidgets import QDialogButtonBox
|
||||||
from vorta.store.models import BackupProfileModel
|
from vorta.store.models import BackupProfileModel
|
||||||
|
|
||||||
|
|
||||||
def test_profile_add(qapp, qtbot):
|
def test_profile_add(qapp, qtbot):
|
||||||
main = qapp.main_window
|
main = qapp.main_window
|
||||||
qtbot.mouseClick(main.profileAddButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.profileAddButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
add_profile_window = main.window
|
add_profile_window = main.window
|
||||||
qtbot.addWidget(add_profile_window)
|
# qtbot.addWidget(add_profile_window)
|
||||||
|
|
||||||
qtbot.keyClicks(add_profile_window.profileNameField, 'Test Profile')
|
qtbot.keyClicks(add_profile_window.profileNameField, 'Test Profile')
|
||||||
qtbot.mouseClick(add_profile_window.buttonBox.button(QDialogButtonBox.Save), QtCore.Qt.LeftButton)
|
qtbot.mouseClick(
|
||||||
|
add_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||||
|
)
|
||||||
|
|
||||||
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
||||||
assert main.profileSelector.currentText() == 'Test Profile'
|
assert main.profileSelector.currentText() == 'Test Profile'
|
||||||
|
@ -19,14 +21,16 @@ def test_profile_add(qapp, qtbot):
|
||||||
|
|
||||||
def test_profile_edit(qapp, qtbot):
|
def test_profile_edit(qapp, qtbot):
|
||||||
main = qapp.main_window
|
main = qapp.main_window
|
||||||
qtbot.mouseClick(main.profileRenameButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.profileRenameButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
edit_profile_window = main.window
|
edit_profile_window = main.window
|
||||||
qtbot.addWidget(edit_profile_window)
|
# qtbot.addWidget(edit_profile_window)
|
||||||
|
|
||||||
edit_profile_window.profileNameField.setText("")
|
edit_profile_window.profileNameField.setText("")
|
||||||
qtbot.keyClicks(edit_profile_window.profileNameField, 'Test Profile')
|
qtbot.keyClicks(edit_profile_window.profileNameField, 'Test Profile')
|
||||||
qtbot.mouseClick(edit_profile_window.buttonBox.button(QDialogButtonBox.Save), QtCore.Qt.LeftButton)
|
qtbot.mouseClick(
|
||||||
|
edit_profile_window.buttonBox.button(QDialogButtonBox.StandardButton.Save), QtCore.Qt.MouseButton.LeftButton
|
||||||
|
)
|
||||||
|
|
||||||
assert BackupProfileModel.get_or_none(name='Default') is None
|
assert BackupProfileModel.get_or_none(name='Default') is None
|
||||||
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
assert BackupProfileModel.get_or_none(name='Test Profile') is not None
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
|
from PyQt6.QtWidgets import QMessageBox
|
||||||
import vorta.borg.borg_job
|
import vorta.borg.borg_job
|
||||||
from vorta.keyring.abc import VortaKeyring
|
from vorta.keyring.abc import VortaKeyring
|
||||||
from vorta.store.models import ArchiveModel, EventLogModel, RepoModel
|
from vorta.store.models import ArchiveModel, EventLogModel, RepoModel
|
||||||
|
@ -20,7 +21,7 @@ def test_repo_add_failures(qapp, qtbot, mocker, borg_json_output):
|
||||||
qtbot.keyClicks(add_repo_window.passwordLineEdit, LONG_PASSWORD)
|
qtbot.keyClicks(add_repo_window.passwordLineEdit, LONG_PASSWORD)
|
||||||
qtbot.keyClicks(add_repo_window.confirmLineEdit, LONG_PASSWORD)
|
qtbot.keyClicks(add_repo_window.confirmLineEdit, LONG_PASSWORD)
|
||||||
qtbot.keyClicks(add_repo_window.repoURL, 'aaa')
|
qtbot.keyClicks(add_repo_window.repoURL, 'aaa')
|
||||||
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert add_repo_window.errorText.text().startswith('Please enter a valid')
|
assert add_repo_window.errorText.text().startswith('Please enter a valid')
|
||||||
|
|
||||||
add_repo_window.passwordLineEdit.clear()
|
add_repo_window.passwordLineEdit.clear()
|
||||||
|
@ -28,34 +29,35 @@ def test_repo_add_failures(qapp, qtbot, mocker, borg_json_output):
|
||||||
qtbot.keyClicks(add_repo_window.passwordLineEdit, SHORT_PASSWORD)
|
qtbot.keyClicks(add_repo_window.passwordLineEdit, SHORT_PASSWORD)
|
||||||
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
||||||
qtbot.keyClicks(add_repo_window.repoURL, 'bbb.com:repo')
|
qtbot.keyClicks(add_repo_window.repoURL, 'bbb.com:repo')
|
||||||
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert add_repo_window.passwordLabel.text() == 'Passwords must be greater than 8 characters long.'
|
assert add_repo_window.passwordLabel.text() == 'Passwords must be greater than 8 characters long.'
|
||||||
|
|
||||||
add_repo_window.passwordLineEdit.clear()
|
add_repo_window.passwordLineEdit.clear()
|
||||||
add_repo_window.confirmLineEdit.clear()
|
add_repo_window.confirmLineEdit.clear()
|
||||||
qtbot.keyClicks(add_repo_window.passwordLineEdit, SHORT_PASSWORD + "1")
|
qtbot.keyClicks(add_repo_window.passwordLineEdit, SHORT_PASSWORD + "1")
|
||||||
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
||||||
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert add_repo_window.passwordLabel.text() == 'Passwords must be identical and greater than 8 characters long.'
|
assert add_repo_window.passwordLabel.text() == 'Passwords must be identical and greater than 8 characters long.'
|
||||||
|
|
||||||
add_repo_window.passwordLineEdit.clear()
|
add_repo_window.passwordLineEdit.clear()
|
||||||
add_repo_window.confirmLineEdit.clear()
|
add_repo_window.confirmLineEdit.clear()
|
||||||
qtbot.keyClicks(add_repo_window.passwordLineEdit, LONG_PASSWORD)
|
qtbot.keyClicks(add_repo_window.passwordLineEdit, LONG_PASSWORD)
|
||||||
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
qtbot.keyClicks(add_repo_window.confirmLineEdit, SHORT_PASSWORD)
|
||||||
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(add_repo_window.saveButton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert add_repo_window.passwordLabel.text() == 'Passwords must be identical.'
|
assert add_repo_window.passwordLabel.text() == 'Passwords must be identical.'
|
||||||
|
|
||||||
|
|
||||||
def test_repo_unlink(qapp, qtbot):
|
def test_repo_unlink(qapp, qtbot, monkeypatch):
|
||||||
main = qapp.main_window
|
main = qapp.main_window
|
||||||
tab = main.repoTab
|
tab = main.repoTab
|
||||||
|
monkeypatch.setattr(QMessageBox, "show", lambda *args: True)
|
||||||
|
|
||||||
main.tabWidget.setCurrentIndex(0)
|
main.tabWidget.setCurrentIndex(0)
|
||||||
qtbot.mouseClick(tab.repoRemoveToolbutton, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.repoRemoveToolbutton, QtCore.Qt.MouseButton.LeftButton)
|
||||||
qtbot.waitUntil(lambda: tab.repoSelector.count() == 1, **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: tab.repoSelector.count() == 1, **pytest._wait_defaults)
|
||||||
assert RepoModel.select().count() == 0
|
assert RepoModel.select().count() == 0
|
||||||
|
|
||||||
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.MouseButton.LeftButton)
|
||||||
# -1 is the repo id in this test
|
# -1 is the repo id in this test
|
||||||
qtbot.waitUntil(lambda: 'Select a backup repository first.' in main.progressText.text(), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: 'Select a backup repository first.' in main.progressText.text(), **pytest._wait_defaults)
|
||||||
assert 'Select a backup repository first.' in main.progressText.text()
|
assert 'Select a backup repository first.' in main.progressText.text()
|
||||||
|
@ -105,7 +107,7 @@ def test_repo_add_success(qapp, qtbot, mocker, borg_json_output):
|
||||||
|
|
||||||
def test_ssh_dialog(qapp, qtbot, tmpdir):
|
def test_ssh_dialog(qapp, qtbot, tmpdir):
|
||||||
main = qapp.main_window
|
main = qapp.main_window
|
||||||
qtbot.mouseClick(main.repoTab.bAddSSHKey, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.repoTab.bAddSSHKey, QtCore.Qt.MouseButton.LeftButton)
|
||||||
ssh_dialog = main.repoTab._window
|
ssh_dialog = main.repoTab._window
|
||||||
|
|
||||||
ssh_dir = tmpdir
|
ssh_dir = tmpdir
|
||||||
|
@ -135,7 +137,7 @@ def test_create(qapp, borg_json_output, mocker, qtbot):
|
||||||
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
popen_result = mocker.MagicMock(stdout=stdout, stderr=stderr, returncode=0)
|
||||||
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
mocker.patch.object(vorta.borg.borg_job, 'Popen', return_value=popen_result)
|
||||||
|
|
||||||
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(main.createStartBtn, QtCore.Qt.MouseButton.LeftButton)
|
||||||
qtbot.waitUntil(lambda: 'Backup finished.' in main.progressText.text(), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: 'Backup finished.' in main.progressText.text(), **pytest._wait_defaults)
|
||||||
qtbot.waitUntil(lambda: main.createStartBtn.isEnabled(), **pytest._wait_defaults)
|
qtbot.waitUntil(lambda: main.createStartBtn.isEnabled(), **pytest._wait_defaults)
|
||||||
assert EventLogModel.select().count() == 1
|
assert EventLogModel.select().count() == 1
|
||||||
|
|
|
@ -2,7 +2,7 @@ from datetime import datetime as dt
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from unittest.mock import MagicMock
|
from unittest.mock import MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5 import QtCore
|
from PyQt6 import QtCore
|
||||||
import vorta.scheduler
|
import vorta.scheduler
|
||||||
from vorta.application import VortaApp
|
from vorta.application import VortaApp
|
||||||
from vorta.store.models import BackupProfileModel, EventLogModel
|
from vorta.store.models import BackupProfileModel, EventLogModel
|
||||||
|
@ -31,17 +31,17 @@ def test_schedule_tab(qapp: VortaApp, qtbot, clockmock):
|
||||||
qapp.scheduler.schedule_changed.connect(lambda *args: tab.draw_next_scheduled_backup())
|
qapp.scheduler.schedule_changed.connect(lambda *args: tab.draw_next_scheduled_backup())
|
||||||
|
|
||||||
# Test
|
# Test
|
||||||
qtbot.mouseClick(tab.scheduleOffRadio, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.scheduleOffRadio, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert tab.nextBackupDateTimeLabel.text() == 'None scheduled'
|
assert tab.nextBackupDateTimeLabel.text() == 'None scheduled'
|
||||||
|
|
||||||
tab.scheduleIntervalCount.setValue(5)
|
tab.scheduleIntervalCount.setValue(5)
|
||||||
qtbot.mouseClick(tab.scheduleIntervalRadio, QtCore.Qt.LeftButton)
|
qtbot.mouseClick(tab.scheduleIntervalRadio, QtCore.Qt.MouseButton.LeftButton)
|
||||||
assert "None" not in tab.nextBackupDateTimeLabel.text()
|
assert "None" not in tab.nextBackupDateTimeLabel.text()
|
||||||
|
|
||||||
tab.scheduleFixedTime.setTime(QtCore.QTime(23, 59))
|
tab.scheduleFixedTime.setTime(QtCore.QTime(23, 59))
|
||||||
|
|
||||||
# Clicking currently broken for this button on github.com only
|
# Clicking currently broken for this button on github.com only
|
||||||
# qtbot.mouseClick(tab.scheduleFixedRadio, QtCore.Qt.LeftButton)
|
# qtbot.mouseClick(tab.scheduleFixedRadio, QtCore.Qt.MouseButton.LeftButton)
|
||||||
|
|
||||||
# Workaround for github
|
# Workaround for github
|
||||||
tab.scheduleFixedRadio.setChecked(True)
|
tab.scheduleFixedRadio.setChecked(True)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from pathlib import PurePath
|
from pathlib import PurePath
|
||||||
import pytest
|
import pytest
|
||||||
from PyQt5.QtCore import QModelIndex
|
from PyQt6.QtCore import QModelIndex
|
||||||
from vorta.views.partials.treemodel import FileSystemItem, FileTreeModel
|
from vorta.views.partials.treemodel import FileSystemItem, FileTreeModel
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue