diff options
Diffstat (limited to 'src/leap')
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 38 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferences_account_page.py | 165 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferences_email_page.py | 38 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferences_vpn_page.py | 150 | ||||
-rw-r--r-- | src/leap/bitmask/gui/preferenceswindow.py | 419 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/eippreferences.ui | 102 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/mainwindow.ui | 8 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/preferences.ui | 234 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/preferences_account_page.ui | 95 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/preferences_email_page.ui | 32 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/preferences_vpn_page.ui | 89 | ||||
-rw-r--r-- | src/leap/bitmask/services/eip/eipconfig.py | 43 |
12 files changed, 746 insertions, 667 deletions
diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 916e7c1f..243fe117 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -37,7 +37,6 @@ from leap.bitmask.config import flags from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.advanced_key_management import AdvancedKeyManagement -from leap.bitmask.gui.eip_preferenceswindow import EIPPreferencesWindow from leap.bitmask.gui.eip_status import EIPStatusWidget from leap.bitmask.gui.loggerwindow import LoggerWindow from leap.bitmask.gui.login import LoginWidget @@ -97,6 +96,9 @@ class MainWindow(QtGui.QMainWindow): # We give the services some time to a halt before forcing quit. SERVICES_STOP_TIMEOUT = 3000 # in milliseconds + # Preferences window + preferences = None + def __init__(self, start_hidden=False, backend_pid=None): """ Constructor for the client main window @@ -213,8 +215,6 @@ class MainWindow(QtGui.QMainWindow): self._backend_connect() self.ui.action_preferences.triggered.connect(self._show_preferences) - self.ui.action_eip_preferences.triggered.connect( - self._show_eip_preferences) self.ui.action_about_leap.triggered.connect(self._about) self.ui.action_quit.triggered.connect(self.quit) self.ui.action_wizard.triggered.connect(self._launch_wizard) @@ -247,7 +247,6 @@ class MainWindow(QtGui.QMainWindow): # disable buttons for now, may come back later. # self.ui.btnPreferences.clicked.connect(self._show_preferences) - # self.ui.btnEIPPreferences.clicked.connect(self._show_eip_preferences) self._enabled_services = [] self._ui_mx_visible = True @@ -601,16 +600,13 @@ class MainWindow(QtGui.QMainWindow): """ user = self._logged_user domain = self._providers.get_selected_provider() - mx_provided = False - if self._provider_details is not None: - mx_provided = MX_SERVICE in self._provider_details['services'] - preferences = PreferencesWindow(self, user, domain, self._backend, - self._soledad_started, mx_provided, - self._leap_signaler) - - self.soledad_ready.connect(preferences.set_soledad_ready) - preferences.show() - preferences.preferences_saved.connect(self._update_eip_enabled_status) + if self.preferences is not None: + self.preferences.close() + self.preferences = PreferencesWindow(self, user, domain, + self._backend, + self._soledad_started, + self._leap_signaler) + self.preferences.show() @QtCore.Slot() def _update_eip_enabled_status(self): @@ -718,20 +714,6 @@ class MainWindow(QtGui.QMainWindow): """ self._eip_status.missing_helpers = True - @QtCore.Slot() - def _show_eip_preferences(self): - """ - TRIGGERS: - self.ui.btnEIPPreferences.clicked - self.ui.action_eip_preferences (disabled for now) - - Display the EIP preferences window. - """ - domain = self._providers.get_selected_provider() - pref = EIPPreferencesWindow(self, domain, - self._backend, self._leap_signaler) - pref.show() - # # updates # diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py new file mode 100644 index 00000000..9cc94482 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Widget for "account" preferences +""" +import logging + +from functools import partial + +from PySide import QtCore, QtGui +from ui_preferences_account_page import Ui_PreferencesAccountPage + +logger = logging.getLogger(__name__) + +class PreferencesAccountPage(QtGui.QWidget): + """ + + """ + + def __init__(self, parent): + """ + """ + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_PreferencesAccountPage() + self.ui.setupUi(self) + self.show() + + self._selected_services = set() + #self._leap_signaler.prov_get_supported_services.connect(self._load_services) + + @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) + + @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() diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py new file mode 100644 index 00000000..08ff5463 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Widget for "email" preferences +""" +import logging + +from PySide import QtCore, QtGui +from ui_preferences_email_page import Ui_PreferencesEmailPage + +logger = logging.getLogger(__name__) + +class PreferencesEmailPage(QtGui.QWidget): + """ + + """ + + def __init__(self, parent): + """ + """ + QtGui.QWidget.__init__(self, parent) + self.ui = Ui_PreferencesEmailPage() + self.ui.setupUi(self) + self.show() + diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py new file mode 100644 index 00000000..ba1366e4 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +""" +Widget for "vpn" preferences +""" + +from PySide import QtCore, QtGui +from ui_preferences_vpn_page import Ui_PreferencesVpnPage + +from leap.bitmask.config.leapsettings import LeapSettings + + +class PreferencesVpnPage(QtGui.QWidget): + """ + Page in the preferences window that shows VPN settings + """ + + def __init__(self, parent, domain, backend, leap_signaler): + """ + :param parent: parent object of the EIPPreferencesWindow. + :type parent: QWidget + + :param domain: the selected by default domain. + :type domain: unicode + + :param backend: Backend being used + :type backend: Backend + """ + QtGui.QWidget.__init__(self, parent) + self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") + + self._settings = LeapSettings() + self._leap_signaler = leap_signaler + self._backend = backend + + # Load UI + self.ui = Ui_PreferencesVpnPage() + self.ui.setupUi(self) + self.ui.flash_label.setVisible(False) + + # Connections + self.ui.gateways_list.clicked.connect(self._save_selected_gateway) + + self._domain = domain + self._backend_connect() + self._backend.eip_get_gateways_list(domain=domain) + + def _flash_error(self, message): + """ + Sets string for the flash message. + + :param message: the text to be displayed + :type message: str + """ + message = "<font color='red'><b>%s</b></font>" % (message,) + self.ui.flash_label.setVisible(True) + self.ui.flash_label.setText(message) + + # def _flash_success(self, message): + # """ + # Sets string for the flash message. + # + # :param message: the text to be displayed + # :type message: str + # """ + # message = "<font color='green'><b>%s</b></font>" % (message,) + # self.ui.flash_label.setVisible(True) + # self.ui.flash_label.setText(message) + + @QtCore.Slot(str) + def _save_selected_gateway(self, index): + """ + TRIGGERS: + self.ui.gateways_list.clicked + + Saves the new gateway setting to the configuration file. + + :param index: the current index of the selection. + :type current_item: QModelIndex + """ + item = self.ui.gateways_list.currentItem() + + if item.text() == self.AUTOMATIC_GATEWAY_LABEL: + gateway = self._settings.GATEWAY_AUTOMATIC + else: + gateway = item.data(QtCore.Qt.UserRole) + self._settings.set_selected_gateway(self._domain, gateway) + self._backend.settings_set_selected_gateway(provider=self._domain, + gateway=gateway) + + @QtCore.Slot(list) + def _update_gateways_list(self, gateways): + """ + TRIGGERS: + Signaler.eip_get_gateways_list + + :param gateways: a list of gateways + :type gateways: list of unicode + + Add the available gateways and select the one stored in + configuration file. + """ + self.ui.gateways_list.clear() + self.ui.gateways_list.addItem(self.AUTOMATIC_GATEWAY_LABEL) + + selected_gateway = self._settings.get_selected_gateway( + self._domain) + + index = 0 + for idx, (gw_name, gw_ip, gw_country) in enumerate(gateways): + gateway_text = "{0} ({1})".format(gw_name, gw_ip) + item = QtGui.QListWidgetItem(self.ui.gateways_list) + item.setText(gateway_text) + item.setIcon(QtGui.QIcon( + ":/images/countries/%s.png" % (gw_country.lower(),))) + item.setData(QtCore.Qt.UserRole, gw_ip) + if gw_ip == selected_gateway: + index = idx + 1 + self.ui.gateways_list.setCurrentRow(index) + + @QtCore.Slot() + def _gateways_list_error(self): + """ + TRIGGERS: + Signaler.eip_get_gateways_list_error + + An error has occurred retrieving the gateway list + so we inform the user. + """ + self._flash_error( + self.tr("Error loading configuration file.")) + self.ui.gateways_list.setEnabled(False) + + def _backend_connect(self): + sig = self._leap_signaler + sig.eip_get_gateways_list.connect(self._update_gateways_list) + sig.eip_get_gateways_list_error.connect(self._gateways_list_error) diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 3c9cd5d0..a9c301c4 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -20,13 +20,16 @@ Preferences window """ import logging -from functools import partial - from PySide import QtCore, QtGui from leap.bitmask.config.leapsettings import LeapSettings + from leap.bitmask.gui.ui_preferences import Ui_Preferences -from leap.bitmask.util.credentials import password_checks + +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 + from leap.bitmask.services import get_service_display_name, MX_SERVICE logger = logging.getLogger(__name__) @@ -38,8 +41,7 @@ class PreferencesWindow(QtGui.QDialog): """ preferences_saved = QtCore.Signal() - def __init__(self, parent, username, domain, backend, soledad_started, mx, - leap_signaler): + def __init__(self, parent, username, domain, backend, soledad_started, leap_signaler): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget @@ -51,397 +53,94 @@ class PreferencesWindow(QtGui.QDialog): :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 leap_signaler: signal server + :type leap_signaler: LeapSignaler """ QtGui.QDialog.__init__(self, parent) - self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") + self._parent = parent 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.ui.close_button.clicked.connect(self.close) - self._select_provider_by_name(domain) + self._add_icons() + self._add_pages() - def _not_logged_in(self): + def _add_icons(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) + Adds all the icons for the different configuration categories. + Icons are QListWidgetItems added to the nav_widget on the side + of the preferences window. - def _provides_mx(self): - """ - Actions to perform if the provider provides MX. + A note on sizing of QListWidgetItems + icon_width = list_widget.width - (2 x nav_widget.spacing) - 2 + icon_height = 56 seems to look ok """ - pw_enabled = True - enabled_services = self._settings.get_enabled_services(self._domain) - mx_name = get_service_display_name(MX_SERVICE) + account_button = QtGui.QListWidgetItem(self.ui.nav_widget) + account_button.setIcon(QtGui.QIcon(":/images/black/32/user.png")) + account_button.setText(self.tr("Account")) + account_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + account_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + account_button.setSizeHint(QtCore.QSize(98,56)) - 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 + vpn_button = QtGui.QListWidgetItem(self.ui.nav_widget) + vpn_button.setIcon(QtGui.QIcon(":/images/black/32/earth.png")) + vpn_button.setText(self.tr("VPN")) + vpn_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + vpn_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + vpn_button.setSizeHint(QtCore.QSize(98,56)) - self.ui.gbPasswordChange.setEnabled(pw_enabled) + email_button = QtGui.QListWidgetItem(self.ui.nav_widget) + email_button.setIcon(QtGui.QIcon(":/images/black/32/email.png")) + email_button.setText(self.tr("Email")) + email_button.setTextAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter) + email_button.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) + email_button.setSizeHint(QtCore.QSize(98,56)) - @QtCore.Slot() - def set_soledad_ready(self): - """ - TRIGGERS: - parent.soledad_ready + self.ui.nav_widget.currentItemChanged.connect(self._change_page) + self.ui.nav_widget.setCurrentRow(0) - It notifies when the soledad object as ready to use. + def _add_pages(self): """ - self.ui.lblPasswordChangeStatus.setVisible(False) - self.ui.gbPasswordChange.setEnabled(True) - - def _set_password_change_status(self, status, error=False, success=False): + Adds the pages for the different configuration categories. """ - Sets the status label for the password change. + self.ui.pages_widget.addWidget(PreferencesAccountPage(self)) + self.ui.pages_widget.addWidget(PreferencesVpnPage(self, self._domain, self._backend, self._leap_signaler)) + self.ui.pages_widget.addWidget(PreferencesEmailPage(self)) - :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) + # + # Slots + # @QtCore.Slot() - def _change_password(self): + def close(self): """ TRIGGERS: - self.ui.pbChangePassword.clicked + self.ui.close_button.clicked - Changes the user's password if the inputboxes are correctly filled. + Close this dialog """ - 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) + self._parent.preferences = None + self.hide() @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): + def _change_page(self, current, previous): """ TRIGGERS: - service_checkbox.stateChanged + self.ui.nav_widget.currentItemChanged - 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): + Changes what page is displayed. """ - 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) + if not current: + current = previous + self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) diff --git a/src/leap/bitmask/gui/ui/eippreferences.ui b/src/leap/bitmask/gui/ui/eippreferences.ui deleted file mode 100644 index 1a5fcd24..00000000 --- a/src/leap/bitmask/gui/ui/eippreferences.ui +++ /dev/null @@ -1,102 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>EIPPreferences</class> - <widget class="QDialog" name="EIPPreferences"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>435</width> - <height>144</height> - </rect> - </property> - <property name="windowTitle"> - <string>Encrypted Internet Preferences</string> - </property> - <property name="windowIcon"> - <iconset resource="../../../../../data/resources/icons.qrc"> - <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QGroupBox" name="gbGatewaySelector"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="title"> - <string>Select gateway for provider</string> - </property> - <property name="checkable"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QLabel" name="lblSelectProvider"> - <property name="text"> - <string>Select &provider:</string> - </property> - <property name="buddy"> - <cstring>cbProvidersGateway</cstring> - </property> - </widget> - </item> - <item row="0" column="1" colspan="2"> - <widget class="QComboBox" name="cbProvidersGateway"> - <item> - <property name="text"> - <string><Select provider></string> - </property> - </item> - </widget> - </item> - <item row="7" column="2"> - <widget class="QPushButton" name="pbSaveGateway"> - <property name="text"> - <string>&Save this provider settings</string> - </property> - </widget> - </item> - <item row="4" column="0" colspan="3"> - <widget class="QLabel" name="lblProvidersGatewayStatus"> - <property name="text"> - <string>< Providers Gateway Status ></string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Select &gateway:</string> - </property> - <property name="buddy"> - <cstring>cbGateways</cstring> - </property> - </widget> - </item> - <item row="1" column="1" colspan="2"> - <widget class="QComboBox" name="cbGateways"> - <item> - <property name="text"> - <string>Automatic</string> - </property> - </item> - </widget> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>cbProvidersGateway</tabstop> - <tabstop>cbGateways</tabstop> - <tabstop>pbSaveGateway</tabstop> - </tabstops> - <resources> - <include location="../../../../../data/resources/icons.qrc"/> - </resources> - <connections/> -</ui> diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index f7570ee6..2e8aea8c 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -317,7 +317,6 @@ <addaction name="action_advanced_key_management"/> <addaction name="separator"/> <addaction name="action_preferences"/> - <addaction name="action_eip_preferences"/> <addaction name="separator"/> <addaction name="action_quit"/> </widget> @@ -338,12 +337,7 @@ <bool>true</bool> </property> <property name="text"> - <string>Account Preferences...</string> - </property> - </action> - <action name="action_eip_preferences"> - <property name="text"> - <string>Internet Preferences...</string> + <string>Preferences...</string> </property> </action> <action name="action_quit"> diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index cd4d3a77..5e30ea57 100644 --- a/src/leap/bitmask/gui/ui/preferences.ui +++ b/src/leap/bitmask/gui/ui/preferences.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>503</width> - <height>401</height> + <width>520</width> + <height>439</height> </rect> </property> <property name="windowTitle"> @@ -17,159 +17,97 @@ <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="4" column="0"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,1,0"> + <property name="spacing"> + <number>6</number> + </property> + <item> + <widget class="QLabel" name="account_label"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> + <property name="text"> + <string>user@example.org</string> </property> - </spacer> + </widget> </item> - <item row="0" column="0"> - <widget class="QGroupBox" name="gbPasswordChange"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="title"> - <string>Password Change</string> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> </property> - <layout class="QFormLayout" name="formLayout"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::ExpandingFieldsGrow</enum> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="lblCurrentPassword"> - <property name="text"> - <string>&Current password:</string> - </property> - <property name="buddy"> - <cstring>leCurrentPassword</cstring> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLineEdit" name="leCurrentPassword"> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="lblNewPassword"> - <property name="text"> - <string>&New password:</string> - </property> - <property name="buddy"> - <cstring>leNewPassword</cstring> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="leNewPassword"> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="lblNewPassword2"> - <property name="text"> - <string>&Re-enter new password:</string> - </property> - <property name="buddy"> - <cstring>leNewPassword2</cstring> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="leNewPassword2"> - <property name="echoMode"> - <enum>QLineEdit::Password</enum> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QPushButton" name="pbChangePassword"> - <property name="text"> - <string>Change</string> - </property> - </widget> - </item> - <item row="3" column="0" colspan="2"> - <widget class="QLabel" name="lblPasswordChangeStatus"> - <property name="text"> - <string><Password change status></string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> </widget> </item> - <item row="3" column="0"> - <widget class="QGroupBox" name="gbEnabledServices"> - <property name="title"> - <string>Enabled services</string> + <item> + <layout class="QHBoxLayout" name="horizontal_layout" stretch="0,0"> + <property name="spacing"> + <number>12</number> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="3" column="1"> - <widget class="QPushButton" name="pbSaveServices"> - <property name="text"> - <string>Save this provider settings</string> - </property> - </widget> - </item> - <item row="2" column="0" colspan="2"> - <widget class="QGroupBox" name="gbServices"> - <property name="title"> - <string>Services</string> - </property> - <property name="flat"> - <bool>false</bool> - </property> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="0"> - <layout class="QVBoxLayout" name="vlServices"/> - </item> - </layout> - </widget> - </item> - <item row="0" column="1"> - <widget class="QComboBox" name="cbProvidersServices"> - <item> - <property name="text"> - <string><Select provider></string> - </property> - </item> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Select provider:</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="2"> - <widget class="QLabel" name="lblProvidersServicesStatus"> - <property name="text"> - <string>< Providers Services Status ></string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> - </widget> + <item> + <widget class="QListWidget" name="nav_widget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>120</width> + <height>16777215</height> + </size> + </property> + <property name="iconSize"> + <size> + <width>32</width> + <height>32</height> + </size> + </property> + <property name="movement"> + <enum>QListView::Static</enum> + </property> + <property name="spacing"> + <number>10</number> + </property> + <property name="viewMode"> + <enum>QListView::IconMode</enum> + </property> + <property name="uniformItemSizes"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="pages_widget"/> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="button_layout" stretch="0,0"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="close_button"> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> diff --git a/src/leap/bitmask/gui/ui/preferences_account_page.ui b/src/leap/bitmask/gui/ui/preferences_account_page.ui new file mode 100644 index 00000000..4e58b2ab --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_account_page.ui @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PreferencesAccountPage</class> + <widget class="QWidget" name="PreferencesAccountPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>462</width> + <height>371</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QPushButton" name="btnChangePassword"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Change Password</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="lblChangePasswordStatus"> + <property name="text"> + <string><change password status></string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>15</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QGroupBox" name="gbServices"> + <property name="title"> + <string>Services</string> + </property> + <property name="flat"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="1" column="0"> + <layout class="QVBoxLayout" name="vlServices"/> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="lblProvidersServicesStatus"> + <property name="text"> + <string>< Providers Services Status ></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/leap/bitmask/gui/ui/preferences_email_page.ui b/src/leap/bitmask/gui/ui/preferences_email_page.ui new file mode 100644 index 00000000..41b3c28d --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_email_page.ui @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PreferencesEmailPage</class> + <widget class="QWidget" name="PreferencesEmailPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>300</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <widget class="QPushButton" name="pushButton"> + <property name="geometry"> + <rect> + <x>250</x> + <y>210</y> + <width>98</width> + <height>27</height> + </rect> + </property> + <property name="text"> + <string>PushButton</string> + </property> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/leap/bitmask/gui/ui/preferences_vpn_page.ui b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui new file mode 100644 index 00000000..85a0dc60 --- /dev/null +++ b/src/leap/bitmask/gui/ui/preferences_vpn_page.ui @@ -0,0 +1,89 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>PreferencesVpnPage</class> + <widget class="QWidget" name="PreferencesVpnPage"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>362</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="flash_label"> + <property name="text"> + <string><flash_label></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="heading_label"> + <property name="text"> + <string>Default VPN Gateway:</string> + </property> + <property name="buddy"> + <cstring>gateways_list</cstring> + </property> + </widget> + </item> + <item> + <widget class="QListWidget" name="gateways_list"> + <item> + <property name="text"> + <string>New Item</string> + </property> + <property name="icon"> + <iconset> + <normalon>:/images/countries/us.png</normalon> + </iconset> + </property> + </item> + <item> + <property name="text"> + <string>New Item</string> + </property> + <property name="icon"> + <iconset> + <normalon>:/images/countries/br.png</normalon> + </iconset> + </property> + </item> + </widget> + </item> + <item> + <widget class="QLabel" name="tip_label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>You must reconnect for changes to take effect.</string> + </property> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="buddy"> + <cstring>gateways_list</cstring> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../../../../../data/resources/flags.qrc"/> + </resources> + <connections/> +</ui> diff --git a/src/leap/bitmask/services/eip/eipconfig.py b/src/leap/bitmask/services/eip/eipconfig.py index 37c0c8ae..5b51d12e 100644 --- a/src/leap/bitmask/services/eip/eipconfig.py +++ b/src/leap/bitmask/services/eip/eipconfig.py @@ -113,39 +113,38 @@ class VPNGatewaySelector(object): """ Return the existing gateways, sorted by timezone proximity. - :rtype: list of tuples (location, ip) - (str, IPv4Address or IPv6Address object) + :rtype: list of tuples (label, ip, country_code) + (str, IPv4Address or IPv6Address object, str) """ gateways_timezones = [] locations = self._eipconfig.get_locations() gateways = self._eipconfig.get_gateways() for idx, gateway in enumerate(gateways): - gateway_location = gateway.get('location') - gateway_distance = 99 # if hasn't location -> should go last - - if gateway_location is not None: - timezone = locations[gateway['location']]['timezone'] - gateway_name = locations[gateway['location']].get('name', None) - if gateway_name is not None: - gateway_location = gateway_name - - gw_offset = int(timezone) - if gw_offset in self.equivalent_timezones: - gw_offset = self.equivalent_timezones[gw_offset] - - gateway_distance = self._get_timezone_distance(gw_offset) + distance = 99 # if hasn't location -> should go last + location = locations.get(gateway.get('location')) + label = gateway.get('location', 'Unknown') + country = 'XX' + if location is not None: + country = location.get('country_code', 'XX') + label = location.get('name', label) + timezone = location.get('timezone') + if timezone is not None: + offset = int(timezone) + if offset in self.equivalent_timezones: + offset = self.equivalent_timezones[offset] + distance = self._get_timezone_distance(offset) ip = self._eipconfig.get_gateway_ip(idx) - gateways_timezones.append((ip, gateway_distance, gateway_location)) + gateways_timezones.append((ip, distance, label, country)) gateways_timezones = sorted(gateways_timezones, key=lambda gw: gw[1]) - gateways = [] - for ip, distance, location in gateways_timezones: - gateways.append((location, ip)) + result = [] + for ip, distance, label, country in gateways_timezones: + result.append((label, ip, country)) - return gateways + return result def get_gateways(self): """ @@ -153,7 +152,7 @@ class VPNGatewaySelector(object): :rtype: list of IPv4Address or IPv6Address object. """ - gateways = [ip for location, ip in self.get_gateways_list()][:4] + gateways = [gateway[1] for gateway in self.get_gateways_list()][:4] return gateways def get_gateways_country_code(self): |