def __init__(self, parent, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) self._account_page = None self._vpn_page = None self._email_page = None self._add_icons() self._set_account(app.current_account()) self._setup_connections() # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self
def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param account: the user or provider :type account: Account :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) self.account = account self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.close_button.clicked.connect(self.close) self.ui.account_label.setText(account.address) self.app.service_selection_changed.connect(self._update_icons) self._add_icons() self._add_pages() self._update_icons(self.account, self.account.services()) # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self
def __init__(self, parent, srp_auth): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param srp_auth: SRPAuth object configured in the main app. :type srp_auth: SRPAuth """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = LeapSettings() self._soledad = None # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers()
def __init__(self, parent, username, domain, backend, soledad_started, mx, leap_signaler): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param username: the user set in the login widget :type username: unicode :param domain: the selected domain in the login widget :type domain: unicode :param backend: Backend being used :type backend: Backend :param soledad_started: whether soledad has started or not :type soledad_started: bool :param mx: whether the current provider provides mx or not. :type mx: bool """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._username = username self._domain = domain self._leap_signaler = leap_signaler self._backend = backend self._soledad_started = soledad_started self._mx_provided = mx self._settings = LeapSettings() self._backend_connect() # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers() if self._username is None: self._not_logged_in() else: self.ui.gbPasswordChange.setEnabled(True) if self._mx_provided: self._provides_mx() self._select_provider_by_name(domain)
def __init__(self, parent, srp_auth, leap_settings, standalone): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param srp_auth: SRPAuth object configured in the main app. :type srp_auth: SRPAuth :param standalone: If True, the application is running as standalone and the preferences dialog should display some messages according to this. :type standalone: bool """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = leap_settings self._standalone = standalone self._soledad = None # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self.ui.lblProvidersGatewayStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) self.ui.cbProvidersGateway.currentIndexChanged[unicode].connect( self._populate_gateways) self.ui.cbGateways.currentIndexChanged[unicode].connect( lambda x: self.ui.lblProvidersGatewayStatus.setVisible(False)) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers()
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ _current_window = None # currently visible preferences window def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param account: the user or provider :type account: Account :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) self.account = account self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.close_button.clicked.connect(self.close) self.ui.account_label.setText(account.address) self.app.service_selection_changed.connect(self._update_icons) self._add_icons() self._add_pages() self._update_icons(self.account, self.account.services()) # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self def _add_icons(self): """ Adds all the icons for the different configuration categories. Icons are QListWidgetItems added to the nav_widget on the side of the preferences window. A note on sizing of QListWidgetItems icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 icon_height = 56 seems to look ok """ account_item = QtGui.QListWidgetItem(self.ui.nav_widget) account_item.setIcon(QtGui.QIcon(":/images/black/32/user.png")) account_item.setText(self.tr("Account")) account_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) account_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) account_item.setSizeHint(QtCore.QSize(98, 56)) self._account_item = account_item vpn_item = QtGui.QListWidgetItem(self.ui.nav_widget) vpn_item.setHidden(True) vpn_item.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) vpn_item.setText(self.tr("VPN")) vpn_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) vpn_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) vpn_item.setSizeHint(QtCore.QSize(98, 56)) self._vpn_item = vpn_item email_item = QtGui.QListWidgetItem(self.ui.nav_widget) email_item.setHidden(True) email_item.setIcon(QtGui.QIcon(":/images/black/32/email.png")) email_item.setText(self.tr("Email")) email_item.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) email_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) email_item.setSizeHint(QtCore.QSize(98, 56)) self._email_item = email_item self.ui.nav_widget.currentItemChanged.connect(self._change_page) self.ui.nav_widget.setCurrentRow(0) def _add_pages(self): """ Adds the pages for the different configuration categories. """ self._account_page = PreferencesAccountPage(self, self.account, self.app) self._vpn_page = PreferencesVpnPage(self, self.account, self.app) self._email_page = PreferencesEmailPage(self, self.account, self.app) self.ui.pages_widget.addWidget(self._account_page) self.ui.pages_widget.addWidget(self._vpn_page) self.ui.pages_widget.addWidget(self._email_page) # # Slots # def closeEvent(self, e): """ TRIGGERS: self.ui.close_button.clicked (since self.close() will trigger closeEvent) whenever the window is closed Close this dialog and destroy it. """ PreferencesWindow._current_window = None # deleteLater does not seem to cascade to items in stackLayout # (even with QtCore.Qt.WA_DeleteOnClose attribute). # so, here we call deleteLater() explicitly: self._account_page.deleteLater() self._vpn_page.deleteLater() self._email_page.deleteLater() self.deleteLater() def _change_page(self, current, previous): """ TRIGGERS: self.ui.nav_widget.currentItemChanged Changes what page is displayed. :param current: the currently selected item (might be None?) :type current: PySide.QtGui.QListWidgetItem :param previous: the previously selected item (might be None) :type previous: PySide.QtGui.QListWidgetItem """ if not current: current = previous self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) def _update_icons(self, account, services): """ TRIGGERS: self.app.service_selection_changed Change which icons are visible. """ if account != self.account: return if HAS_EIP: self._vpn_item.setHidden(EIP_SERVICE not in services)
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ def __init__(self, parent, srp_auth): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param srp_auth: SRPAuth object configured in the main app. :type srp_auth: SRPAuth """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = LeapSettings() self._soledad = None # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self.ui.lblProvidersGatewayStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) self.ui.cbProvidersGateway.currentIndexChanged[unicode].connect( self._populate_gateways) self.ui.cbGateways.currentIndexChanged[unicode].connect( lambda x: self.ui.lblProvidersGatewayStatus.setVisible(False)) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers() def set_soledad_ready(self, soledad): """ SLOT TRIGGERS: parent.soledad_ready It sets the soledad object as ready to use. :param soledad: Soledad object configured in the main app. :type soledad: Soledad """ self._soledad = soledad self.ui.gbPasswordChange.setEnabled(True) def _set_password_change_status(self, status, error=False, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str """ if error: status = "<font color='red'><b>%s</b></font>" % (status,) elif success: status = "<font color='green'><b>%s</b></font>" % (status,) self.ui.lblPasswordChangeStatus.setVisible(True) self.ui.lblPasswordChangeStatus.setText(status) def _set_changing_password(self, disable): """ Enables or disables the widgets in the password change group box. :param disable: True if the widgets should be disabled and it displays the status label that shows that is changing the password. False if they should be enabled. :type disable: bool """ if disable: self._set_password_change_status(self.tr("Changing password...")) self.ui.leCurrentPassword.setEnabled(not disable) self.ui.leNewPassword.setEnabled(not disable) self.ui.leNewPassword2.setEnabled(not disable) self.ui.pbChangePassword.setEnabled(not disable) def _change_password(self): """ SLOT TRIGGERS: self.ui.pbChangePassword.clicked Changes the user's password if the inputboxes are correctly filled. """ username = self._srp_auth.get_username() current_password = self.ui.leCurrentPassword.text() new_password = self.ui.leNewPassword.text() new_password2 = self.ui.leNewPassword2.text() ok, msg = basic_password_checks(username, new_password, new_password2) if not ok: self._set_changing_password(False) self._set_password_change_status(msg, error=True) self.ui.leNewPassword.setFocus() return self._set_changing_password(True) d = self._srp_auth.change_password(current_password, new_password) d.addCallback(partial(self._change_password_success, new_password)) d.addErrback(self._change_password_problem) def _change_password_success(self, new_password, _): """ Callback used to display a successfully performed action. :param new_password: the new password for the user. :type new_password: str. :param _: the returned data from self._srp_auth.change_password Ignored """ logger.debug("SRP password changed successfully.") try: self._soledad.change_passphrase(str(new_password)) logger.debug("Soledad password changed successfully.") except NoStorageSecret: logger.debug( "No storage secret for password change in Soledad.") self._set_password_change_status( self.tr("Password changed successfully."), success=True) self._clear_password_inputs() self._set_changing_password(False) def _change_password_problem(self, failure): """ Errback called if there was a problem with the deferred. Also is used to display an error message. :param failure: the cause of the method failed. :type failure: twisted.python.Failure """ logger.error("Error changing password: %s", (failure, )) problem = self.tr("There was a problem changing the password.") if failure.check(SRPAuthBadPassword): problem = self.tr("You did not enter a correct current password.") self._set_password_change_status(problem, error=True) self._set_changing_password(False) failure.trap(Exception) def _clear_password_inputs(self): """ Clear the contents of the inputs. """ self.ui.leCurrentPassword.setText("") self.ui.leNewPassword.setText("") self.ui.leNewPassword2.setText("") def _set_providers_services_status(self, status, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str :param success: is set to True if we should display the message as green :type success: bool """ if success: status = "<font color='green'><b>%s</b></font>" % (status,) self.ui.lblProvidersServicesStatus.setVisible(True) self.ui.lblProvidersServicesStatus.setText(status) def _set_providers_gateway_status(self, status, success=False, error=False): """ Sets the status label for the gateway change. :param status: status message to display, can be HTML :type status: str :param success: is set to True if we should display the message as green :type success: bool :param error: is set to True if we should display the message as red :type error: bool """ if success: status = "<font color='green'><b>%s</b></font>" % (status,) elif error: status = "<font color='red'><b>%s</b></font>" % (status,) self.ui.lblProvidersGatewayStatus.setVisible(True) self.ui.lblProvidersGatewayStatus.setText(status) def _add_configured_providers(self): """ Add the client's configured providers to the providers combo boxes. """ self.ui.cbProvidersServices.clear() self.ui.cbProvidersGateway.clear() for provider in self._settings.get_configured_providers(): self.ui.cbProvidersServices.addItem(provider) self.ui.cbProvidersGateway.addItem(provider) def _service_selection_changed(self, service, state): """ SLOT TRIGGER: service_checkbox.stateChanged Adds the service to the state if the state is checked, removes it otherwise :param service: service to handle :type service: str :param state: state of the checkbox :type state: int """ if state == QtCore.Qt.Checked: self._selected_services = \ self._selected_services.union(set([service])) else: self._selected_services = \ self._selected_services.difference(set([service])) # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) def _populate_services(self, domain): """ SLOT TRIGGERS: self.ui.cbProvidersServices.currentIndexChanged[unicode] Loads the services that the provider provides into the UI for the user to enable or disable. :param domain: the domain of the provider to load services from. :type domain: str """ # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) if not domain: return provider_config = self._get_provider_config(domain) if provider_config is None: return # set the proper connection for the 'save' button try: self.ui.pbSaveServices.clicked.disconnect() except RuntimeError: pass # Signal was not connected save_services = partial(self._save_enabled_services, domain) self.ui.pbSaveServices.clicked.connect(save_services) services = get_supported(provider_config.get_services()) services_conf = self._settings.get_enabled_services(domain) # discard changes if other provider is selected self._selected_services = set() # from: http://stackoverflow.com/a/13103617/687989 # remove existing checkboxes layout = self.ui.vlServices for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) # add one checkbox per service and set the current configured value for service in services: try: checkbox = QtGui.QCheckBox(self) service_label = get_service_display_name(service) checkbox.setText(service_label) self.ui.vlServices.addWidget(checkbox) checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) checkbox.setChecked(service in services_conf) except ValueError: logger.error("Something went wrong while trying to " "load service %s" % (service,)) def _save_enabled_services(self, provider): """ SLOT TRIGGERS: self.ui.pbSaveServices.clicked Saves the new enabled services settings to the configuration file. :param provider: the provider config that we need to save. :type provider: str """ services = list(self._selected_services) self._settings.set_enabled_services(provider, services) msg = self.tr( "Services settings for provider '{0}' saved.".format(provider)) logger.debug(msg) self._set_providers_services_status(msg, success=True) def _get_provider_config(self, domain): """ Helper to return a valid Provider Config from the domain name. :param domain: the domain name of the provider. :type domain: str :rtype: ProviderConfig or None if there is a problem loading the config """ provider_config = ProviderConfig() provider_config_path = os.path.join( "leap", "providers", domain, "provider.json") if not provider_config.load(provider_config_path): provider_config = None return provider_config def _save_selected_gateway(self, provider): """ SLOT TRIGGERS: self.ui.pbSaveGateway.clicked Saves the new gateway setting to the configuration file. :param provider: the provider config that we need to save. :type provider: str """ gateway = self.ui.cbGateways.currentText() if gateway == self.AUTOMATIC_GATEWAY_LABEL: gateway = self._settings.GATEWAY_AUTOMATIC else: idx = self.ui.cbGateways.currentIndex() gateway = self.ui.cbGateways.itemData(idx) self._settings.set_selected_gateway(provider, gateway) msg = self.tr( "Gateway settings for provider '{0}' saved.".format(provider)) logger.debug(msg) self._set_providers_gateway_status(msg, success=True) def _populate_gateways(self, domain): """ SLOT TRIGGERS: self.ui.cbProvidersGateway.currentIndexChanged[unicode] Loads the gateways that the provider provides into the UI for the user to select. :param domain: the domain of the provider to load gateways from. :type domain: str """ # We hide the maybe-visible status label after a change self.ui.lblProvidersGatewayStatus.setVisible(False) if not domain: return try: # disconnect prevoiusly connected save method self.ui.pbSaveGateway.clicked.disconnect() except RuntimeError: pass # Signal was not connected # set the proper connection for the 'save' button save_gateway = partial(self._save_selected_gateway, domain) self.ui.pbSaveGateway.clicked.connect(save_gateway) eip_config = EIPConfig() provider_config = self._get_provider_config(domain) eip_config_path = os.path.join("leap", "providers", domain, "eip-service.json") api_version = provider_config.get_api_version() eip_config.set_api_version(api_version) eip_loaded = eip_config.load(eip_config_path) if not eip_loaded or provider_config is None: self._set_providers_gateway_status( self.tr("There was a problem with configuration files."), error=True) return gateways = VPNGatewaySelector(eip_config).get_gateways_list() logger.debug(gateways) self.ui.cbGateways.clear() self.ui.cbGateways.addItem(self.AUTOMATIC_GATEWAY_LABEL) # Add the available gateways and # select the one stored in configuration file. selected_gateway = self._settings.get_selected_gateway(domain) index = 0 for idx, (gw_name, gw_ip) in enumerate(gateways): gateway = "{0} ({1})".format(gw_name, gw_ip) self.ui.cbGateways.addItem(gateway, gw_ip) if gw_ip == selected_gateway: index = idx + 1 self.ui.cbGateways.setCurrentIndex(index)
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ preferences_saved = QtCore.Signal() def __init__(self, parent, username, domain, backend, soledad_started, mx, leap_signaler): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param username: the user set in the login widget :type username: unicode :param domain: the selected domain in the login widget :type domain: unicode :param backend: Backend being used :type backend: Backend :param soledad_started: whether soledad has started or not :type soledad_started: bool :param mx: whether the current provider provides mx or not. :type mx: bool """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._username = username self._domain = domain self._leap_signaler = leap_signaler self._backend = backend self._soledad_started = soledad_started self._mx_provided = mx self._settings = LeapSettings() self._backend_connect() # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers() if self._username is None: self._not_logged_in() else: self.ui.gbPasswordChange.setEnabled(True) if self._mx_provided: self._provides_mx() self._select_provider_by_name(domain) def _not_logged_in(self): """ Actions to perform if the user is not logged in. """ msg = self.tr( "In order to change your password you need to be logged in.") self._set_password_change_status(msg) self.ui.gbPasswordChange.setEnabled(False) def _provides_mx(self): """ Actions to perform if the provider provides MX. """ pw_enabled = True enabled_services = self._settings.get_enabled_services(self._domain) mx_name = get_service_display_name(MX_SERVICE) if MX_SERVICE not in enabled_services: msg = self.tr("You need to enable {0} in order to change " "the password.".format(mx_name)) self._set_password_change_status(msg, error=True) pw_enabled = False else: # check if Soledad is bootstrapped if not self._soledad_started: msg = self.tr( "You need to wait until {0} is ready in " "order to change the password.".format(mx_name)) self._set_password_change_status(msg) pw_enabled = False self.ui.gbPasswordChange.setEnabled(pw_enabled) @QtCore.Slot() def set_soledad_ready(self): """ TRIGGERS: parent.soledad_ready It notifies when the soledad object as ready to use. """ self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.gbPasswordChange.setEnabled(True) def _set_password_change_status(self, status, error=False, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str """ if error: status = "<font color='red'><b>%s</b></font>" % (status,) elif success: status = "<font color='green'><b>%s</b></font>" % (status,) if not self.ui.gbPasswordChange.isEnabled(): status = "<font color='black'>%s</font>" % (status,) self.ui.lblPasswordChangeStatus.setVisible(True) self.ui.lblPasswordChangeStatus.setText(status) def _set_changing_password(self, disable): """ Enables or disables the widgets in the password change group box. :param disable: True if the widgets should be disabled and it displays the status label that shows that is changing the password. False if they should be enabled. :type disable: bool """ if disable: self._set_password_change_status(self.tr("Changing password...")) self.ui.leCurrentPassword.setEnabled(not disable) self.ui.leNewPassword.setEnabled(not disable) self.ui.leNewPassword2.setEnabled(not disable) self.ui.pbChangePassword.setEnabled(not disable) @QtCore.Slot() def _change_password(self): """ TRIGGERS: self.ui.pbChangePassword.clicked Changes the user's password if the inputboxes are correctly filled. """ username = self._username current_password = self.ui.leCurrentPassword.text() new_password = self.ui.leNewPassword.text() new_password2 = self.ui.leNewPassword2.text() ok, msg = password_checks(username, new_password, new_password2) if not ok: self._set_changing_password(False) self._set_password_change_status(msg, error=True) self.ui.leNewPassword.setFocus() return self._set_changing_password(True) self._backend.user_change_password(current_password=current_password, new_password=new_password) @QtCore.Slot() def _srp_change_password_ok(self): """ TRIGGERS: self._backend.signaler.srp_password_change_ok Callback used to display a successfully changed password. """ new_password = self.ui.leNewPassword.text() logger.debug("SRP password changed successfully.") if self._mx_provided: self._backend.soledad_change_password(new_password=new_password) else: self._change_password_success() @QtCore.Slot(unicode) def _srp_change_password_problem(self, msg): """ TRIGGERS: self._backend.signaler.srp_password_change_error self._backend.signaler.srp_password_change_badpw Callback used to display an error on changing password. :param msg: the message to show to the user. :type msg: unicode """ logger.error("Error changing password") self._set_password_change_status(msg, error=True) self._set_changing_password(False) @QtCore.Slot() def _soledad_change_password_ok(self): """ TRIGGERS: Signaler.soledad_password_change_ok Soledad password change went OK. """ logger.debug("Soledad password changed successfully.") self._change_password_success() def _change_password_success(self): """ Callback used to display a successfully changed password. """ logger.debug("Soledad password changed successfully.") self._set_password_change_status( self.tr("Password changed successfully."), success=True) self._clear_password_inputs() self._set_changing_password(False) @QtCore.Slot(unicode) def _soledad_change_password_problem(self, msg): """ TRIGGERS: Signaler.soledad_password_change_error Callback used to display an error on changing password. :param msg: the message to show to the user. :type msg: unicode """ logger.error("Error changing soledad password") self._set_password_change_status(msg, error=True) self._set_changing_password(False) def _clear_password_inputs(self): """ Clear the contents of the inputs. """ self.ui.leCurrentPassword.setText("") self.ui.leNewPassword.setText("") self.ui.leNewPassword2.setText("") def _set_providers_services_status(self, status, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str :param success: is set to True if we should display the message as green :type success: bool """ if success: status = "<font color='green'><b>%s</b></font>" % (status,) self.ui.lblProvidersServicesStatus.setVisible(True) self.ui.lblProvidersServicesStatus.setText(status) def _add_configured_providers(self): """ Add the client's configured providers to the providers combo boxes. """ self.ui.cbProvidersServices.clear() for provider in self._settings.get_configured_providers(): self.ui.cbProvidersServices.addItem(provider) def _select_provider_by_name(self, name): """ Given a provider name/domain, selects it in the combobox. :param name: name or domain for the provider :type name: str """ provider_index = self.ui.cbProvidersServices.findText(name) self.ui.cbProvidersServices.setCurrentIndex(provider_index) @QtCore.Slot(str, int) def _service_selection_changed(self, service, state): """ TRIGGERS: service_checkbox.stateChanged Adds the service to the state if the state is checked, removes it otherwise :param service: service to handle :type service: str :param state: state of the checkbox :type state: int """ if state == QtCore.Qt.Checked: self._selected_services = \ self._selected_services.union(set([service])) else: self._selected_services = \ self._selected_services.difference(set([service])) # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) @QtCore.Slot(str) def _populate_services(self, domain): """ TRIGGERS: self.ui.cbProvidersServices.currentIndexChanged[unicode] Fill the services list with the selected provider's services. :param domain: the domain of the provider to load services from. :type domain: str """ # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) if not domain: return # set the proper connection for the 'save' button try: self.ui.pbSaveServices.clicked.disconnect() except RuntimeError: pass # Signal was not connected save_services = partial(self._save_enabled_services, domain) self.ui.pbSaveServices.clicked.connect(save_services) self._backend.provider_get_supported_services(domain=domain) @QtCore.Slot(str) def _load_services(self, services): """ TRIGGERS: self.ui.cbProvidersServices.currentIndexChanged[unicode] Loads the services that the provider provides into the UI for the user to enable or disable. :param domain: the domain of the provider to load services from. :type domain: str """ domain = self.ui.cbProvidersServices.currentText() services_conf = self._settings.get_enabled_services(domain) # discard changes if other provider is selected self._selected_services = set() # from: http://stackoverflow.com/a/13103617/687989 # remove existing checkboxes layout = self.ui.vlServices for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) # add one checkbox per service and set the current configured value for service in services: try: checkbox = QtGui.QCheckBox(self) service_label = get_service_display_name(service) checkbox.setText(service_label) self.ui.vlServices.addWidget(checkbox) checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) checkbox.setChecked(service in services_conf) except ValueError: logger.error("Something went wrong while trying to " "load service %s" % (service,)) @QtCore.Slot(str) def _save_enabled_services(self, provider): """ TRIGGERS: self.ui.pbSaveServices.clicked Saves the new enabled services settings to the configuration file. :param provider: the provider config that we need to save. :type provider: str """ services = list(self._selected_services) self._settings.set_enabled_services(provider, services) msg = self.tr( "Services settings for provider '{0}' saved.".format(provider)) logger.debug(msg) self._set_providers_services_status(msg, success=True) self.preferences_saved.emit() def _backend_connect(self): """ Helper to connect to backend signals """ sig = self._leap_signaler sig.prov_get_supported_services.connect(self._load_services) sig.srp_password_change_ok.connect(self._srp_change_password_ok) pwd_change_error = lambda: self._srp_change_password_problem( self.tr("There was a problem changing the password.")) sig.srp_password_change_error.connect(pwd_change_error) pwd_change_badpw = lambda: self._srp_change_password_problem( self.tr("You did not enter a correct current password.")) sig.srp_password_change_badpw.connect(pwd_change_badpw) sig.soledad_password_change_ok.connect( self._soledad_change_password_ok) sig.soledad_password_change_error.connect( self._soledad_change_password_problem)
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ _current_window = None # currently visible preferences window def __init__(self, parent, account, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param account: the user or provider :type account: Account :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) self.account = account self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.close_button.clicked.connect(self.close) self.ui.account_label.setText(account.address) self.app.service_selection_changed.connect(self._update_icons) self._add_icons() self._add_pages() self._update_icons(self.account, self.account.services()) # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self def _add_icons(self): """ Adds all the icons for the different configuration categories. Icons are QListWidgetItems added to the nav_widget on the side of the preferences window. A note on sizing of QListWidgetItems icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 icon_height = 56 seems to look ok """ account_item = QtGui.QListWidgetItem(self.ui.nav_widget) account_item.setIcon(QtGui.QIcon(":/images/black/32/user.png")) account_item.setText(self.tr("Account")) account_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) account_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) account_item.setSizeHint(QtCore.QSize(98, 56)) self._account_item = account_item vpn_item = QtGui.QListWidgetItem(self.ui.nav_widget) vpn_item.setHidden(True) vpn_item.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) vpn_item.setText(self.tr("VPN")) vpn_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) vpn_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) vpn_item.setSizeHint(QtCore.QSize(98, 56)) self._vpn_item = vpn_item email_item = QtGui.QListWidgetItem(self.ui.nav_widget) email_item.setHidden(True) email_item.setIcon(QtGui.QIcon(":/images/black/32/email.png")) email_item.setText(self.tr("Email")) email_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) email_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) email_item.setSizeHint(QtCore.QSize(98, 56)) self._email_item = email_item self.ui.nav_widget.currentItemChanged.connect(self._change_page) self.ui.nav_widget.setCurrentRow(0) def _add_pages(self): """ Adds the pages for the different configuration categories. """ self._account_page = PreferencesAccountPage( self, self.account, self.app) self._vpn_page = PreferencesVpnPage(self, self.account, self.app) self._email_page = PreferencesEmailPage(self, self.account, self.app) self.ui.pages_widget.addWidget(self._account_page) self.ui.pages_widget.addWidget(self._vpn_page) self.ui.pages_widget.addWidget(self._email_page) # # Slots # def closeEvent(self, e): """ TRIGGERS: self.ui.close_button.clicked (since self.close() will trigger closeEvent) whenever the window is closed Close this dialog and destroy it. """ PreferencesWindow._current_window = None # deleteLater does not seem to cascade to items in stackLayout # (even with QtCore.Qt.WA_DeleteOnClose attribute). # so, here we call deleteLater() explicitly: self._account_page.deleteLater() self._vpn_page.deleteLater() self._email_page.deleteLater() self.deleteLater() def _change_page(self, current, previous): """ TRIGGERS: self.ui.nav_widget.currentItemChanged Changes what page is displayed. :param current: the currently selected item (might be None?) :type current: PySide.QtGui.QListWidgetItem :param previous: the previously selected item (might be None) :type previous: PySide.QtGui.QListWidgetItem """ if not current: current = previous self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) def _update_icons(self, account, services): """ TRIGGERS: self.app.service_selection_changed Change which icons are visible. """ if account != self.account: return if HAS_EIP: self._vpn_item.setHidden(EIP_SERVICE not in services)
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ _current_window = None # currently visible preferences window _panels = { "account": 0, "vpn": 1, "email": 2 } def __init__(self, parent, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) self._account_page = None self._vpn_page = None self._email_page = None self._add_icons() self._set_account(app.current_account()) self._setup_connections() # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self def _set_account(self, account): """ Initially sets, or resets, the currently viewed account. The account might not represent an authenticated user, but just a domain. """ self.ui.account_label.setText(account.address) self._add_pages(account) self._update_icons(account) self.ui.pages_widget.setCurrentIndex(0) self.ui.nav_widget.setCurrentRow(0) def _add_icons(self): """ Adds all the icons for the different configuration categories. Icons are QListWidgetItems added to the nav_widget on the side of the preferences window. A note on sizing of QListWidgetItems icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 icon_height = 56 seems to look ok """ account_item = QtGui.QListWidgetItem(self.ui.nav_widget) account_item.setIcon(QtGui.QIcon(":/images/black/32/user.png")) account_item.setText(self.tr("Account")) account_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) account_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) account_item.setSizeHint(QtCore.QSize(98, 56)) self._account_item = account_item vpn_item = QtGui.QListWidgetItem(self.ui.nav_widget) vpn_item.setHidden(True) vpn_item.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) vpn_item.setText(self.tr("VPN")) vpn_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) vpn_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) vpn_item.setSizeHint(QtCore.QSize(98, 56)) self._vpn_item = vpn_item email_item = QtGui.QListWidgetItem(self.ui.nav_widget) email_item.setHidden(True) email_item.setIcon(QtGui.QIcon(":/images/black/32/email.png")) email_item.setText(self.tr("Email")) email_item.setTextAlignment( QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) email_item.setFlags( QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) email_item.setSizeHint(QtCore.QSize(98, 56)) self._email_item = email_item def _add_pages(self, account): """ Adds the pages for the different configuration categories. """ self._remove_pages() # in case different account was loaded. # load placeholder widgets if the page should not be loaded. # the order of the pages is important, and must match the order # of the nav_widget icons. self._account_page = PreferencesAccountPage(self, account, self.app) if account.has_eip(): self._vpn_page = PreferencesVpnPage(self, account, self.app) else: self._vpn_page = PreferencesPage(self) if account.has_email(): self._email_page = PreferencesEmailPage(self, account, self.app) else: self._email_page = PreferencesPage(self) self.ui.pages_widget.addWidget(self._account_page) self.ui.pages_widget.addWidget(self._vpn_page) self.ui.pages_widget.addWidget(self._email_page) def _remove_pages(self): # deleteLater does not seem to cascade to items in stackLayout # (even with QtCore.Qt.WA_DeleteOnClose attribute). # so, here we call deleteLater() explicitly. if self._account_page is not None: self.ui.pages_widget.removeWidget(self._account_page) self._account_page.teardown_connections() self._account_page.deleteLater() if self._vpn_page is not None: self.ui.pages_widget.removeWidget(self._vpn_page) self._vpn_page.teardown_connections() self._vpn_page.deleteLater() if self._email_page is not None: self.ui.pages_widget.removeWidget(self._email_page) self._email_page.teardown_connections() self._email_page.deleteLater() def _setup_connections(self): """ setup signal connections """ self.ui.nav_widget.currentItemChanged.connect(self._change_page) self.ui.close_button.clicked.connect(self.close) self.app.service_selection_changed.connect(self._update_icons) sig = self.app.signaler sig.srp_auth_ok.connect(self._login_status_changed) sig.srp_logout_ok.connect(self._login_status_changed) sig.srp_status_logged_in.connect(self._update_account) sig.srp_status_not_logged_in.connect(self._update_account) def _teardown_connections(self): """ clean up signal connections """ self.ui.nav_widget.currentItemChanged.disconnect(self._change_page) self.ui.close_button.clicked.disconnect(self.close) self.app.service_selection_changed.disconnect(self._update_icons) sig = self.app.signaler sig.srp_auth_ok.disconnect(self._login_status_changed) sig.srp_logout_ok.disconnect(self._login_status_changed) sig.srp_status_logged_in.disconnect(self._update_account) sig.srp_status_not_logged_in.disconnect(self._update_account) # # Slots # def closeEvent(self, e): """ TRIGGERS: self.ui.close_button.clicked (since self.close() will trigger closeEvent) whenever the window is closed Close this dialog and destroy it. """ PreferencesWindow._current_window = None self._teardown_connections() self._remove_pages() self.deleteLater() def _change_page(self, current, previous): """ TRIGGERS: self.ui.nav_widget.currentItemChanged Changes what page is displayed. :param current: the currently selected item (might be None?) :type current: PySide.QtGui.QListWidgetItem :param previous: the previously selected item (might be None) :type previous: PySide.QtGui.QListWidgetItem """ if not current: current = previous self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) def _update_icons(self, account): """ TRIGGERS: self.app.service_selection_changed Change which icons are visible. """ self._vpn_item.setHidden(not account.has_eip()) self._email_item.setHidden(not account.has_email()) def _login_status_changed(self): """ Triggered by signal srp_auth_ok, srp_logout_ok """ self.app.backend.user_get_logged_in_status() def _update_account(self): """ Triggered by get srp_status_logged_in, srp_status_not_logged_in """ self._set_account(self.app.current_account()) def set_page(self, page): """ Jump to a particular page """ index = PreferencesWindow._panels[page] self.ui.nav_widget.setCurrentRow(index) self.ui.pages_widget.setCurrentIndex(index)
def __init__(self, parent, srp_auth, provider_config, soledad, domain): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param srp_auth: SRPAuth object configured in the main app. :type srp_auth: SRPAuth :param provider_config: ProviderConfig object. :type provider_config: ProviderConfig :param soledad: Soledad instance :type soledad: Soledad :param domain: the selected domain in the login widget :type domain: unicode """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = LeapSettings() self._soledad = soledad # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers() pw_enabled = False # check if the user is logged in if srp_auth is not None and srp_auth.get_token() is not None: # check if provider has 'mx' ... if provider_config.provides_mx(): enabled_services = self._settings.get_enabled_services(domain) mx_name = get_service_display_name(MX_SERVICE) # ... and if the user have it enabled if MX_SERVICE not in enabled_services: msg = self.tr("You need to enable {0} in order to change " "the password.".format(mx_name)) self._set_password_change_status(msg, error=True) else: if sameProxiedObjects(self._soledad, None): msg = self.tr( "You need to wait until {0} is ready in " "order to change the password.".format(mx_name)) self._set_password_change_status(msg) else: # Soledad is bootstrapped pw_enabled = True else: pw_enabled = True else: msg = self.tr( "In order to change your password you need to be logged in.") self._set_password_change_status(msg) self._select_provider_by_name(domain) self.ui.gbPasswordChange.setEnabled(pw_enabled)
class PreferencesWindow(QtGui.QDialog): """ Window that displays the preferences. """ def __init__(self, parent, srp_auth, provider_config, soledad, domain): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget :param srp_auth: SRPAuth object configured in the main app. :type srp_auth: SRPAuth :param provider_config: ProviderConfig object. :type provider_config: ProviderConfig :param soledad: Soledad instance :type soledad: Soledad :param domain: the selected domain in the login widget :type domain: unicode """ QtGui.QDialog.__init__(self, parent) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") self._srp_auth = srp_auth self._settings = LeapSettings() self._soledad = soledad # Load UI self.ui = Ui_Preferences() self.ui.setupUi(self) self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.lblProvidersServicesStatus.setVisible(False) self._selected_services = set() # Connections self.ui.pbChangePassword.clicked.connect(self._change_password) self.ui.cbProvidersServices.currentIndexChanged[unicode].connect( self._populate_services) if not self._settings.get_configured_providers(): self.ui.gbEnabledServices.setEnabled(False) else: self._add_configured_providers() pw_enabled = False # check if the user is logged in if srp_auth is not None and srp_auth.get_token() is not None: # check if provider has 'mx' ... if provider_config.provides_mx(): enabled_services = self._settings.get_enabled_services(domain) mx_name = get_service_display_name(MX_SERVICE) # ... and if the user have it enabled if MX_SERVICE not in enabled_services: msg = self.tr("You need to enable {0} in order to change " "the password.".format(mx_name)) self._set_password_change_status(msg, error=True) else: if sameProxiedObjects(self._soledad, None): msg = self.tr( "You need to wait until {0} is ready in " "order to change the password.".format(mx_name)) self._set_password_change_status(msg) else: # Soledad is bootstrapped pw_enabled = True else: pw_enabled = True else: msg = self.tr( "In order to change your password you need to be logged in.") self._set_password_change_status(msg) self._select_provider_by_name(domain) self.ui.gbPasswordChange.setEnabled(pw_enabled) def set_soledad_ready(self): """ SLOT TRIGGERS: parent.soledad_ready It notifies when the soledad object as ready to use. """ self.ui.lblPasswordChangeStatus.setVisible(False) self.ui.gbPasswordChange.setEnabled(True) def _set_password_change_status(self, status, error=False, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str """ if error: status = "<font color='red'><b>%s</b></font>" % (status,) elif success: status = "<font color='green'><b>%s</b></font>" % (status,) if not self.ui.gbPasswordChange.isEnabled(): status = "<font color='black'>%s</font>" % (status,) self.ui.lblPasswordChangeStatus.setVisible(True) self.ui.lblPasswordChangeStatus.setText(status) def _set_changing_password(self, disable): """ Enables or disables the widgets in the password change group box. :param disable: True if the widgets should be disabled and it displays the status label that shows that is changing the password. False if they should be enabled. :type disable: bool """ if disable: self._set_password_change_status(self.tr("Changing password...")) self.ui.leCurrentPassword.setEnabled(not disable) self.ui.leNewPassword.setEnabled(not disable) self.ui.leNewPassword2.setEnabled(not disable) self.ui.pbChangePassword.setEnabled(not disable) def _change_password(self): """ SLOT TRIGGERS: self.ui.pbChangePassword.clicked Changes the user's password if the inputboxes are correctly filled. """ username = self._srp_auth.get_username() current_password = self.ui.leCurrentPassword.text() new_password = self.ui.leNewPassword.text() new_password2 = self.ui.leNewPassword2.text() ok, msg = basic_password_checks(username, new_password, new_password2) if not ok: self._set_changing_password(False) self._set_password_change_status(msg, error=True) self.ui.leNewPassword.setFocus() return self._set_changing_password(True) d = self._srp_auth.change_password(current_password, new_password) d.addCallback(partial(self._change_password_success, new_password)) d.addErrback(self._change_password_problem) def _change_password_success(self, new_password, _): """ Callback used to display a successfully performed action. :param new_password: the new password for the user. :type new_password: str. :param _: the returned data from self._srp_auth.change_password Ignored """ logger.debug("SRP password changed successfully.") try: self._soledad.change_passphrase(new_password) logger.debug("Soledad password changed successfully.") except NoStorageSecret: logger.debug( "No storage secret for password change in Soledad.") self._set_password_change_status( self.tr("Password changed successfully."), success=True) self._clear_password_inputs() self._set_changing_password(False) def _change_password_problem(self, failure): """ Errback called if there was a problem with the deferred. Also is used to display an error message. :param failure: the cause of the method failed. :type failure: twisted.python.Failure """ logger.error("Error changing password: %s", (failure, )) problem = self.tr("There was a problem changing the password.") if failure.check(SRPAuthBadUserOrPassword): problem = self.tr("You did not enter a correct current password.") self._set_password_change_status(problem, error=True) self._set_changing_password(False) failure.trap(Exception) def _clear_password_inputs(self): """ Clear the contents of the inputs. """ self.ui.leCurrentPassword.setText("") self.ui.leNewPassword.setText("") self.ui.leNewPassword2.setText("") def _set_providers_services_status(self, status, success=False): """ Sets the status label for the password change. :param status: status message to display, can be HTML :type status: str :param success: is set to True if we should display the message as green :type success: bool """ if success: status = "<font color='green'><b>%s</b></font>" % (status,) self.ui.lblProvidersServicesStatus.setVisible(True) self.ui.lblProvidersServicesStatus.setText(status) def _add_configured_providers(self): """ Add the client's configured providers to the providers combo boxes. """ self.ui.cbProvidersServices.clear() for provider in self._settings.get_configured_providers(): self.ui.cbProvidersServices.addItem(provider) def _select_provider_by_name(self, name): """ Given a provider name/domain, selects it in the combobox. :param name: name or domain for the provider :type name: str """ provider_index = self.ui.cbProvidersServices.findText(name) self.ui.cbProvidersServices.setCurrentIndex(provider_index) def _service_selection_changed(self, service, state): """ SLOT TRIGGER: service_checkbox.stateChanged Adds the service to the state if the state is checked, removes it otherwise :param service: service to handle :type service: str :param state: state of the checkbox :type state: int """ if state == QtCore.Qt.Checked: self._selected_services = \ self._selected_services.union(set([service])) else: self._selected_services = \ self._selected_services.difference(set([service])) # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) def _populate_services(self, domain): """ SLOT TRIGGERS: self.ui.cbProvidersServices.currentIndexChanged[unicode] Loads the services that the provider provides into the UI for the user to enable or disable. :param domain: the domain of the provider to load services from. :type domain: str """ # We hide the maybe-visible status label after a change self.ui.lblProvidersServicesStatus.setVisible(False) if not domain: return provider_config = self._get_provider_config(domain) if provider_config is None: return # set the proper connection for the 'save' button try: self.ui.pbSaveServices.clicked.disconnect() except RuntimeError: pass # Signal was not connected save_services = partial(self._save_enabled_services, domain) self.ui.pbSaveServices.clicked.connect(save_services) services = get_supported(provider_config.get_services()) services_conf = self._settings.get_enabled_services(domain) # discard changes if other provider is selected self._selected_services = set() # from: http://stackoverflow.com/a/13103617/687989 # remove existing checkboxes layout = self.ui.vlServices for i in reversed(range(layout.count())): layout.itemAt(i).widget().setParent(None) # add one checkbox per service and set the current configured value for service in services: try: checkbox = QtGui.QCheckBox(self) service_label = get_service_display_name(service) checkbox.setText(service_label) self.ui.vlServices.addWidget(checkbox) checkbox.stateChanged.connect( partial(self._service_selection_changed, service)) checkbox.setChecked(service in services_conf) except ValueError: logger.error("Something went wrong while trying to " "load service %s" % (service,)) def _save_enabled_services(self, provider): """ SLOT TRIGGERS: self.ui.pbSaveServices.clicked Saves the new enabled services settings to the configuration file. :param provider: the provider config that we need to save. :type provider: str """ services = list(self._selected_services) self._settings.set_enabled_services(provider, services) msg = self.tr( "Services settings for provider '{0}' saved.".format(provider)) logger.debug(msg) self._set_providers_services_status(msg, success=True) def _get_provider_config(self, domain): """ Helper to return a valid Provider Config from the domain name. :param domain: the domain name of the provider. :type domain: str :rtype: ProviderConfig or None if there is a problem loading the config """ provider_config = ProviderConfig() provider_config_path = os.path.join( "leap", "providers", domain, "provider.json") if not provider_config.load(provider_config_path): provider_config = None return provider_config