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 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 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, )
def revoke_user(self, user_info): def _on_revoke_question_finished(return_code, answer): if return_code and answer == _("ACTION_USER_REVOCATION_CONFIRM"): self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "revoke_success", QtToTrioJob), ThreadSafeQtSignal(self, "revoke_error", QtToTrioJob), _do_revoke_user, client=self.client, user_info=user_info, ) ask_question( self, _("TEXT_USER_REVOCATION_TITLE"), _("TEXT_USER_REVOCATION_INSTRUCTIONS_user").format( user=user_info.short_user_display), [_("ACTION_USER_REVOCATION_CONFIRM"), _("ACTION_CANCEL")], on_finished=_on_revoke_question_finished, )
def closeEvent(self, event): def _on_closing_question_finished(return_code, answer): if not return_code or answer != _("ACTION_GUARDATA_QUIT_CONFIRM"): event.ignore() self.force_close = False self.need_close = False else: state = self.saveGeometry() self.event_bus.send(ClientEvent.GUI_CONFIG_CHANGED, gui_geometry=state) self.close_all_tabs() event.accept() QApplication.quit() if self.minimize_on_close and not self.need_close: self.hide() event.ignore() if not self.minimize_on_close_notif_already_send: self.minimize_on_close_notif_already_send = True self.systray_notification.emit( "guardata", _("TEXT_TRAY_GUARDATA_STILL_RUNNING_MESSAGE"), 2000) else: tab = self.tab_center.widget(0) if self.tab_center.count() == 1 and (tab and not tab.is_logged_in): self.force_close = True if self.config.gui_confirmation_before_close and not self.force_close: ask_question( self if self.isVisible() else None, _("TEXT_GUARDATA_QUIT_TITLE"), _("TEXT_GUARDATA_QUIT_INSTRUCTIONS"), [_("ACTION_GUARDATA_QUIT_CONFIRM"), _("ACTION_CANCEL")], on_finished=_on_closing_question_finished, ) event.ignore() else: _on_closing_question_finished( 1, _("ACTION_GUARDATA_QUIT_CONFIRM"))
def cancel_invitation(self, token): def _on_cancel_invitation_question_finished(return_code, answer): if return_code and answer == _( "TEXT_USER_INVITE_CANCEL_INVITE_ACCEPT"): self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "cancel_invitation_success", QtToTrioJob), ThreadSafeQtSignal(self, "cancel_invitation_error", QtToTrioJob), _do_cancel_invitation, client=self.client, token=token, ) ask_question( self, _("TEXT_USER_INVITE_CANCEL_INVITE_QUESTION_TITLE"), _("TEXT_USER_INVITE_CANCEL_INVITE_QUESTION_CONTENT"), [_("TEXT_USER_INVITE_CANCEL_INVITE_ACCEPT"), _("ACTION_NO")], on_finished=_on_cancel_invitation_question_finished, )
def delete_files(self): files = self.table_files.selected_files() 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], ) if len(files) == 1: ask_question( self, _("TEXT_FILE_DELETE_TITLE"), _("TEXT_FILE_DELETE_INSTRUCTIONS_name").format( name=files[0].name), [_("ACTION_FILE_DELETE"), _("ACTION_CANCEL")], on_finished=_on_delete_file_question_finished, ) else: ask_question( self, _("TEXT_FILE_DELETE_MULTIPLE_TITLE_count").format( count=len(files)), _("TEXT_FILE_DELETE_MULTIPLE_INSTRUCTIONS_count").format( count=len(files)), [_("ACTION_FILE_DELETE_MULTIPLE"), _("ACTION_CANCEL")], on_finished=_on_delete_file_question_finished, )
def reencrypt_workspace(self, workspace_id, user_revoked, role_revoked, reencryption_already_in_progress): if workspace_id in self.reencrypting or ( not user_revoked and not role_revoked and not reencryption_already_in_progress): return def _on_workspace_reencryption_question_finished(return_code, answer): if not return_code or answer != _( "ACTION_WORKSPACE_REENCRYPTION_CONFIRM"): return @contextmanager def _handle_fs_errors(): try: yield except FSBackendOfflineError as exc: raise JobResultError(ret=workspace_id, status="offline-backend", origin=exc) except FSWorkspaceNoAccess as exc: raise JobResultError(ret=workspace_id, status="access-error", origin=exc) except FSWorkspaceNotFoundError as exc: raise JobResultError(ret=workspace_id, status="not-found", origin=exc) except FSError as exc: raise JobResultError(ret=workspace_id, status="fs-error", origin=exc) async def _reencrypt(on_progress, workspace_id): with _handle_fs_errors(): if reencryption_already_in_progress: job = await self.client.user_fs.workspace_continue_reencryption( workspace_id) else: job = await self.client.user_fs.workspace_start_reencryption( workspace_id) while True: with _handle_fs_errors(): total, done = await job.do_one_batch() on_progress.emit(workspace_id, total, done) if total == done: break return workspace_id self.reencrypting.add(workspace_id) self.jobs_ctx.submit_job( ThreadSafeQtSignal(self, "workspace_reencryption_success", QtToTrioJob), ThreadSafeQtSignal(self, "workspace_reencryption_error", QtToTrioJob), _reencrypt, on_progress=ThreadSafeQtSignal( self, "workspace_reencryption_progress", EntryID, int, int), workspace_id=workspace_id, ) question = "" if user_revoked: question += "{}\n".format( _("TEXT_WORKSPACE_NEED_REENCRYPTION_BECAUSE_USER_REVOKED")) if role_revoked: question += "{}\n".format( _("TEXT_WORKSPACE_NEED_REENCRYPTION_BECAUSE_USER_REMOVED")) question += _("TEXT_WORKSPACE_NEED_REENCRYPTION_INSTRUCTIONS") ask_question( self, _("TEXT_WORKSPACE_NEED_REENCRYPTION_TITLE"), question, [_("ACTION_WORKSPACE_REENCRYPTION_CONFIRM"), _("ACTION_CANCEL")], on_finished=_on_workspace_reencryption_question_finished, )