summaryrefslogtreecommitdiff
path: root/src/leap/bitmask/gui/preferenceswindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/leap/bitmask/gui/preferenceswindow.py')
-rw-r--r--src/leap/bitmask/gui/preferenceswindow.py505
1 files changed, 122 insertions, 383 deletions
diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py
index 3c9cd5d0..f1252301 100644
--- a/src/leap/bitmask/gui/preferenceswindow.py
+++ b/src/leap/bitmask/gui/preferenceswindow.py
@@ -20,428 +20,167 @@ Preferences window
"""
import logging
-from functools import partial
-
from PySide import QtCore, QtGui
-from leap.bitmask.config.leapsettings import LeapSettings
+from leap.bitmask.services import EIP_SERVICE, MX_SERVICE
+
from leap.bitmask.gui.ui_preferences import Ui_Preferences
-from leap.bitmask.util.credentials import password_checks
-from leap.bitmask.services import get_service_display_name, MX_SERVICE
+from leap.bitmask.gui.preferences_account_page import PreferencesAccountPage
+from leap.bitmask.gui.preferences_vpn_page import PreferencesVpnPage
+from leap.bitmask.gui.preferences_email_page import PreferencesEmailPage
logger = logging.getLogger(__name__)
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):
+ _current_window = None # currently visible preferences window
+
+ def __init__(self, parent, account, app):
"""
: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
+
+ :param account: the user or provider
+ :type account: Account
+
+ :param app: the current App object
+ :type app: App
"""
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()
+ self.account = account
+ self.app = app
- # 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):
+ 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_window()
+ 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:
- parent.soledad_ready
+ self.ui.close_button.clicked
+ (since self.close() will trigger closeEvent)
+ whenever the window is closed
- It notifies when the soledad object as ready to use.
+ Close this dialog and destroy it.
"""
- self.ui.lblPasswordChangeStatus.setVisible(False)
- self.ui.gbPasswordChange.setEnabled(True)
+ PreferencesWindow._current_window = None
- 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)
+ # 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()
@QtCore.Slot()
- def _change_password(self):
+ def _change_page(self, current, previous):
"""
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()
+ self.ui.nav_widget.currentItemChanged
- @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
+ Changes what page is displayed.
- Callback used to display an error on changing password.
+ :param current: the currently selected item (might be None?)
+ :type current: PySide.QtGui.QListWidgetItem
- :param msg: the message to show to the user.
- :type msg: unicode
+ :param previous: the previously selected item (might be None)
+ :type previous: PySide.QtGui.QListWidgetItem
"""
- logger.error("Error changing password")
- self._set_password_change_status(msg, error=True)
- self._set_changing_password(False)
+ if not current:
+ current = previous
+ self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current))
- @QtCore.Slot()
- def _soledad_change_password_ok(self):
+ @QtCore.Slot(object, list)
+ def _update_icons(self, account, services):
"""
TRIGGERS:
- Signaler.soledad_password_change_ok
-
- Soledad password change went OK.
- """
- logger.debug("Soledad password changed successfully.")
- self._change_password_success()
+ self.app.service_selection_changed
- def _change_password_success(self):
+ Change which icons are visible.
"""
- 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:
+ if account != self.account:
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)
+ self._vpn_item.setHidden(not EIP_SERVICE in services)
+ # self._email_item.setHidden(not MX_SERVICE in services)
+ # ^^ disable email for now, there is nothing there yet.