def reload_workspace_name(self, workspace_name): self.workspace_name = workspace_name display = workspace_name if not self.timestamped: if not self.is_shared: shared_message = _("TEXT_WORKSPACE_IS_PRIVATE") elif not self.is_owner: shared_message = _("TEXT_WORKSPACE_IS_OWNED_BY_user").format( user=self.owner.short_user_display) elif len(self.others) == 1: (user, ) = self.others shared_message = _("TEXT_WORKSPACE_IS_SHARED_WITH_user" ).format(user=user.short_user_display) else: n = len(self.others) assert n > 1 shared_message = _( "TEXT_WORKSPACE_IS_SHARED_WITH_n_USERS").format(n=n) display += " ({})".format(shared_message) else: display += "-" + _("TEXT_WORKSPACE_IS_TIMESTAMPED_date").format( date=format_datetime(self.workspace_fs.timestamp)) self.label_title.setToolTip(display) if len(display) > 20: display = display[:20] + "..." self.label_title.setText(display)
def _on_claimer_error(self, job): if self.claimer_job is not job: return assert job assert job.is_finished() assert job.status != "ok" # This callback can be called after the creation of a new claimer job in the case # of a restart, due to Qt signals being called later. if job.status == "cancelled": return # Safety net for concurrency issues if self.claimer_job is not job: return self.claimer_job = None msg = "" exc = None if job.status == "invitation-not-found": msg = _("TEXT_CLAIM_DEVICE_INVITATION_NOT_FOUND") elif self.claim_job.status == "backend-not-available": msg = _("TEXT_INVITATION_BACKEND_NOT_AVAILABLE") else: msg = _("TEXT_CLAIM_DEVICE_UNKNOWN_ERROR") if job.exc: exc = job.exc.params.get("origin", None) self.rejected.emit() show_error(self, msg, exception=exc)
def __init__(self, jobs_ctx, greeter): super().__init__() self.setupUi(self) self.jobs_ctx = jobs_ctx self.greeter = greeter self.get_requests_job = None self.create_user_job = None self.widget_info.hide() self.label_waiting.show() self.line_edit_user_full_name.textChanged.connect(self.check_infos) self.line_edit_user_email.textChanged.connect(self.check_infos) self.line_edit_device.textChanged.connect(self.check_infos) # self.combo_profile.addItem(_("TEXT_USER_PROFILE_OUTSIDER"), UserProfile.OUTSIDER) self.combo_profile.addItem(_("TEXT_USER_PROFILE_STANDARD"), UserProfile.STANDARD) self.combo_profile.addItem(_("TEXT_USER_PROFILE_ADMIN"), UserProfile.ADMIN) self.combo_profile.setCurrentIndex(0) self.get_requests_success.connect(self._on_get_requests_success) self.get_requests_error.connect(self._on_get_requests_error) self.create_user_success.connect(self._on_create_user_success) self.create_user_error.connect(self._on_create_user_error) self.button_create_user.clicked.connect(self._on_create_user_clicked) self.get_requests_job = self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "get_requests_success", QtToTrioJob), ThreadSafeQtSignal(self, "get_requests_error", QtToTrioJob), self.greeter.get_claim_requests, )
def _on_connection_state_changed(self, status, status_exc, allow_systray=True): text = None icon = None tooltip = None notif = None disconnected = None self.menu.label_organization_name.hide() self.menu.label_organization_size.clear() if status in (BackendConnStatus.READY, BackendConnStatus.INITIALIZING): if status == BackendConnStatus.READY and self.client.device.is_admin: self._get_organization_stats() tooltip = text = _("TEXT_BACKEND_STATE_CONNECTED") icon = QPixmap(":/icons/images/material/cloud_queue.svg") elif status == BackendConnStatus.LOST: tooltip = text = _("TEXT_BACKEND_STATE_DISCONNECTED") icon = QPixmap(":/icons/images/material/cloud_off.svg") disconnected = True elif status == BackendConnStatus.REFUSED: disconnected = True cause = status_exc.__cause__ if isinstance(cause, HandshakeAPIVersionError): tooltip = _("TEXT_BACKEND_STATE_API_MISMATCH_versions").format( versions=", ".join( [str(v.version) for v in cause.backend_versions])) elif isinstance(cause, HandshakeRevokedDevice): tooltip = _("TEXT_BACKEND_STATE_REVOKED_DEVICE") notif = ("REVOKED", tooltip) self.new_notification.emit(*notif) elif isinstance(cause, HandshakeOrganizationExpired): tooltip = _("TEXT_BACKEND_STATE_ORGANIZATION_EXPIRED") else: tooltip = _("TEXT_BACKEND_STATE_UNKNOWN") text = _("TEXT_BACKEND_STATE_DISCONNECTED") icon = QPixmap(":/icons/images/material/cloud_off.svg") notif = ("WARNING", tooltip) elif status == BackendConnStatus.CRASHED: text = _("TEXT_BACKEND_STATE_DISCONNECTED") tooltip = _("TEXT_BACKEND_STATE_CRASHED_cause").format( cause=str(status_exc.__cause__)) icon = QPixmap(":/icons/images/material/cloud_off.svg") notif = ("ERROR", tooltip) disconnected = True self.menu.set_connection_state(text, tooltip, icon) if notif: self.new_notification.emit(*notif) if allow_systray and disconnected: self.systray_notification.emit( "guardata", _("TEXT_SYSTRAY_BACKEND_DISCONNECT_organization").format( organization=self.client.device.organization_id), 5000, )
def _define_shortcuts(self): self.shortcut_close = QShortcut(QKeySequence(QKeySequence.Close), self) self.shortcut_close.activated.connect( self._shortcut_proxy(self.close_current_tab)) self.shortcut_new_tab = QShortcut(QKeySequence(QKeySequence.AddTab), self) self.shortcut_new_tab.activated.connect( self._shortcut_proxy(self._on_add_instance_clicked)) self.shortcut_settings = QShortcut(QKeySequence(_("Ctrl+K")), self) self.shortcut_settings.activated.connect( self._shortcut_proxy(self._show_settings)) self.shortcut_menu = QShortcut(QKeySequence(_("Alt+E")), self) self.shortcut_menu.activated.connect( self._shortcut_proxy(self._show_menu)) # self.shortcut_help = QShortcut(QKeySequence(QKeySequence.HelpContents), self) # self.shortcut_help.activated.connect(self._shortcut_proxy(self._on_show_doc_clicked)) self.shortcut_quit = QShortcut(QKeySequence(QKeySequence.Quit), self) self.shortcut_quit.activated.connect( self._shortcut_proxy(self.close_app)) self.shortcut_create_org = QShortcut(QKeySequence(QKeySequence.New), self) self.shortcut_create_org.activated.connect( self._shortcut_proxy(self._on_create_org_clicked)) self.shortcut_join_org = QShortcut(QKeySequence(QKeySequence.Open), self) self.shortcut_join_org.activated.connect( self._shortcut_proxy(self._on_join_org_clicked)) shortcut = QShortcut(QKeySequence(QKeySequence.NextChild), self) shortcut.activated.connect(self._shortcut_proxy(self._cycle_tabs(1))) shortcut = QShortcut(QKeySequence(QKeySequence.PreviousChild), self) shortcut.activated.connect(self._shortcut_proxy(self._cycle_tabs(-1)))
def __init__(self, jobs_ctx, greeter, invite_addr, client): super().__init__() self.setupUi(self) self.jobs_ctx = jobs_ctx self.greeter = greeter self.invite_addr = invite_addr self.client = client self.wait_peer_job = None self.wait_peer_success.connect(self._on_wait_peer_success) self.wait_peer_error.connect(self._on_wait_peer_error) self.send_email_success.connect(self._on_send_email_success) self.send_email_error.connect(self._on_send_email_error) self.button_start.clicked.connect(self._on_button_start_clicked) self.button_send_email.clicked.connect( self._on_button_send_email_clicked) # Hide the send email button if the user has no human_handle (hand hence no email) if not self.client.device.human_handle: self.button_send_email.hide() self.label_instructions.setText( _("TEXT_GREET_DEVICE_INSTRUCTIONS_NO_EMAIL")) else: self.label_instructions.setText( _("TEXT_GREET_DEVICE_INSTRUCTIONS_email").format( email=self.client.device.human_handle.email)) self.button_copy_addr.clicked.connect(self._on_copy_addr_clicked)
def user_info(self, val): profiles_txt = { UserProfile.OUTSIDER: _("TEXT_USER_PROFILE_OUTSIDER"), UserProfile.STANDARD: _("TEXT_USER_PROFILE_STANDARD"), UserProfile.ADMIN: _("TEXT_USER_PROFILE_ADMIN"), } self._user_info = val if self.user_info.is_revoked: self.setToolTip(_("TEXT_USER_IS_REVOKED")) self.widget.setStyleSheet("background-color: #DDDDDD;") else: self.setToolTip("") self.widget.setStyleSheet("background-color: #FFFFFF;") if self.user_info.human_handle: self.label_email.setText( ensure_string_size(self.user_info.human_handle.email, 260, self.label_email.font())) self.label_email.setToolTip(self.user_info.human_handle.email) self.label_username.setText( ensure_string_size(self.user_info.short_user_display, 260, self.label_username.font())) self.label_username.setToolTip(self.user_info.short_user_display) self.label_role.setText(profiles_txt[self.user_info.profile])
def _on_rename_error(self, job): if job.exc.params.get("multi"): show_error(self, _("TEXT_FILE_RENAME_MULTIPLE_ERROR"), exception=job.exc) else: show_error(self, _("TEXT_FILE_RENAME_ERROR"), exception=job.exc)
def _on_url_input_finished(return_code, url): if not return_code or url is None: return if url == "": show_error(self, _("TEXT_JOIN_ORG_INVALID_URL")) return action_addr = None try: action_addr = BackendActionAddr.from_url(url.strip()) except ValueError as exc: show_error(self, _("TEXT_INVALID_URL"), exception=exc) return if isinstance(action_addr, BackendOrganizationBootstrapAddr): self._on_bootstrap_org_clicked(action_addr) elif isinstance(action_addr, BackendInvitationAddr): if action_addr.invitation_type == InvitationType.USER: self._on_claim_user_clicked(action_addr) elif action_addr.invitation_type == InvitationType.DEVICE: self._on_claim_device_clicked(action_addr) else: show_error(self, _("TEXT_INVALID_URL")) else: show_error(self, _("TEXT_INVALID_URL"))
def open_files(self): files = self.table_files.selected_files() if len(files) == 1: if not self.open_file(files[0][2]): show_error( self, _("TEXT_FILE_OPEN_ERROR_file").format(file=files[0][2])) else: def _on_open_file_question_finished(return_code, answer): if return_code and answer == _("ACTION_FILE_OPEN_MULTIPLE"): success = True for f in files: success &= self.open_file(f[2]) if not success: show_error(self, _("TEXT_FILE_OPEN_MULTIPLE_ERROR")) ask_question( self, _("TEXT_FILE_OPEN_MULTIPLE_TITLE_count").format( count=len(files)), _("TEXT_FILE_OPEN_MULTIPLE_INSTRUCTIONS_count").format( count=len(files)), [_("ACTION_FILE_OPEN_MULTIPLE"), _("ACTION_CANCEL")], on_finished=_on_open_file_question_finished, )
def _on_open_file_question_finished(return_code, answer): if return_code and answer == _("ACTION_FILE_OPEN_MULTIPLE"): success = True for f in files: success &= self.open_file(f[2]) if not success: show_error(self, _("TEXT_FILE_OPEN_MULTIPLE_ERROR"))
def on_tab_state_changed(self, tab, state): idx = self.tab_center.indexOf(tab) if idx == -1: return if state == "login": if self._get_login_tab_index() != -1: self.tab_center.removeTab(idx) else: self.tab_center.setTabToolTip( idx, _("TEXT_TAB_TITLE_LOG_IN_SCREEN")) self.tab_center.setTabText(idx, _("TEXT_TAB_TITLE_LOG_IN_SCREEN")) self.tab_center.setStyleSheet( "QTabBar::tab {min-width:7em;padding:4px;}") elif state == "logout": self.tab_center.removeTab(idx) idx = self._get_login_tab_index() if idx == -1: self.add_instance() else: tab_widget = self.tab_center.widget(idx) log_widget = None if not tab_widget else tab_widget.get_login_widget( ) if log_widget: log_widget.reload_devices() elif state == "connected": device = tab.current_device tab_name = ( f"{device.organization_id} - {device.short_user_display} - {device.device_display}" ) self.tab_center.setTabToolTip(idx, tab_name) self.tab_center.setTabText(idx, tab_name) if self.tab_center.count() == 1: self.tab_center.setTabsClosable(False) self._toggle_add_tab_button()
def _on_bootstrap_question_finished(return_code, answer): if not return_code: return if answer == _("ACTION_NO_DEVICE_JOIN_ORGANIZATION"): self._on_join_org_clicked() elif answer == _("ACTION_NO_DEVICE_CREATE_ORGANIZATION"): self._on_create_org_clicked()
def add_instance(self, start_arg: Optional[str] = None): action_addr = None if start_arg: try: action_addr = BackendActionAddr.from_url(start_arg) except ValueError as exc: show_error(self, _("TEXT_INVALID_URL"), exception=exc) # Do not open a new logging widget if the organisation is already opened if (action_addr and isinstance(action_addr, BackendOrganizationFileLinkAddr) and self.tab_center.count()): self.go_to_file_link(action_addr) return self.switch_to_login_tab() self.show_top() if action_addr and isinstance(action_addr, BackendOrganizationFileLinkAddr): # Organization is not connected, login is required return elif action_addr: if isinstance(action_addr, BackendOrganizationBootstrapAddr): self._on_bootstrap_org_clicked(action_addr) elif isinstance(action_addr, BackendInvitationAddr): if action_addr.invitation_type == InvitationType.USER: self._on_claim_user_clicked(action_addr) elif action_addr.invitation_type == InvitationType.DEVICE: self._on_claim_device_clicked(action_addr) else: show_error(self, _("TEXT_INVALID_URL")) return
def close_tab(self, index, force=False): def _close_tab(logged): self.tab_center.removeTab(index) if logged: if not tab: return tab.logout() self.reload_login_devices() if self.tab_center.count() == 1: self.tab_center.setTabsClosable(False) self._toggle_add_tab_button() tab = self.tab_center.widget(index) if not force: if tab and tab.is_logged_in: def _on_tab_close_question_finished(return_code, answer): if return_code and answer == _("ACTION_TAB_CLOSE_CONFIRM"): _close_tab(True) ask_question( self, _("TEXT_TAB_CLOSE_TITLE"), _("TEXT_TAB_CLOSE_INSTRUCTIONS_device").format( device= f"{tab.client.device.short_user_display} - {tab.client.device.device_display}" ), [_("ACTION_TAB_CLOSE_CONFIRM"), _("ACTION_CANCEL")], on_finished=_on_tab_close_question_finished, ) elif tab: _close_tab(False) elif tab: _close_tab(tab.is_logged_in)
def goto_file_clicked(self): def _on_file_link_input_finished(return_code, file_link): if not return_code or not file_link: return url = None try: url = BackendOrganizationFileLinkAddr.from_url(file_link) except ValueError as exc: show_error(self, _("TEXT_WORKSPACE_GOTO_FILE_LINK_INVALID_LINK"), exception=exc) return for widget in self._iter_workspace_buttons(): if widget.workspace_fs.workspace_id == url.workspace_id: self.load_workspace(widget.workspace_fs, path=url.path, selected=True) return show_error(self, _("TEXT_WORKSPACE_GOTO_FILE_LINK_WORKSPACE_NOT_FOUND")) get_text_input( self, _("TEXT_WORKSPACE_GOTO_FILE_LINK_TITLE"), _("TEXT_WORKSPACE_GOTO_FILE_LINK_INSTRUCTIONS"), placeholder=_("TEXT_WORKSPACE_GOTO_FILE_LINK_PLACEHOLDER"), default_text="", button_text=_("ACTION_GOTO_FILE_LINK"), on_finished=_on_file_link_input_finished, )
def login_with_password(self, key_file, password): message = None exception = None try: device = load_device_with_password(key_file, password) if guardataApp.is_device_connected( device.organization_addr.organization_id, device.device_id): message = _("TEXT_LOGIN_ERROR_ALREADY_CONNECTED") else: self.start_client(device) except LocalDeviceError as exc: message = _("TEXT_LOGIN_ERROR_AUTHENTICATION_FAILED") exception = exc except (RuntimeError, MountpointConfigurationError, MountpointDriverCrash) as exc: message = _("TEXT_LOGIN_MOUNTPOINT_ERROR") exception = exc except Exception as exc: message = _("TEXT_LOGIN_UNKNOWN_ERROR") exception = exc logger.exception("Unhandled error during login") finally: if message: show_error(self, message, exception=exception) self.login_failed.emit()
def on_client_run_error(self): assert self.running_client_job.is_finished() if self.client: self.client.event_bus.disconnect(ClientEvent.GUI_CONFIG_CHANGED, self.on_client_config_updated) if self.running_client_job.status is not None: if isinstance(self.running_client_job.exc, HandshakeRevokedDevice): show_error( self, _("TEXT_LOGIN_ERROR_DEVICE_REVOKED"), exception=self.running_client_job.exc, ) elif isinstance(self.running_client_job.exc, MountpointWinfspNotAvailable): show_error( self, _("TEXT_LOGIN_ERROR_WINFSP_NOT_AVAILABLE"), exception=self.running_client_job.exc, ) elif isinstance(self.running_client_job.exc, MountpointFuseNotAvailable): show_error( self, _("TEXT_LOGIN_ERROR_FUSE_NOT_AVAILABLE"), exception=self.running_client_job.exc, ) else: logger.exception("Unhandled error", exc_info=self.running_client_job.exc) show_error(self, _("TEXT_LOGIN_UNKNOWN_ERROR"), exception=self.running_client_job.exc) self.running_client_job = None self.logged_out.emit()
def show_context_menu(self, pos): global_pos = self.mapToGlobal(pos) menu = QMenu(self) action = menu.addAction(_("ACTION_USER_INVITE_COPY_ADDR")) action.triggered.connect(self.copy_addr) action = menu.addAction(_("ACTION_USER_INVITE_COPY_EMAIL")) action.triggered.connect(self.copy_email) menu.exec_(global_pos)
def on_create_error(self, job): if job.status == "invalid-name": show_error(self, _("TEXT_WORKSPACE_CREATE_NEW_INVALID_NAME"), exception=job.exc) else: show_error(self, _("TEXT_WORKSPACE_CREATE_NEW_UNKNOWN_ERROR"), exception=job.exc)
def switch_icon(self): icon = self._draw_pixmap(self.source, self.isSelected(), self.is_synced, self.is_confined) self.setIcon(QIcon(icon)) if self.is_confined: self.setToolTip(_("TEXT_FILE_ITEM_IS_CONFINED_TOOLTIP")) elif self.is_synced: self.setToolTip(_("TEXT_FILE_ITEM_IS_SYNCED_TOOLTIP")) else: self.setToolTip(_("TEXT_FILE_ITEM_IS_NOT_SYNCED_TOOLTIP"))
def __init__(self, jobs_ctx, event_bus, config, minimize_on_close: bool = False, **kwargs): super().__init__(**kwargs) self.setupUi(self) self.setMenuBar(None) self.jobs_ctx = jobs_ctx self.event_bus = event_bus self.config = config self.minimize_on_close = minimize_on_close # Explain only once that the app stays in background self.minimize_on_close_notif_already_send = False self.force_close = False self.need_close = False self.event_bus.connect(ClientEvent.GUI_CONFIG_CHANGED, self.on_config_updated) self.setWindowTitle( _("TEXT_GUARDATA_WINDOW_TITLE_version").format( version=GUARDATA_VERSION)) self.foreground_needed.connect(self._on_foreground_needed) self.new_instance_needed.connect(self._on_new_instance_needed) self.tab_center.tabCloseRequested.connect(self.close_tab) self.menu_button = Button() self.menu_button.setCursor(Qt.PointingHandCursor) self.menu_button.setIcon(QIcon(":/icons/images/material/menu.svg")) self.menu_button.setIconSize(QSize(24, 24)) self.menu_button.setText(_("ACTION_MAIN_MENU_SHOW")) self.menu_button.setObjectName("MenuButton") self.menu_button.setProperty("color", QColor(0x00, 0x92, 0xFF)) self.menu_button.setProperty("hover_color", QColor(0x00, 0x70, 0xDD)) self.menu_button.setStyleSheet( "#MenuButton {background: none; border: none; color: #2185d0;}" "#MenuButton:hover {color: #0070DD;}") self.menu_button.apply_style() self.menu_button.clicked.connect(self._show_menu) self.tab_center.setCornerWidget(self.menu_button, Qt.TopRightCorner) self.add_tab_button = Button() self.add_tab_button.setCursor(Qt.PointingHandCursor) self.add_tab_button.setIcon(QIcon(":/icons/images/material/add.svg")) self.add_tab_button.setIconSize(QSize(24, 24)) self.add_tab_button.setProperty("color", QColor(0x00, 0x92, 0xFF)) self.add_tab_button.setProperty("hover_color", QColor(0x00, 0x70, 0xDD)) self.add_tab_button.setStyleSheet("background: none; border: none;") self.add_tab_button.apply_style() self.add_tab_button.clicked.connect(self._on_add_instance_clicked) self.tab_center.setCornerWidget(self.add_tab_button, Qt.TopLeftCorner) self.tab_center.currentChanged.connect(self.on_current_tab_changed) self._define_shortcuts() self.ensurePolished()
def on_rename_error(self, job): if job.status == "invalid-name": show_error(self, _("TEXT_WORKSPACE_RENAME_INVALID_NAME"), exception=job.exc) else: show_error(self, _("TEXT_WORKSPACE_RENAME_UNKNOWN_ERROR"), exception=job.exc)
def get_role_translation(user_role): ROLES_TRANSLATIONS = { WorkspaceRole.READER: _("TEXT_WORKSPACE_ROLE_READER"), WorkspaceRole.CONTRIBUTOR: _("TEXT_WORKSPACE_ROLE_CONTRIBUTOR"), WorkspaceRole.MANAGER: _("TEXT_WORKSPACE_ROLE_MANAGER"), WorkspaceRole.OWNER: _("TEXT_WORKSPACE_ROLE_OWNER"), NOT_SHARED_KEY: _("TEXT_WORKSPACE_ROLE_NOT_SHARED"), } return ROLES_TRANSLATIONS[user_role]
def _on_delete_error(self, job): if not getattr(job.exc, "params", None): return if job.exc.params.get("multi"): show_error(self, _("TEXT_FILE_DELETE_MULTIPLE_ERROR"), exception=job.exc) else: show_error(self, _("TEXT_FILE_DELETE_ERROR"), exception=job.exc)
async def test_delete_dirs(aqtbot, running_backend, logged_gui_with_workspace, monkeypatch, input_patcher): w_f = logged_gui_with_workspace.test_get_files_widget() assert w_f is not None async with aqtbot.wait_signal(w_f.folder_stat_success): pass assert w_f.table_files.rowCount() == 1 await create_directories(logged_gui_with_workspace, aqtbot, monkeypatch, ["Dir1", "Dir2", "Dir3"], input_patcher) assert w_f.table_files.rowCount() == 4 # Delete one directory first await aqtbot.run(w_f.table_files.setRangeSelected, QtWidgets.QTableWidgetSelectionRange(1, 0, 1, 0), True) assert len(w_f.table_files.selected_files()) == 1 input_patcher.patch_question( "guardata.client.gui.files_widget.ask_question", QtWidgets.QDialog.Accepted, _("ACTION_FILE_DELETE"), ) async with aqtbot.wait_signals( [w_f.delete_success, w_f.folder_stat_success]): w_f.table_files.delete_clicked.emit() # Wait until the file widget is refreshed by the timer while w_f.update_timer.isActive(): async with aqtbot.wait_signal(w_f.folder_stat_success, timeout=3000): pass assert w_f.table_files.rowCount() == 3 # Then delete two await aqtbot.run(w_f.table_files.setRangeSelected, QtWidgets.QTableWidgetSelectionRange(1, 0, 2, 0), True) assert len(w_f.table_files.selected_files()) == 2 input_patcher.patch_question( "guardata.client.gui.files_widget.ask_question", QtWidgets.QDialog.Accepted, _("ACTION_FILE_DELETE_MULTIPLE"), ) async with aqtbot.wait_signals( [w_f.delete_success, w_f.folder_stat_success]): w_f.table_files.delete_clicked.emit() # Wait until the file widget is refreshed by the timer while w_f.update_timer.isActive(): async with aqtbot.wait_signal(w_f.folder_stat_success, timeout=3000): pass assert w_f.table_files.rowCount() == 1 for i in range(5): assert w_f.table_files.item( 0, i).data(TYPE_DATA_INDEX) == FileType.ParentWorkspace
def get_filesize(bytesize): SYSTEM = [ (1024**4, _("TEXT_FILE_SIZE_TB")), (1024**3, _("TEXT_FILE_SIZE_GB")), (1024**2, _("TEXT_FILE_SIZE_MB")), (1024**1, _("TEXT_FILE_SIZE_KB")), (1024**0, _("TEXT_FILE_SIZE_B")), ] return size(bytesize, system=SYSTEM)
def _on_invite_error(self, job): assert job.is_finished() assert job.status != "ok" status = job.status if status == "offline": errmsg = _("TEXT_INVITE_DEVICE_INVITE_OFFLINE") else: errmsg = _("TEXT_INVITE_DEVICE_INVITE_ERROR") show_error(self, errmsg, exception=job.exc)
def _on_delete_file_question_finished(return_code, answer): if return_code and (answer == _("ACTION_FILE_DELETE") or answer == _("ACTION_FILE_DELETE_MULTIPLE")): self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "delete_success", QtToTrioJob), ThreadSafeQtSignal(self, "delete_error", QtToTrioJob), _do_delete, workspace_fs=self.workspace_fs, files=[(self.current_directory / f.name, f.type) for f in files], )
def show_window(self, skip_dialogs=False, invitation_link=""): self.show() try: if not self.restoreGeometry(self.config.gui_geometry): self.resize_standard() except TypeError: self.resize_standard() QCoreApplication.processEvents() # Used with the --diagnose option if skip_dialogs: return # At the very first launch if self.config.gui_first_launch: self.event_bus.send( ClientEvent.GUI_CONFIG_CHANGED, gui_first_launch=False, gui_last_version=GUARDATA_VERSION, ) # For each guardata update if self.config.gui_last_version and self.config.gui_last_version != GUARDATA_VERSION: # Acknowledge the changes self.event_bus.send(ClientEvent.GUI_CONFIG_CHANGED, gui_last_version=GUARDATA_VERSION) devices = list_available_devices(self.config.config_dir) if not len(devices) and not invitation_link and platform != "darwin": # Add some refresh of async sleep # ELse should start once the main window is fully painted (catch ready event) self.show_top() def _on_bootstrap_question_finished(return_code, answer): if not return_code: return if answer == _("ACTION_NO_DEVICE_JOIN_ORGANIZATION"): self._on_join_org_clicked() elif answer == _("ACTION_NO_DEVICE_CREATE_ORGANIZATION"): self._on_create_org_clicked() ask_question( self, _("TEXT_KICKSTART_GUARDATA_WHAT_TO_DO_TITLE"), _("TEXT_KICKSTART_GUARDATA_WHAT_TO_DO_INSTRUCTIONS"), [ _("ACTION_NO_DEVICE_CREATE_ORGANIZATION"), _("ACTION_NO_DEVICE_JOIN_ORGANIZATION"), ], on_finished=_on_bootstrap_question_finished, radio_mode=True, )