Skip to content

Commit

Permalink
Avoid changing GUI in QThread
Browse files Browse the repository at this point in the history
  • Loading branch information
m3nu committed Mar 16, 2024
1 parent 61fe1f3 commit 504be70
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 208 deletions.
82 changes: 74 additions & 8 deletions src/vorta/views/archive_tab.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import sys
from typing import Dict, Optional
from datetime import timedelta

from PyQt6 import QtCore, uic
from PyQt6.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, pyqtSlot
Expand Down Expand Up @@ -36,13 +37,15 @@
borg_compat,
choose_file_dialog,
format_archive_name,
get_asset
get_asset,
pretty_bytes,
find_best_unit_for_sizes
)
from vorta.views import diff_result, extract_dialog
from vorta.views.diff_result import DiffResultDialog, DiffTree
from vorta.views.extract_dialog import ExtractDialog, ExtractTree
from vorta.views.utils import get_colored_icon
from vorta.views.workers.archive_table_worker import PopulateArchiveTableAsync
from vorta.views.utils import get_colored_icon, SizeItem
from vorta.views.workers.mount_points_worker import MountPointsWorker

uifile = get_asset('UI/archivetab.ui')
ArchiveTabUI, ArchiveTabBase = uic.loadUiType(uifile)
Expand Down Expand Up @@ -234,23 +237,85 @@ def _toggle_all_buttons(self, enabled=True):
# Restore states
self.on_selection_change()

def set_mount_points(self, mount_points, repo_mounts):
if len(repo_mounts) == 0:
return

archives = [s for s in self.profile().repo.archives.select().order_by(ArchiveModel.time.desc())]

# if no archive's name can be found in self.mount_points, then hide the mount point column
if not any(a.name in mount_points for a in archives):
return
else:
self.archiveTable.showColumn(3)
self.repo_mount_point = repo_mounts[0]

for row, archive in enumerate(archives):
mount_point = self.mount_points.get(archive.name)
if mount_point is not None:
item = QTableWidgetItem(mount_point)
self.archiveTable.setItem(row, 3, item)

def populate_from_profile(self):
"""Populate archive list and prune settings from profile."""
self.archiveTable.blockSignals(True)
profile = self.profile()
if profile.repo is not None:

if profile.repo.name:
repo_name = f"{profile.repo.name} ({profile.repo.url})"
else:
repo_name = profile.repo.url
self.toolBox.setItemText(0, self.tr('Archives for {}').format(repo_name))

populateArchiveTableWorker = PopulateArchiveTableAsync(profile, self.mount_points, self.archiveTable)
populateArchiveTableWorker = MountPointsWorker(profile.repo.url)
self.workers.append(populateArchiveTableWorker) # preserve worker reference
populateArchiveTableWorker.signal.connect(self.set_mount_points)
populateArchiveTableWorker.start()
self.archiveTable.hideColumn(3)

archives = [s for s in profile.repo.archives.select().order_by(ArchiveModel.time.desc())]

sorting = self.archiveTable.isSortingEnabled()
self.archiveTable.setSortingEnabled(False)
best_unit = find_best_unit_for_sizes((a.size for a in archives), precision=SIZE_DECIMAL_DIGITS)
for row, archive in enumerate(archives):
self.archiveTable.insertRow(row)

formatted_time = archive.time.strftime('%Y-%m-%d %H:%M')
self.archiveTable.setItem(row, 0, QTableWidgetItem(formatted_time))

if self.remaining_refresh_archives == 0:
self._toggle_all_buttons(enabled=True)
# format units based on user settings for 'dynamic' or 'fixed' units
fixed_unit = best_unit if SettingsModel.get(key='enable_fixed_units').value else None
size = pretty_bytes(archive.size, fixed_unit=fixed_unit, precision=SIZE_DECIMAL_DIGITS)
self.archiveTable.setItem(row, 1, SizeItem(size))

if archive.duration is not None:
formatted_duration = str(timedelta(seconds=round(archive.duration)))
else:
formatted_duration = ''

self.archiveTable.setItem(row, 2, QTableWidgetItem(formatted_duration))
self.archiveTable.setItem(row, 4, QTableWidgetItem(archive.name))

if archive.trigger == 'scheduled':
item = QTableWidgetItem(get_colored_icon('clock-o'), '')
item.setToolTip(self.tr('Scheduled'))
self.archiveTable.setItem(row, 5, item)
elif archive.trigger == 'user':
item = QTableWidgetItem(get_colored_icon('user'), '')
item.setToolTip(self.tr('User initiated'))
item.setTextAlignment(Qt.AlignmentFlag.AlignRight)
self.archiveTable.setItem(row, 5, item)

self.archiveTable.setRowCount(len(archives))
self.archiveTable.setSortingEnabled(sorting)
item = self.archiveTable.item(0, 0)
self.archiveTable.scrollToItem(item)

self.archiveTable.selectionModel().clearSelection()

if self.remaining_refresh_archives == 0:
self._toggle_all_buttons(enabled=True)
else:
self.mount_points = {}
self.archiveTable.setRowCount(0)
Expand All @@ -261,13 +326,14 @@ def populate_from_profile(self):
self.prunePrefixTemplate.setText(profile.prune_prefix)

# Populate pruning options from database
profile = self.profile()
for i in self.prune_intervals:
getattr(self, f'prune_{i}').setValue(getattr(profile, f'prune_{i}'))
getattr(self, f'prune_{i}').valueChanged.connect(self.save_prune_setting)
self.prune_keep_within.setText(profile.prune_keep_within)
self.prune_keep_within.editingFinished.connect(self.save_prune_setting)

self.archiveTable.blockSignals(False)

def on_selection_change(self, selected=None, deselected=None):
"""
React to a change of the selection of the archiveTableView.
Expand Down
4 changes: 2 additions & 2 deletions src/vorta/views/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,11 @@ def profile_selection_changed_action(self, index):
logger.info('step 1')
self.archiveTab.populate_from_profile()
logger.info('step 2')
self.repoTab.populate_from_profile() # 1s
self.repoTab.populate_from_profile()
logger.info('step 3')
self.sourceTab.populate_from_profile()
logger.info('step 4')
self.scheduleTab.populate_from_profile() #1s
self.scheduleTab.populate_from_profile()
logger.info('step 5')
SettingsModel.update({SettingsModel.str_value: self.current_profile.id}).where(
SettingsModel.key == 'previous_profile_id'
Expand Down
36 changes: 19 additions & 17 deletions src/vorta/views/schedule_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from vorta.scheduler import ScheduleStatusType
from vorta.store.models import BackupProfileMixin, EventLogModel, WifiSettingModel
from vorta.utils import get_asset
from vorta.views.workers.wifi_list_worker import PopulateWifiAsync
from vorta.views.workers.wifi_list_worker import WifiListWorker
from vorta.views.utils import get_colored_icon

uifile = get_asset('UI/scheduletab.ui')
Expand Down Expand Up @@ -173,12 +173,27 @@ def populate_from_profile(self):
else:
self.createCmdLineEdit.setEnabled(False)

populateWifiWorker = PopulateWifiAsync(profile, self.wifiListWidget)
self.workers.append(populateWifiWorker) # preserve reference
populateWifiWorker.start()
wifiListWorker = WifiListWorker(profile.id)
self.workers.append(wifiListWorker) # preserve reference
wifiListWorker.signal.connect(self.set_wifi_list)
wifiListWorker.start()

self.populate_logs()
self.draw_next_scheduled_backup()

def set_wifi_list(self, wifi_list):
self.wifiListWidget.clear()
for wifi in wifi_list:
item = QListWidgetItem()
item.setText(wifi.ssid)
item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
if wifi.allowed:
item.setCheckState(QtCore.Qt.CheckState.Checked)
else:
item.setCheckState(QtCore.Qt.CheckState.Unchecked)
self.wifiListWidget.addItem(item)


def draw_next_scheduled_backup(self):
status = self.app.scheduler.next_job_for_profile(self.profile().id)
if status.type in (
Expand All @@ -195,19 +210,6 @@ def draw_next_scheduled_backup(self):
self.nextBackupDateTimeLabel.setText(text)
self.nextBackupDateTimeLabel.repaint()

# def populate_wifi(self):
# self.wifiListWidget.clear()
# for wifi in get_sorted_wifis(self.profile()):
# item = QListWidgetItem()
# item.setText(wifi.ssid)
# item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
# if wifi.allowed:
# item.setCheckState(QtCore.Qt.CheckState.Checked)
# else:
# item.setCheckState(QtCore.Qt.CheckState.Unchecked)
# self.wifiListWidget.addItem(item)
# self.wifiListWidget.itemChanged.connect(self.save_wifi_item)

def save_wifi_item(self, item):
db_item = WifiSettingModel.get(ssid=item.text(), profile=self.profile().id)
db_item.allowed = item.checkState() == Qt.CheckState.Checked
Expand Down
134 changes: 0 additions & 134 deletions src/vorta/views/workers/archive_table_worker.py

This file was deleted.

Loading

0 comments on commit 504be70

Please sign in to comment.