Skip to content

Commit 504be70

Browse files
committed
Avoid changing GUI in QThread
1 parent 61fe1f3 commit 504be70

File tree

6 files changed

+200
-208
lines changed

6 files changed

+200
-208
lines changed

src/vorta/views/archive_tab.py

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import sys
33
from typing import Dict, Optional
4+
from datetime import timedelta
45

56
from PyQt6 import QtCore, uic
67
from PyQt6.QtCore import QItemSelectionModel, QMimeData, QPoint, Qt, pyqtSlot
@@ -36,13 +37,15 @@
3637
borg_compat,
3738
choose_file_dialog,
3839
format_archive_name,
39-
get_asset
40+
get_asset,
41+
pretty_bytes,
42+
find_best_unit_for_sizes
4043
)
4144
from vorta.views import diff_result, extract_dialog
4245
from vorta.views.diff_result import DiffResultDialog, DiffTree
4346
from vorta.views.extract_dialog import ExtractDialog, ExtractTree
44-
from vorta.views.utils import get_colored_icon
45-
from vorta.views.workers.archive_table_worker import PopulateArchiveTableAsync
47+
from vorta.views.utils import get_colored_icon, SizeItem
48+
from vorta.views.workers.mount_points_worker import MountPointsWorker
4649

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

240+
def set_mount_points(self, mount_points, repo_mounts):
241+
if len(repo_mounts) == 0:
242+
return
243+
244+
archives = [s for s in self.profile().repo.archives.select().order_by(ArchiveModel.time.desc())]
245+
246+
# if no archive's name can be found in self.mount_points, then hide the mount point column
247+
if not any(a.name in mount_points for a in archives):
248+
return
249+
else:
250+
self.archiveTable.showColumn(3)
251+
self.repo_mount_point = repo_mounts[0]
252+
253+
for row, archive in enumerate(archives):
254+
mount_point = self.mount_points.get(archive.name)
255+
if mount_point is not None:
256+
item = QTableWidgetItem(mount_point)
257+
self.archiveTable.setItem(row, 3, item)
258+
237259
def populate_from_profile(self):
238260
"""Populate archive list and prune settings from profile."""
261+
self.archiveTable.blockSignals(True)
239262
profile = self.profile()
240263
if profile.repo is not None:
241-
242264
if profile.repo.name:
243265
repo_name = f"{profile.repo.name} ({profile.repo.url})"
244266
else:
245267
repo_name = profile.repo.url
246268
self.toolBox.setItemText(0, self.tr('Archives for {}').format(repo_name))
247269

248-
populateArchiveTableWorker = PopulateArchiveTableAsync(profile, self.mount_points, self.archiveTable)
270+
populateArchiveTableWorker = MountPointsWorker(profile.repo.url)
249271
self.workers.append(populateArchiveTableWorker) # preserve worker reference
272+
populateArchiveTableWorker.signal.connect(self.set_mount_points)
250273
populateArchiveTableWorker.start()
274+
self.archiveTable.hideColumn(3)
275+
276+
archives = [s for s in profile.repo.archives.select().order_by(ArchiveModel.time.desc())]
277+
278+
sorting = self.archiveTable.isSortingEnabled()
279+
self.archiveTable.setSortingEnabled(False)
280+
best_unit = find_best_unit_for_sizes((a.size for a in archives), precision=SIZE_DECIMAL_DIGITS)
281+
for row, archive in enumerate(archives):
282+
self.archiveTable.insertRow(row)
283+
284+
formatted_time = archive.time.strftime('%Y-%m-%d %H:%M')
285+
self.archiveTable.setItem(row, 0, QTableWidgetItem(formatted_time))
251286

252-
if self.remaining_refresh_archives == 0:
253-
self._toggle_all_buttons(enabled=True)
287+
# format units based on user settings for 'dynamic' or 'fixed' units
288+
fixed_unit = best_unit if SettingsModel.get(key='enable_fixed_units').value else None
289+
size = pretty_bytes(archive.size, fixed_unit=fixed_unit, precision=SIZE_DECIMAL_DIGITS)
290+
self.archiveTable.setItem(row, 1, SizeItem(size))
291+
292+
if archive.duration is not None:
293+
formatted_duration = str(timedelta(seconds=round(archive.duration)))
294+
else:
295+
formatted_duration = ''
296+
297+
self.archiveTable.setItem(row, 2, QTableWidgetItem(formatted_duration))
298+
self.archiveTable.setItem(row, 4, QTableWidgetItem(archive.name))
299+
300+
if archive.trigger == 'scheduled':
301+
item = QTableWidgetItem(get_colored_icon('clock-o'), '')
302+
item.setToolTip(self.tr('Scheduled'))
303+
self.archiveTable.setItem(row, 5, item)
304+
elif archive.trigger == 'user':
305+
item = QTableWidgetItem(get_colored_icon('user'), '')
306+
item.setToolTip(self.tr('User initiated'))
307+
item.setTextAlignment(Qt.AlignmentFlag.AlignRight)
308+
self.archiveTable.setItem(row, 5, item)
309+
310+
self.archiveTable.setRowCount(len(archives))
311+
self.archiveTable.setSortingEnabled(sorting)
312+
item = self.archiveTable.item(0, 0)
313+
self.archiveTable.scrollToItem(item)
314+
315+
self.archiveTable.selectionModel().clearSelection()
316+
317+
if self.remaining_refresh_archives == 0:
318+
self._toggle_all_buttons(enabled=True)
254319
else:
255320
self.mount_points = {}
256321
self.archiveTable.setRowCount(0)
@@ -261,13 +326,14 @@ def populate_from_profile(self):
261326
self.prunePrefixTemplate.setText(profile.prune_prefix)
262327

263328
# Populate pruning options from database
264-
profile = self.profile()
265329
for i in self.prune_intervals:
266330
getattr(self, f'prune_{i}').setValue(getattr(profile, f'prune_{i}'))
267331
getattr(self, f'prune_{i}').valueChanged.connect(self.save_prune_setting)
268332
self.prune_keep_within.setText(profile.prune_keep_within)
269333
self.prune_keep_within.editingFinished.connect(self.save_prune_setting)
270334

335+
self.archiveTable.blockSignals(False)
336+
271337
def on_selection_change(self, selected=None, deselected=None):
272338
"""
273339
React to a change of the selection of the archiveTableView.

src/vorta/views/main_window.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,11 @@ def profile_selection_changed_action(self, index):
183183
logger.info('step 1')
184184
self.archiveTab.populate_from_profile()
185185
logger.info('step 2')
186-
self.repoTab.populate_from_profile() # 1s
186+
self.repoTab.populate_from_profile()
187187
logger.info('step 3')
188188
self.sourceTab.populate_from_profile()
189189
logger.info('step 4')
190-
self.scheduleTab.populate_from_profile() #1s
190+
self.scheduleTab.populate_from_profile()
191191
logger.info('step 5')
192192
SettingsModel.update({SettingsModel.str_value: self.current_profile.id}).where(
193193
SettingsModel.key == 'previous_profile_id'

src/vorta/views/schedule_tab.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from vorta.scheduler import ScheduleStatusType
1414
from vorta.store.models import BackupProfileMixin, EventLogModel, WifiSettingModel
1515
from vorta.utils import get_asset
16-
from vorta.views.workers.wifi_list_worker import PopulateWifiAsync
16+
from vorta.views.workers.wifi_list_worker import WifiListWorker
1717
from vorta.views.utils import get_colored_icon
1818

1919
uifile = get_asset('UI/scheduletab.ui')
@@ -173,12 +173,27 @@ def populate_from_profile(self):
173173
else:
174174
self.createCmdLineEdit.setEnabled(False)
175175

176-
populateWifiWorker = PopulateWifiAsync(profile, self.wifiListWidget)
177-
self.workers.append(populateWifiWorker) # preserve reference
178-
populateWifiWorker.start()
176+
wifiListWorker = WifiListWorker(profile.id)
177+
self.workers.append(wifiListWorker) # preserve reference
178+
wifiListWorker.signal.connect(self.set_wifi_list)
179+
wifiListWorker.start()
180+
179181
self.populate_logs()
180182
self.draw_next_scheduled_backup()
181183

184+
def set_wifi_list(self, wifi_list):
185+
self.wifiListWidget.clear()
186+
for wifi in wifi_list:
187+
item = QListWidgetItem()
188+
item.setText(wifi.ssid)
189+
item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
190+
if wifi.allowed:
191+
item.setCheckState(QtCore.Qt.CheckState.Checked)
192+
else:
193+
item.setCheckState(QtCore.Qt.CheckState.Unchecked)
194+
self.wifiListWidget.addItem(item)
195+
196+
182197
def draw_next_scheduled_backup(self):
183198
status = self.app.scheduler.next_job_for_profile(self.profile().id)
184199
if status.type in (
@@ -195,19 +210,6 @@ def draw_next_scheduled_backup(self):
195210
self.nextBackupDateTimeLabel.setText(text)
196211
self.nextBackupDateTimeLabel.repaint()
197212

198-
# def populate_wifi(self):
199-
# self.wifiListWidget.clear()
200-
# for wifi in get_sorted_wifis(self.profile()):
201-
# item = QListWidgetItem()
202-
# item.setText(wifi.ssid)
203-
# item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsUserCheckable)
204-
# if wifi.allowed:
205-
# item.setCheckState(QtCore.Qt.CheckState.Checked)
206-
# else:
207-
# item.setCheckState(QtCore.Qt.CheckState.Unchecked)
208-
# self.wifiListWidget.addItem(item)
209-
# self.wifiListWidget.itemChanged.connect(self.save_wifi_item)
210-
211213
def save_wifi_item(self, item):
212214
db_item = WifiSettingModel.get(ssid=item.text(), profile=self.profile().id)
213215
db_item.allowed = item.checkState() == Qt.CheckState.Checked

src/vorta/views/workers/archive_table_worker.py

Lines changed: 0 additions & 134 deletions
This file was deleted.

0 commit comments

Comments
 (0)