diff options
author | Tomás Touceda <chiiph@leap.se> | 2014-08-15 10:32:37 -0300 |
---|---|---|
committer | Tomás Touceda <chiiph@leap.se> | 2014-08-15 10:32:37 -0300 |
commit | e8c028f3eb6cd0681f039c456dc1ac45c98d598f (patch) | |
tree | b7e84ebafad106726308d3c87f58ad1d900d66d7 /src/leap/bitmask/gui | |
parent | 159dbe295148975bdfe9a50f871254aa9adf2328 (diff) | |
parent | fb9bad95cc4bd2769af5f91c2f0cac1be4c3c617 (diff) |
Merge branch 'release-0.6.1'0.6.1
Diffstat (limited to 'src/leap/bitmask/gui')
-rw-r--r-- | src/leap/bitmask/gui/eip_status.py | 71 | ||||
-rw-r--r-- | src/leap/bitmask/gui/loggerwindow.py | 117 | ||||
-rw-r--r-- | src/leap/bitmask/gui/login.py | 77 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mail_status.py | 12 | ||||
-rw-r--r-- | src/leap/bitmask/gui/mainwindow.py | 473 | ||||
-rw-r--r-- | src/leap/bitmask/gui/providers.py | 114 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/advanced_key_management.ui | 4 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/eip_status.ui | 55 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/eippreferences.ui | 4 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/loggerwindow.ui | 4 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/login.ui | 87 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/logout.ui | 74 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/mail_status.ui | 6 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/mainwindow.ui | 55 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/preferences.ui | 4 | ||||
-rw-r--r-- | src/leap/bitmask/gui/ui/wizard.ui | 126 | ||||
-rw-r--r-- | src/leap/bitmask/gui/wizard.py | 21 |
17 files changed, 856 insertions, 448 deletions
diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index a707050a..abd6e2c9 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -70,8 +70,11 @@ class EIPStatusWidget(QtGui.QWidget): self.ui.eip_bandwidth.hide() self.hide_fw_down_button() + self.hide_eip_cancel_button() self.ui.btnFwDown.clicked.connect( self._on_fw_down_button_clicked) + self.ui.btnEipCancel.clicked.connect( + self._on_eip_cancel_button_clicked) # Set the EIP status icons self.CONNECTING_ICON = None @@ -88,6 +91,7 @@ class EIPStatusWidget(QtGui.QWidget): self._provider = "" self.is_restart = False self.is_cold_start = True + self.user_cancelled = False self.missing_helpers = False @@ -210,15 +214,15 @@ class EIPStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/32/wait.png", - ":/images/black/32/on.png", - ":/images/black/32/off.png") + ":/images/black/22/wait.png", + ":/images/black/22/on.png", + ":/images/black/22/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/32/wait.png", - ":/images/white/32/on.png", - ":/images/white/32/off.png") + ":/images/white/22/wait.png", + ":/images/white/22/on.png", + ":/images/white/22/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) @@ -285,6 +289,8 @@ class EIPStatusWidget(QtGui.QWidget): Triggered when the app activates eip. Disables the start/stop button. """ + # XXX hack -- we show the cancel button instead. + self.ui.btnEipStartStop.hide() self.set_startstop_enabled(False) msg = self.tr("Encrypted Internet is starting") self.set_eip_message(msg) @@ -295,6 +301,9 @@ class EIPStatusWidget(QtGui.QWidget): Triggered when a default provider_config has not been found. Disables the start button and adds instructions to the user. """ + # XXX this name is unfortunate. "disable" is also applied to a + # pushbutton being grayed out. + logger.debug('Hiding EIP start button') # you might be tempted to change this for a .setEnabled(False). # it won't work. it's under the claws of the state machine. @@ -327,6 +336,7 @@ class EIPStatusWidget(QtGui.QWidget): """ # logger.debug('Showing EIP start button') self.eip_button.show() + self.hide_eip_cancel_button() # Restore the eip action menu menu = self._systray.contextMenu() @@ -357,6 +367,7 @@ class EIPStatusWidget(QtGui.QWidget): leap_assert_type(error, bool) if error: logger.error(status) + self.hide_eip_cancel_button() else: logger.debug(status) self._eip_status = status @@ -420,6 +431,28 @@ class EIPStatusWidget(QtGui.QWidget): self.set_eip_message(msg) self.set_eip_status("") + def hide_eip_cancel_button(self): + """ + Hide eip-cancel button. + """ + self.ui.btnEipCancel.hide() + + def show_eip_cancel_button(self): + """ + Show eip-cancel button. + """ + self.ui.btnEipCancel.show() + self.user_cancelled = False + + def _on_eip_cancel_button_clicked(self): + """ + Call backend to kill the openvpn process with root privileges. + """ + self.eip_conductor.cancelled = True + self.eip_conductor._backend.bitmask_root_vpn_down() + self.user_cancelled = True + self.hide_eip_cancel_button() + @QtCore.Slot(dict) def eip_stopped(self, restart=False, failed=False): """ @@ -433,6 +466,11 @@ class EIPStatusWidget(QtGui.QWidget): self._reset_traffic_rates() self.ui.eip_bandwidth.hide() + if self.user_cancelled: + self.eip_conductor._backend.tear_fw_down() + self.eip_button.show() + failed = False + # This is assuming the firewall works correctly, but we should test fw # status positively. # Or better call it from the conductor... @@ -447,6 +485,7 @@ class EIPStatusWidget(QtGui.QWidget): msg = failed_msg else: msg = clear_traffic + self.set_eip_message(msg) self.ui.lblEIPStatus.show() self.show() @@ -523,16 +562,19 @@ class EIPStatusWidget(QtGui.QWidget): self.eipconnection.qtsigs.connected_signal.emit() self._on_eip_connected() self.is_cold_start = False + self.hide_eip_cancel_button() + self.eip_button.show() # XXX should lookup vpn_state map in EIPConnection elif vpn_state == "AUTH": self.set_eip_status(self.tr("Authenticating...")) + + # XXX should be handled by a future state machine instead. + self.show_eip_cancel_button() # we wipe up any previous error info in the EIP message # when we detect vpn authentication is happening msg = self.tr("Encrypted Internet is starting") self.set_eip_message(msg) - # on the first-run path, we hadn't showed the button yet. - self.eip_button.show() elif vpn_state == "GET_CONFIG": self.set_eip_status(self.tr("Retrieving configuration...")) elif vpn_state == "WAIT": @@ -682,9 +724,17 @@ class EIPStatusWidget(QtGui.QWidget): def _on_eip_vpn_launcher_exception(self): # XXX We should implement again translatable exceptions so # we can pass a translatable string to the panel (usermessage attr) - self.set_eip_status("VPN Launcher error.", error=True) + # FIXME this logic should belong to the backend, not to this + # widget. self.set_eipstatus_off() + st = self.tr("VPN Launcher error. See the logs for more info.") + self.set_eip_status(st, error=True) + + msg = self.tr("Encrypted Internet failed to start") + self.set_eip_message(msg) + self.show_fw_down_button() + self.aborted() def _on_eip_no_polkit_agent_error(self): @@ -743,6 +793,3 @@ class EIPStatusWidget(QtGui.QWidget): """ self.set_eip_status("", error=error) self.set_eip_status_icon("error") - -import eipstatus_rc -assert(eipstatus_rc) diff --git a/src/leap/bitmask/gui/loggerwindow.py b/src/leap/bitmask/gui/loggerwindow.py index 3a8354b1..360dd5f0 100644 --- a/src/leap/bitmask/gui/loggerwindow.py +++ b/src/leap/bitmask/gui/loggerwindow.py @@ -18,11 +18,10 @@ """ History log window """ -import logging import cgi +import logging from PySide import QtCore, QtGui -from twisted.internet import threads from ui_loggerwindow import Ui_LoggerWindow @@ -38,17 +37,17 @@ class LoggerWindow(QtGui.QDialog): """ Window that displays a history of the logged messages in the app. """ - def __init__(self, handler): + _paste_ok = QtCore.Signal(object) + _paste_error = QtCore.Signal(object) + + def __init__(self, parent, handler): """ Initialize the widget with the custom handler. :param handler: Custom handler that supports history and signal. :type handler: LeapLogHandler. """ - from twisted.internet import reactor - self.reactor = reactor - - QtGui.QDialog.__init__(self) + QtGui.QDialog.__init__(self, parent) leap_assert(handler, "We need a handler for the logger window") leap_assert_type(handler, LeapLogHandler) @@ -67,6 +66,9 @@ class LoggerWindow(QtGui.QDialog): self.ui.cbCaseInsensitive.stateChanged.connect(self._load_history) self.ui.btnPastebin.clicked.connect(self._pastebin_this) + self._paste_ok.connect(self._pastebin_ok) + self._paste_error.connect(self._pastebin_err) + self._current_filter = "" self._current_history = "" @@ -193,6 +195,45 @@ class LoggerWindow(QtGui.QDialog): self.ui.btnPastebin.setText(self.tr("Send to Pastebin.com")) self.ui.btnPastebin.setEnabled(True) + def _pastebin_ok(self, link): + """ + Handle a successful paste. + + :param link: the recently created pastebin link. + :type link: str + """ + self._set_pastebin_sending(False) + msg = self.tr("Your pastebin link <a href='{0}'>{0}</a>") + msg = msg.format(link) + + # We save the dialog in an instance member to avoid dialog being + # deleted right after we exit this method + self._msgBox = msgBox = QtGui.QMessageBox( + QtGui.QMessageBox.Information, self.tr("Pastebin OK"), msg) + msgBox.setWindowModality(QtCore.Qt.NonModal) + msgBox.show() + + def _pastebin_err(self, failure): + """ + Handle a failure in paste. + + :param failure: the exception that made the paste fail. + :type failure: Exception + """ + self._set_pastebin_sending(False) + logger.error(repr(failure)) + + msg = self.tr("Sending logs to Pastebin failed!") + if isinstance(failure, pastebin.PostLimitError): + msg = self.tr('Maximum posts per day reached') + + # We save the dialog in an instance member to avoid dialog being + # deleted right after we exit this method + self._msgBox = msgBox = QtGui.QMessageBox( + QtGui.QMessageBox.Critical, self.tr("Pastebin Error"), msg) + msgBox.setWindowModality(QtCore.Qt.NonModal) + msgBox.show() + def _pastebin_this(self): """ Send the current log history to pastebin.com and gives the user a link @@ -204,55 +245,19 @@ class LoggerWindow(QtGui.QDialog): """ content = self._current_history pb = pastebin.PastebinAPI() - link = pb.paste(PASTEBIN_API_DEV_KEY, content, - paste_name="Bitmask log", - paste_expire_date='1M') - - # convert to 'raw' link - link = "http://pastebin.com/raw.php?i=" + link.split('/')[-1] - - return link - - def pastebin_ok(link): - """ - Callback handler for `do_pastebin`. - - :param link: the recently created pastebin link. - :type link: str - """ - self._set_pastebin_sending(False) - msg = self.tr("Your pastebin link <a href='{0}'>{0}</a>") - msg = msg.format(link) - - # We save the dialog in an instance member to avoid dialog being - # deleted right after we exit this method - self._msgBox = msgBox = QtGui.QMessageBox( - QtGui.QMessageBox.Information, self.tr("Pastebin OK"), msg) - msgBox.setWindowModality(QtCore.Qt.NonModal) - msgBox.show() - - def pastebin_err(failure): - """ - Errback handler for `do_pastebin`. - - :param failure: the failure that triggered the errback. - :type failure: twisted.python.failure.Failure - """ - self._set_pastebin_sending(False) - logger.error(repr(failure)) - - msg = self.tr("Sending logs to Pastebin failed!") - if failure.check(pastebin.PostLimitError): - msg = self.tr('Maximum posts per day reached') + try: + link = pb.paste(PASTEBIN_API_DEV_KEY, content, + paste_name="Bitmask log", + paste_expire_date='1M') + # convert to 'raw' link + link = "http://pastebin.com/raw.php?i=" + link.split('/')[-1] - # We save the dialog in an instance member to avoid dialog being - # deleted right after we exit this method - self._msgBox = msgBox = QtGui.QMessageBox( - QtGui.QMessageBox.Critical, self.tr("Pastebin Error"), msg) - msgBox.setWindowModality(QtCore.Qt.NonModal) - msgBox.show() + self._paste_ok.emit(link) + except Exception as e: + self._paste_error.emit(e) self._set_pastebin_sending(True) - d = threads.deferToThread(do_pastebin) - d.addCallback(pastebin_ok) - d.addErrback(pastebin_err) + + self._paste_thread = QtCore.QThread() + self._paste_thread.run = lambda: do_pastebin() + self._paste_thread.start() diff --git a/src/leap/bitmask/gui/login.py b/src/leap/bitmask/gui/login.py index f66e71d9..2a79fafd 100644 --- a/src/leap/bitmask/gui/login.py +++ b/src/leap/bitmask/gui/login.py @@ -43,10 +43,6 @@ class LoginWidget(QtGui.QWidget): cancel_login = QtCore.Signal() logout = QtCore.Signal() - # Emitted when the user selects "Other..." in the provider - # combobox or click "Create Account" - show_wizard = QtCore.Signal() - MAX_STATUS_WIDTH = 40 # Keyring @@ -64,7 +60,6 @@ class LoginWidget(QtGui.QWidget): QtGui.QWidget.__init__(self, parent) self._settings = settings - self._selected_provider_index = -1 self.ui = Ui_LoginWidget() self.ui.setupUi(self) @@ -80,9 +75,6 @@ class LoginWidget(QtGui.QWidget): self.ui.lnUser.returnPressed.connect(self._focus_password) - self.ui.cmbProviders.currentIndexChanged.connect( - self._current_provider_changed) - self.ui.btnLogout.clicked.connect( self.logout) @@ -111,35 +103,6 @@ class LoginWidget(QtGui.QWidget): enable = True if state == QtCore.Qt.Checked else False self._settings.set_remember(enable) - def set_providers(self, provider_list): - """ - Set the provider list to provider_list plus an "Other..." item - that triggers the wizard - - :param provider_list: list of providers - :type provider_list: list of str - """ - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.clear() - self.ui.cmbProviders.addItems(provider_list + [self.tr("Other...")]) - self.ui.cmbProviders.blockSignals(False) - - def select_provider_by_name(self, name): - """ - Given a provider name/domain, it selects it in the combobox - - :param name: name or domain for the provider - :type name: str - """ - provider_index = self.ui.cmbProviders.findText(name) - self.ui.cmbProviders.setCurrentIndex(provider_index) - - def get_selected_provider(self): - """ - Returns the selected provider in the combobox - """ - return self.ui.cmbProviders.currentText() - def set_remember(self, value): """ Checks the remember user and password checkbox @@ -216,8 +179,7 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnUser.setEnabled(enabled) self.ui.lnPassword.setEnabled(enabled) - self.ui.chkRemember.setEnabled(enabled) - self.ui.cmbProviders.setEnabled(enabled) + self.ui.chkRemember.setEnabled(enabled and has_keyring()) self._set_cancel(not enabled) @@ -258,41 +220,20 @@ class LoginWidget(QtGui.QWidget): """ self.ui.lnPassword.setFocus() - @QtCore.Slot(int) - def _current_provider_changed(self, idx): - """ - TRIGGERS: - self.ui.cmbProviders.currentIndexChanged - - :param idx: the index of the new selected item - :type idx: int - """ - if idx == (self.ui.cmbProviders.count() - 1): - self.show_wizard.emit() - # Leave the previously selected provider in the combobox - prev_provider = 0 - if self._selected_provider_index != -1: - prev_provider = self._selected_provider_index - self.ui.cmbProviders.blockSignals(True) - self.ui.cmbProviders.setCurrentIndex(prev_provider) - self.ui.cmbProviders.blockSignals(False) - else: - self._selected_provider_index = idx - - def start_login(self): + def start_login(self, provider): """ Setups the login widgets for actually performing the login and performs some basic checks. + :param provider: the domain of the current provider + :type provider: unicode str :returns: True if everything's good to go, False otherwise :rtype: bool """ username = self.get_user() password = self.get_password() - provider = self.get_selected_provider() - self._enabled_services = self._settings.get_enabled_services( - self.get_selected_provider()) + self._enabled_services = self._settings.get_enabled_services(provider) if len(provider) == 0: self.set_status( @@ -331,14 +272,16 @@ class LoginWidget(QtGui.QWidget): % (e,)) return True - def logged_in(self): + def logged_in(self, provider): """ Sets the widgets to the logged in state + + :param provider: the domain of the current provider + :type provider: unicode str """ self.ui.login_widget.hide() self.ui.logged_widget.show() - self.ui.lblUser.setText(make_address( - self.get_user(), self.get_selected_provider())) + self.ui.lblUser.setText(make_address(self.get_user(), provider)) if flags.OFFLINE is False: self.logged_in_signal.emit() diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index bb755b5c..d523f449 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -134,15 +134,15 @@ class MailStatusWidget(QtGui.QWidget): WIN : light icons """ EIP_ICONS = EIP_ICONS_TRAY = ( - ":/images/black/32/wait.png", - ":/images/black/32/on.png", - ":/images/black/32/off.png") + ":/images/black/22/wait.png", + ":/images/black/22/on.png", + ":/images/black/22/off.png") if IS_LINUX: EIP_ICONS_TRAY = ( - ":/images/white/32/wait.png", - ":/images/white/32/on.png", - ":/images/white/32/off.png") + ":/images/white/22/wait.png", + ":/images/white/22/on.png", + ":/images/white/22/off.png") self.CONNECTING_ICON = QtGui.QPixmap(EIP_ICONS[0]) self.CONNECTED_ICON = QtGui.QPixmap(EIP_ICONS[1]) diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index 6959650b..8ce7f2fc 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -22,6 +22,8 @@ import time from datetime import datetime +import psutil + from PySide import QtCore, QtGui from leap.bitmask import __version__ as VERSION @@ -43,6 +45,7 @@ from leap.bitmask.gui.mail_status import MailStatusWidget from leap.bitmask.gui.preferenceswindow import PreferencesWindow from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard +from leap.bitmask.gui.providers import Providers from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX from leap.bitmask.platform_init.initializers import init_platform @@ -56,7 +59,7 @@ from leap.bitmask.services.mail import conductor as mail_conductor from leap.bitmask.services import EIP_SERVICE, MX_SERVICE -from leap.bitmask.util import make_address +from leap.bitmask.util import autostart, make_address from leap.bitmask.util.keyring_helpers import has_keyring from leap.bitmask.logs.leap_log_handler import LeapLogHandler @@ -95,9 +98,9 @@ class MainWindow(QtGui.QMainWindow): EIP_START_TIMEOUT = 60000 # in milliseconds # We give the services some time to a halt before forcing quit. - SERVICES_STOP_TIMEOUT = 20000 # in milliseconds + SERVICES_STOP_TIMEOUT = 3000 # in milliseconds - def __init__(self, start_hidden=False): + def __init__(self, start_hidden=False, backend_pid=None): """ Constructor for the client main window @@ -106,6 +109,7 @@ class MainWindow(QtGui.QMainWindow): :type start_hidden: bool """ QtGui.QMainWindow.__init__(self) + autostart.set_autostart(True) # register leap events ######################################## register(signal=proto.UPDATER_NEW_UPDATES, @@ -125,6 +129,11 @@ class MainWindow(QtGui.QMainWindow): self._backend = BackendProxy() + # periodically check if the backend is alive + self._backend_checker = QtCore.QTimer(self) + self._backend_checker.timeout.connect(self._check_backend_status) + self._backend_checker.start(2000) + self._leap_signaler = LeapSignaler() self._leap_signaler.start() @@ -140,14 +149,18 @@ class MainWindow(QtGui.QMainWindow): self._mail_status = MailStatusWidget(self) self.ui.mailLayout.addWidget(self._mail_status) + # Provider List + self._providers = Providers(self.ui.cmbProviders) + # Qt Signal Connections ##################################### # TODO separate logic from ui signals. self._login_widget.login.connect(self._login) self._login_widget.cancel_login.connect(self._cancel_login) - self._login_widget.show_wizard.connect(self._launch_wizard) self._login_widget.logout.connect(self._logout) + self._providers.connect_provider_changed(self._on_provider_changed) + # EIP Control redux ######################################### self._eip_conductor = eip_conductor.EIPConductor( self._settings, self._backend, self._leap_signaler) @@ -158,11 +171,16 @@ class MainWindow(QtGui.QMainWindow): self._disable_eip_missing_helpers) self.ui.eipLayout.addWidget(self._eip_status) + + # XXX we should get rid of the circular refs + # conductor <-> status, right now keeping state on the widget ifself. self._eip_conductor.add_eip_widget(self._eip_status) self._eip_conductor.connect_signals() self._eip_conductor.qtsigs.connected_signal.connect( self._on_eip_connection_connected) + self._eip_conductor.qtsigs.disconnected_signal.connect( + self._on_eip_connection_disconnected) self._eip_conductor.qtsigs.connected_signal.connect( self._maybe_run_soledad_setup_checks) @@ -172,10 +190,10 @@ class MainWindow(QtGui.QMainWindow): self.eip_needs_login.connect(self._eip_status.disable_eip_start) self.eip_needs_login.connect(self._disable_eip_start_action) + # XXX all this info about state should move to eip conductor too self._already_started_eip = False self._trying_to_start_eip = False - self._already_started_eip = False self._soledad_started = False # This is created once we have a valid provider config @@ -189,6 +207,7 @@ class MainWindow(QtGui.QMainWindow): # used to know if we are in the final steps of quitting self._quitting = False self._finally_quitting = False + self._system_quit = False self._backend_connected_signals = [] self._backend_connect() @@ -201,8 +220,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.action_wizard.triggered.connect(self._launch_wizard) self.ui.action_show_logs.triggered.connect(self._show_logger_window) self.ui.action_help.triggered.connect(self._help) + self.ui.action_create_new_account.triggered.connect( - self._launch_wizard) + self._on_provider_changed) self.ui.action_advanced_key_management.triggered.connect( self._show_AKM) @@ -224,8 +244,8 @@ class MainWindow(QtGui.QMainWindow): self._action_eip_startstop = QtGui.QAction("", self) self._eip_status.set_action_eip_startstop(self._action_eip_startstop) - self._action_visible = QtGui.QAction(self.tr("Hide Main Window"), self) - self._action_visible.triggered.connect(self._toggle_visible) + self._action_visible = QtGui.QAction(self.tr("Show Main Window"), self) + self._action_visible.triggered.connect(self._ensure_visible) # disable buttons for now, may come back later. # self.ui.btnPreferences.clicked.connect(self._show_preferences) @@ -264,23 +284,16 @@ class MainWindow(QtGui.QMainWindow): self._wizard = None self._wizard_firstrun = False - self._logger_window = None - self._start_hidden = start_hidden + self._backend_pid = backend_pid self._mail_conductor = mail_conductor.MailConductor(self._backend) self._mail_conductor.connect_mail_signals(self._mail_status) self.logout.connect(self._mail_conductor.stop_mail_services) - # Eip machine is a public attribute where the state machine for - # the eip connection will be available to the different components. - # Remember that this will not live in the +1600LOC mainwindow for - # all the eternity, so at some point we will be moving this to - # the EIPConductor or some other clever component that we will - # instantiate from here. + # start event machines from within the eip and mail conductors - # start event machines # TODO should encapsulate all actions into one object self._eip_conductor.start_eip_machine( action=self._action_eip_startstop) @@ -334,6 +347,23 @@ class MainWindow(QtGui.QMainWindow): logger.error("Bad call to the backend:") logger.error(data) + @QtCore.Slot() + def _check_backend_status(self): + """ + TRIGGERS: + self._backend_checker.timeout + + Check that the backend is running. Otherwise show an error to the user. + """ + online = self._backend.online + if not online: + logger.critical("Backend is not online.") + QtGui.QMessageBox.critical( + self, self.tr("Application error"), + self.tr("There is a problem contacting the backend, please " + "restart Bitmask.")) + self._backend_checker.stop() + def _backend_connect(self, only_tracked=False): """ Connect to backend signals. @@ -479,7 +509,6 @@ class MainWindow(QtGui.QMainWindow): def _launch_wizard(self): """ TRIGGERS: - self._login_widget.show_wizard self.ui.action_wizard.triggered Also called in first run. @@ -534,20 +563,16 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.ui.action_show_logs.triggered - Displays the window with the history of messages logged until now + Display the window with the history of messages logged until now and displays the new ones on arrival. """ - if self._logger_window is None: - leap_log_handler = self._get_leap_logging_handler() - if leap_log_handler is None: - logger.error('Leap logger handler not found') - return - else: - self._logger_window = LoggerWindow(handler=leap_log_handler) - self._logger_window.setVisible( - not self._logger_window.isVisible()) + leap_log_handler = self._get_leap_logging_handler() + if leap_log_handler is None: + logger.error('Leap logger handler not found') + return else: - self._logger_window.setVisible(not self._logger_window.isVisible()) + lw = LoggerWindow(self, handler=leap_log_handler) + lw.show() @QtCore.Slot() def _show_AKM(self): @@ -555,9 +580,9 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.ui.action_advanced_key_management.triggered - Displays the Advanced Key Management dialog. + Display the Advanced Key Management dialog. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() logged_user = "{0}@{1}".format(self._logged_user, domain) details = self._provider_details @@ -577,10 +602,10 @@ class MainWindow(QtGui.QMainWindow): self.ui.btnPreferences.clicked (disabled for now) self.ui.action_preferences - Displays the preferences window. + Display the preferences window. """ user = self._logged_user - domain = self._login_widget.get_selected_provider() + 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'] @@ -695,9 +720,9 @@ class MainWindow(QtGui.QMainWindow): self.ui.btnEIPPreferences.clicked self.ui.action_eip_preferences (disabled for now) - Displays the EIP preferences window. + Display the EIP preferences window. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() pref = EIPPreferencesWindow(self, domain, self._backend, self._leap_signaler) pref.show() @@ -721,7 +746,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self.new_updates - Displays the new updates label and sets the updates_content + Display the new updates label and sets the updates_content :param req: Request type :type req: leap.common.events.events_pb2.SignalRequest @@ -774,7 +799,7 @@ class MainWindow(QtGui.QMainWindow): # XXX: May be this can be divided into two methods? providers = self._settings.get_configured_providers() - self._login_widget.set_providers(providers) + self._providers.set_providers(providers) self._show_systray() if not self._start_hidden: @@ -790,12 +815,12 @@ class MainWindow(QtGui.QMainWindow): # select the configured provider in the combo box domain = self._wizard.get_domain() - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) self._login_widget.set_remember(self._wizard.get_remember()) self._enabled_services = list(self._wizard.get_services()) self._settings.set_enabled_services( - self._login_widget.get_selected_provider(), + self._providers.get_selected_provider(), self._enabled_services) if possible_username is not None: self._login_widget.set_user(possible_username) @@ -812,7 +837,7 @@ class MainWindow(QtGui.QMainWindow): domain = self._settings.get_provider() if domain is not None: - self._login_widget.select_provider_by_name(domain) + self._providers.select_provider_by_name(domain) if not self._settings.get_remember(): # nothing to do here @@ -875,11 +900,7 @@ class MainWindow(QtGui.QMainWindow): """ Set the login label to reflect offline status. """ - provider = "" - if not self._logged_in_offline: - provider = self.ui.lblLoginProvider.text() - - self.ui.lblLoginProvider.setText(provider + self.tr(" (offline mode)")) + # TODO: figure out what widget to use for this. Maybe the window title? # # systray @@ -936,10 +957,8 @@ class MainWindow(QtGui.QMainWindow): :param reason: the reason why the tray got activated. :type reason: int - Displays the context menu from the tray icon + Display the context menu from the tray icon """ - self._update_hideshow_menu() - context_menu = self._systray.contextMenu() if not IS_MAC: # for some reason, context_menu.show() @@ -948,48 +967,42 @@ class MainWindow(QtGui.QMainWindow): # this works however. context_menu.exec_(self._systray.geometry().center()) - def _update_hideshow_menu(self): - """ - Updates the Hide/Show main window menu text based on the - visibility of the window. + @QtCore.Slot() + def _ensure_visible(self): """ - get_action = lambda visible: ( - self.tr("Show Main Window"), - self.tr("Hide Main Window"))[int(visible)] + TRIGGERS: + self._action_visible.triggered - # set labels - visible = self.isVisible() and self.isActiveWindow() - self._action_visible.setText(get_action(visible)) + Ensure that the window is visible and raised. + """ + QtGui.QApplication.setQuitOnLastWindowClosed(True) + self.show() + if IS_LINUX: + # On ubuntu, activateWindow doesn't work reliably, so + # we do the following as a workaround. See + # https://bugreports.qt-project.org/browse/QTBUG-24932 + # for more details + QtGui.QX11Info.setAppUserTime(0) + self.activateWindow() + self.raise_() @QtCore.Slot() - def _toggle_visible(self): + def _ensure_invisible(self): """ TRIGGERS: self._action_visible.triggered - Toggles the window visibility + Ensure that the window is hidden. """ - visible = self.isVisible() and self.isActiveWindow() - - if not visible: - QtGui.QApplication.setQuitOnLastWindowClosed(True) - self.show() - self.activateWindow() - self.raise_() - else: - # We set this in order to avoid dialogs shutting down the - # app on close, as they will be the only visible window. - # e.g.: PreferencesWindow, LoggerWindow - QtGui.QApplication.setQuitOnLastWindowClosed(False) - self.hide() - - # Wait a bit until the window visibility has changed so - # the menu is set with the correct value. - QtDelayedCall(500, self._update_hideshow_menu) + # We set this in order to avoid dialogs shutting down the + # app on close, as they will be the only visible window. + # e.g.: PreferencesWindow, LoggerWindow + QtGui.QApplication.setQuitOnLastWindowClosed(False) + self.hide() def _center_window(self): """ - Centers the mainwindow based on the desktop geometry + Center the main window based on the desktop geometry """ geometry = self._settings.get_geometry() state = self._settings.get_windowstate() @@ -1048,22 +1061,40 @@ class MainWindow(QtGui.QMainWindow): # TODO: don't hardcode! smtp_port = 2013 - url = ("<a href='https://addons.mozilla.org/es/thunderbird/" - "addon/bitmask/'>bitmask addon</a>") - - msg = self.tr( - "<strong>Instructions to use mail:</strong><br>" - "If you use Thunderbird you can use the Bitmask extension helper. " - "Search for 'Bitmask' in the add-on manager or download it " - "from: {0}.<br><br>" - "You can configure Bitmask manually with these options:<br>" - "<em>" - " Incoming -> IMAP, port: {1}<br>" - " Outgoing -> SMTP, port: {2}<br>" - " Username -> your bitmask username.<br>" - " Password -> does not matter, use any text. " - " Just don't leave it empty and don't use your account's password." - "</em>").format(url, IMAP_PORT, smtp_port) + help_url = "<p><a href='https://{0}'>{0}</a></p>".format( + self.tr("bitmask.net/help")) + + lang = QtCore.QLocale.system().name().replace('_', '-') + thunderbird_extension_url = \ + "https://addons.mozilla.org/{0}/" \ + "thunderbird/addon/bitmask/".format(lang) + + email_quick_reference = self.tr("Email quick reference") + thunderbird_text = self.tr( + "For Thunderbird, you can use the " + "Bitmask extension. Search for \"Bitmask\" in the add-on " + "manager or download it from <a href='{0}'>" + "addons.mozilla.org</a>.".format(thunderbird_extension_url)) + manual_text = self.tr( + "Alternately, you can manually configure " + "your mail client to use Bitmask Email with these options:") + manual_imap = self.tr("IMAP: localhost, port {0}".format(IMAP_PORT)) + manual_smtp = self.tr("SMTP: localhost, port {0}".format(smtp_port)) + manual_username = self.tr("Username: your full email address") + manual_password = self.tr("Password: any non-empty text") + + msg = help_url + self.tr( + "<p><strong>{0}</strong></p>" + "<p>{1}</p>" + "<p>{2}" + "<ul>" + "<li> {3}</li>" + "<li> {4}</li>" + "<li> {5}</li>" + "<li> {6}</li>" + "</ul></p>").format(email_quick_reference, thunderbird_text, + manual_text, manual_imap, manual_smtp, + manual_username, manual_password) QtGui.QMessageBox.about(self, self.tr("Bitmask Help"), msg) def _needs_update(self): @@ -1089,26 +1120,19 @@ class MainWindow(QtGui.QMainWindow): "Error: API version incompatible.") QtGui.QMessageBox.warning(self, self.tr("Incompatible Provider"), msg) - def changeEvent(self, e): - """ - Reimplements the changeEvent method to minimize to tray - """ - if not IS_MAC and \ - QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ - e.type() == QtCore.QEvent.WindowStateChange and \ - self.isMinimized(): - self._toggle_visible() - e.accept() - return - QtGui.QMainWindow.changeEvent(self, e) - def closeEvent(self, e): """ Reimplementation of closeEvent to close to tray """ + if not e.spontaneous(): + # if the system requested the `close` then we should quit. + self._system_quit = True + self.quit() + return + if QtGui.QSystemTrayIcon.isSystemTrayAvailable() and \ not self._really_quit: - self._toggle_visible() + self._ensure_invisible() e.ignore() return @@ -1119,7 +1143,7 @@ class MainWindow(QtGui.QMainWindow): def _first_run(self): """ - Returns True if there are no configured providers. False otherwise + Return True if there are no configured providers. False otherwise :rtype: bool """ @@ -1128,13 +1152,15 @@ class MainWindow(QtGui.QMainWindow): skip_first_run = self._settings.get_skip_first_run() return not (has_provider_on_disk and skip_first_run) + @QtCore.Slot() def _download_provider_config(self): """ - Starts the bootstrapping sequence. It will download the + Start the bootstrapping sequence. It will download the provider configuration if it's not present, otherwise will emit the corresponding signals inmediately """ - domain = self._login_widget.get_selected_provider() + self._disconnect_scheduled_login() + domain = self._providers.get_selected_provider() self._backend.provider_setup(provider=domain) @QtCore.Slot(dict) @@ -1151,7 +1177,7 @@ class MainWindow(QtGui.QMainWindow): :type data: dict """ if data[PASSED_KEY]: - selected_provider = self._login_widget.get_selected_provider() + selected_provider = self._providers.get_selected_provider() self._backend.provider_bootstrap(provider=selected_provider) else: logger.error(data[ERROR_KEY]) @@ -1160,38 +1186,122 @@ class MainWindow(QtGui.QMainWindow): @QtCore.Slot() def _login_problem_provider(self): """ - Warns the user about a problem with the provider during login. + Warn the user about a problem with the provider during login. """ + # XXX triggers? self._login_widget.set_status( self.tr("Unable to login: Problem with provider")) self._login_widget.set_enabled(True) + def _schedule_login(self): + """ + Schedule the login sequence to go after the EIP started. + + The login sequence is connected to all finishing status of EIP + (connected, disconnected, aborted or died) to continue with the login + after EIP. + """ + logger.debug('Login scheduled when eip_connected is triggered') + eip_sigs = self._eip_conductor.qtsigs + eip_sigs.connected_signal.connect(self._download_provider_config) + eip_sigs.disconnected_signal.connect(self._download_provider_config) + eip_sigs.connection_aborted_signal.connect( + self._download_provider_config) + eip_sigs.connection_died_signal.connect(self._download_provider_config) + + def _disconnect_scheduled_login(self): + """ + Disconnect scheduled login signals if exists + """ + try: + eip_sigs = self._eip_conductor.qtsigs + eip_sigs.connected_signal.disconnect( + self._download_provider_config) + eip_sigs.disconnected_signal.disconnect( + self._download_provider_config) + eip_sigs.connection_aborted_signal.disconnect( + self._download_provider_config) + eip_sigs.connection_died_signal.disconnect( + self._download_provider_config) + except Exception: + # signal not connected + pass + + @QtCore.Slot(object) + def _on_provider_changed(self, wizard=True): + """ + TRIGGERS: + self._providers._provider_changed + self.ui.action_create_new_account.triggered + + Ask the user if really wants to change provider since a services stop + is required for that action. + + :param wizard: whether the 'other...' option was picked or not. + :type wizard: bool + """ + # TODO: we should handle the case that EIP is autostarting since we + # won't get a warning until EIP has fully started. + # TODO: we need to add a check for the mail status (smtp/imap/soledad) + something_runing = (self._logged_user is not None or + self._already_started_eip) + if not something_runing: + if wizard: + self._launch_wizard() + return + + title = self.tr("Stop services") + text = "<b>" + self.tr("Do you want to stop all services?") + "</b>" + informative_text = self.tr("In order to change the provider, the " + "running services needs to be stopped.") + + msg = QtGui.QMessageBox(self) + msg.setWindowTitle(title) + msg.setText(text) + msg.setInformativeText(informative_text) + msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + msg.setDefaultButton(QtGui.QMessageBox.No) + msg.setIcon(QtGui.QMessageBox.Warning) + res = msg.exec_() + + if res == QtGui.QMessageBox.Yes: + self._stop_services() + self._eip_conductor.qtsigs.do_disconnect_signal.emit() + if wizard: + self._launch_wizard() + else: + if not wizard: + # if wizard, the widget restores itself + self._providers.restore_previous_provider() + @QtCore.Slot() def _login(self): """ TRIGGERS: self._login_widget.login - Starts the login sequence. Which involves bootstrapping the + Start the login sequence. Which involves bootstrapping the selected provider if the selection is valid (not empty), then start the SRP authentication, and as the last step bootstrapping the EIP service """ # TODO most of this could ve handled by the login widget, - # but we'd have to move lblLoginProvider into the widget itself, - # instead of having it as a top-level attribute. + provider = self._providers.get_selected_provider() if flags.OFFLINE is True: logger.debug("OFFLINE mode! bypassing remote login") # TODO reminder, we're not handling logout for offline # mode. - self._login_widget.logged_in() + self._login_widget.logged_in(provider) self._logged_in_offline = True self._set_label_offline() self.offline_mode_bypass_login.emit() else: self.ui.action_create_new_account.setEnabled(False) - if self._login_widget.start_login(): - self._download_provider_config() + if self._login_widget.start_login(provider): + if self._trying_to_start_eip: + self._schedule_login() + else: + self._download_provider_config() @QtCore.Slot(unicode) def _authentication_error(self, msg): @@ -1217,11 +1327,16 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._login_widget.cancel_login - Stops the login sequence. + Stop the login sequence. """ logger.debug("Cancelling log in.") + self._disconnect_scheduled_login() + self._cancel_ongoing_defers() + # Needed in case of EIP starting and login deferer never set + self._set_login_cancelled() + def _cancel_ongoing_defers(self): """ Cancel the running defers to avoid app blocking. @@ -1241,7 +1356,7 @@ class MainWindow(QtGui.QMainWindow): Signaler.prov_cancelled_setup fired by self._backend.provider_cancel_setup() - This method re-enables the login widget and display a message for + Re-enable the login widget and display a message for the cancelled operation. """ self._login_widget.set_status(self.tr("Log in cancelled by the user.")) @@ -1262,7 +1377,7 @@ class MainWindow(QtGui.QMainWindow): self._show_hide_unsupported_services() - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.user_login(provider=domain, username=username, password=password) else: @@ -1282,7 +1397,7 @@ class MainWindow(QtGui.QMainWindow): self._logged_user = self._login_widget.get_user() user = self._logged_user - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() full_user_id = make_address(user, domain) self._mail_conductor.userid = full_user_id self._start_eip_bootstrap() @@ -1301,13 +1416,12 @@ class MainWindow(QtGui.QMainWindow): def _start_eip_bootstrap(self): """ - Changes the stackedWidget index to the EIP status one and + Change the stackedWidget index to the EIP status one and triggers the eip bootstrapping. """ - self._login_widget.logged_in() - domain = self._login_widget.get_selected_provider() - self.ui.lblLoginProvider.setText(domain) + domain = self._providers.get_selected_provider() + self._login_widget.logged_in(domain) self._enabled_services = self._settings.get_enabled_services(domain) @@ -1329,7 +1443,7 @@ class MainWindow(QtGui.QMainWindow): and enabled. This is triggered right after the provider has been set up. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() lang = QtCore.QLocale.system().name() self._backend.provider_get_details(domain=domain, lang=lang) @@ -1345,12 +1459,12 @@ class MainWindow(QtGui.QMainWindow): def _provides_mx_and_enabled(self): """ - Defines if the current provider provides mx and if we have it enabled. + Define if the current provider provides mx and if we have it enabled. :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) mx_enabled = MX_SERVICE in enabled_services @@ -1362,12 +1476,12 @@ class MainWindow(QtGui.QMainWindow): def _provides_eip_and_enabled(self): """ - Defines if the current provider provides eip and if we have it enabled. + Define if the current provider provides eip and if we have it enabled. :returns: True if provides and is enabled, False otherwise :rtype: bool """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() enabled_services = self._settings.get_enabled_services(domain) eip_enabled = EIP_SERVICE in enabled_services @@ -1388,7 +1502,7 @@ class MainWindow(QtGui.QMainWindow): username = self._login_widget.get_user() password = unicode(self._login_widget.get_password()) - provider_domain = self._login_widget.get_selected_provider() + provider_domain = self._providers.get_selected_provider() if flags.OFFLINE: full_user_id = make_address(username, provider_domain) @@ -1404,7 +1518,7 @@ class MainWindow(QtGui.QMainWindow): password=password, uuid=uuid) else: if self._logged_user is not None: - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.soledad_bootstrap(username=username, domain=domain, password=password) @@ -1464,14 +1578,14 @@ class MainWindow(QtGui.QMainWindow): @QtCore.Slot() def _disable_eip_start_action(self): """ - Disables the EIP start action in the systray menu. + Disable the EIP start action in the systray menu. """ self._action_eip_startstop.setEnabled(False) @QtCore.Slot() def _enable_eip_start_action(self): """ - Enables the EIP start action in the systray menu. + Enable the EIP start action in the systray menu. """ self._action_eip_startstop.setEnabled(True) self._eip_status.enable_eip_start() @@ -1488,7 +1602,7 @@ class MainWindow(QtGui.QMainWindow): """ self._already_started_eip = True - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._settings.set_defaultprovider(domain) self._backend.eip_get_gateway_country_code(domain=domain) @@ -1497,6 +1611,16 @@ class MainWindow(QtGui.QMainWindow): self._backend.eip_check_dns(domain=domain) @QtCore.Slot() + def _on_eip_connection_disconnected(self): + """ + TRIGGERS: + self._eip_conductor.qtsigs.disconnected_signal + + Set the eip status to not started. + """ + self._already_started_eip = False + + @QtCore.Slot() def _set_eip_provider(self, country_code=None): """ TRIGGERS: @@ -1505,7 +1629,7 @@ class MainWindow(QtGui.QMainWindow): Set the current provider and country code in the eip status widget. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._eip_status.set_provider(domain, country_code) @QtCore.Slot() @@ -1513,7 +1637,7 @@ class MainWindow(QtGui.QMainWindow): """ Trigger this if we don't have a working DNS resolver. """ - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() msg = self.tr( "The server at {0} can't be found, because the DNS lookup " "failed. DNS is the network service that translates a " @@ -1528,7 +1652,7 @@ class MainWindow(QtGui.QMainWindow): def _try_autostart_eip(self): """ - Tries to autostart EIP + Try to autostart EIP. """ settings = self._settings default_provider = settings.get_defaultprovider() @@ -1548,6 +1672,8 @@ class MainWindow(QtGui.QMainWindow): :param autostart: we are autostarting EIP when this is True :type autostart: bool """ + # XXX should move to EIP conductor. + # during autostart we assume that the provider provides EIP if autostart: should_start = EIP_SERVICE in self._enabled_services @@ -1567,9 +1693,15 @@ class MainWindow(QtGui.QMainWindow): self._enable_eip_start_action() self._eip_status.set_eip_status( self.tr("Starting...")) + self._eip_status.show_eip_cancel_button() + + # We were disabling the button, but now that we have + # a cancel button we just hide it. It will be visible + # when the connection is completed successfully. + self._eip_status.eip_button.hide() self._eip_status.eip_button.setEnabled(False) - domain = self._login_widget.get_selected_provider() + domain = self._providers.get_selected_provider() self._backend.eip_setup(provider=domain) self._already_started_eip = True @@ -1627,8 +1759,9 @@ class MainWindow(QtGui.QMainWindow): """ passed = data[PASSED_KEY] if not passed: - self._login_widget.set_status( - self.tr("Unable to connect: Problem with provider")) + self._eip_status.set_eip_status( + self.tr("Unable to connect: Problem with provider"), + error=True) logger.error(data[ERROR_KEY]) self._already_started_eip = False self._eip_status.aborted() @@ -1641,7 +1774,7 @@ class MainWindow(QtGui.QMainWindow): TRIGGERS: self._login_widget.logout - Starts the logout sequence + Start the logout sequence """ self._cancel_ongoing_defers() @@ -1659,7 +1792,6 @@ class MainWindow(QtGui.QMainWindow): Inform the user about a logout error. """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._login_widget.set_status( self.tr("Something went wrong with the logout.")) @@ -1669,11 +1801,10 @@ class MainWindow(QtGui.QMainWindow): TRIGGER: self._srp_auth.logout_ok - Switches the stackedWidget back to the login stage after + Switch the stackedWidget back to the login stage after logging out """ self._login_widget.done_logout() - self.ui.lblLoginProvider.setText(self.tr("Login")) self._logged_user = None self._login_widget.logged_out() @@ -1690,7 +1821,7 @@ class MainWindow(QtGui.QMainWindow): self._backend.signaler.prov_https_connection self._backend.signaler.prov_download_ca_cert - If there was a problem, displays it, otherwise it does nothing. + If there was a problem, display it, otherwise it does nothing. This is used for intermediate bootstrapping stages, in case they fail. """ @@ -1744,6 +1875,7 @@ class MainWindow(QtGui.QMainWindow): imap_stopped = lambda: self._remove_service('imap') self._leap_signaler.imap_stopped.connect(imap_stopped) + # XXX change name, already used in conductor. eip_stopped = lambda: self._remove_service('eip') self._leap_signaler.eip_stopped.connect(eip_stopped) @@ -1766,11 +1898,13 @@ class MainWindow(QtGui.QMainWindow): if self._quitting: return + autostart.set_autostart(False) + self._quitting = True # first thing to do quitting, hide the mainwindow and show tooltip. self.hide() - if self._systray is not None: + if not self._system_quit and self._systray is not None: self._systray.showMessage( self.tr('Quitting...'), self.tr('Bitmask is quitting, please wait.')) @@ -1782,21 +1916,39 @@ class MainWindow(QtGui.QMainWindow): if self._wizard: self._wizard.close() - if self._logger_window: - self._logger_window.close() - # Set this in case that the app is hidden QtGui.QApplication.setQuitOnLastWindowClosed(True) - self._stop_services() - self._really_quit = True + if not self._backend.online: + self.final_quit() + return + # call final quit when all the services are stopped self.all_services_stopped.connect(self.final_quit) + + self._stop_services() + + # we wait and call manually since during the system's logout the + # backend process can be killed and we won't get a response. + # XXX: also, for some reason the services stop timeout does not work. + if self._system_quit: + time.sleep(0.5) + self.final_quit() + # or if we reach the timeout QtDelayedCall(self.SERVICES_STOP_TIMEOUT, self.final_quit) + def _backend_kill(self): + """ + Send a kill signal to the backend process. + This is called if the backend does not respond to requests. + """ + if self._backend_pid is not None: + logger.debug("Killing backend") + psutil.Process(self._backend_pid).kill() + @QtCore.Slot() def _remove_service(self, service): """ @@ -1807,6 +1959,7 @@ class MainWindow(QtGui.QMainWindow): :param service: the service that we want to remove :type service: str """ + logger.debug("Removing service: {0}".format(service)) self._services_being_stopped.discard(service) if not self._services_being_stopped: @@ -1825,16 +1978,22 @@ class MainWindow(QtGui.QMainWindow): if self._finally_quitting: return + logger.debug('Final quit...') self._finally_quitting = True - logger.debug('Closing soledad...') - self._backend.soledad_close() - logger.debug('Final quit...') + if self._backend.online: + logger.debug('Closing soledad...') + self._backend.soledad_close() self._leap_signaler.stop() + self._backend.stop() time.sleep(0.05) # give the thread a little time to finish. + if self._system_quit or not self._backend.online: + logger.debug("Killing the backend") + self._backend_kill() + # Remove lockfiles on a clean shutdown. logger.debug('Cleaning pidfiles') if IS_WIN: diff --git a/src/leap/bitmask/gui/providers.py b/src/leap/bitmask/gui/providers.py new file mode 100644 index 00000000..b3eb8620 --- /dev/null +++ b/src/leap/bitmask/gui/providers.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2013,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/>. +# + +""" +An instance of class Providers, held by mainwindow, is responsible for +managing the current provider and the combobox provider list. +""" + +from collections import deque +from PySide import QtCore + + +class Providers(QtCore.QObject): + + # Emitted when the user changes the provider combobox index. The object + # parameter is actually a boolean value that is True if "Other..." was + # selected, False otherwse + _provider_changed = QtCore.Signal(object) + + def __init__(self, providers_combo): + """ + :param providers_combo: combo widget that lists providers + :type providers_combo: QWidget + """ + QtCore.QObject.__init__(self) + self._providers_indexes = deque(maxlen=2) # previous and current + self._providers_indexes.append(-1) + self._combo = providers_combo + self._combo.currentIndexChanged.connect( + self._current_provider_changed) + + def set_providers(self, provider_list): + """ + Set the provider list to provider_list plus an "Other..." item + that triggers the wizard + + :param provider_list: list of providers + :type provider_list: list of str + """ + self._combo.blockSignals(True) + self._combo.clear() + self._combo.addItems(provider_list + [self.tr("Other...")]) + self._combo.blockSignals(False) + + def select_provider_by_name(self, name): + """ + Given a provider name/domain, it selects it in the combobox + + :param name: name or domain for the provider + :type name: unicode str + """ + provider_index = self._combo.findText(name) + self._providers_indexes.append(provider_index) + + # block the signals during a combobox change since we don't want to + # trigger the default signal that makes the UI ask the user for + # confirmation + self._combo.blockSignals(True) + self._combo.setCurrentIndex(provider_index) + self._combo.blockSignals(False) + + def get_selected_provider(self): + """ + Returns the selected provider in the combobox + + :rtype: unicode str + """ + return self._combo.currentText() + + def connect_provider_changed(self, callback): + """ + Connects callback to provider_changed signal + """ + self._provider_changed.connect(callback) + + def restore_previous_provider(self): + """ + Set as selected provider the one that was selected previously. + """ + prev_provider = self._providers_indexes.popleft() + self._providers_indexes.append(prev_provider) + self._combo.blockSignals(True) + self._combo.setCurrentIndex(prev_provider) + self._combo.blockSignals(False) + + @QtCore.Slot(int) + def _current_provider_changed(self, idx): + """ + TRIGGERS: + self._combo.currentIndexChanged + + :param idx: the index of the new selected item + :type idx: int + """ + self._providers_indexes.append(idx) + is_wizard = idx == (self._combo.count() - 1) + self._provider_changed.emit(is_wizard) + if is_wizard: + self.restore_previous_provider() diff --git a/src/leap/bitmask/gui/ui/advanced_key_management.ui b/src/leap/bitmask/gui/ui/advanced_key_management.ui index 3b567347..72f70d24 100644 --- a/src/leap/bitmask/gui/ui/advanced_key_management.ui +++ b/src/leap/bitmask/gui/ui/advanced_key_management.ui @@ -14,7 +14,7 @@ <string>Advanced Key Management</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <layout class="QGridLayout" name="gridLayout_4"> @@ -184,7 +184,7 @@ </layout> </widget> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/eip_status.ui b/src/leap/bitmask/gui/ui/eip_status.ui index 7216bb0a..0fb861bc 100644 --- a/src/leap/bitmask/gui/ui/eip_status.ui +++ b/src/leap/bitmask/gui/ui/eip_status.ui @@ -28,13 +28,26 @@ <property name="verticalSpacing"> <number>0</number> </property> - <item row="0" column="4"> + <item row="0" column="5"> <widget class="QPushButton" name="btnEipStartStop"> <property name="text"> <string>Turn On</string> </property> </widget> </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>0</height> + </size> + </property> + </spacer> + </item> <item row="0" column="0"> <widget class="QLabel" name="label"> <property name="maximumSize"> @@ -47,7 +60,7 @@ <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/earth.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/32/earth.png</pixmap> </property> </widget> </item> @@ -86,39 +99,26 @@ </property> </widget> </item> - <item row="0" column="5"> + <item row="0" column="6"> <widget class="QLabel" name="lblVPNStatusIcon"> <property name="maximumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> </size> </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/off.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/off.png</pixmap> </property> <property name="scaledContents"> <bool>true</bool> </property> </widget> </item> - <item row="1" column="2"> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>0</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="2" colspan="4"> + <item row="2" column="2" colspan="5"> <widget class="QWidget" name="eip_bandwidth" native="true"> <layout class="QHBoxLayout" name="horizontalLayout"> <property name="spacing"> @@ -162,7 +162,7 @@ <string>0.0 KB/s</string> </property> <property name="icon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/black/32/arrow-down.png</normaloff>:/images/black/32/arrow-down.png</iconset> </property> <property name="flat"> @@ -213,7 +213,7 @@ <string>0.0 KB/s</string> </property> <property name="icon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/black/32/arrow-up.png</normaloff>:/images/black/32/arrow-up.png</iconset> </property> <property name="flat"> @@ -239,7 +239,7 @@ </layout> </widget> </item> - <item row="0" column="3"> + <item row="0" column="4"> <widget class="QPushButton" name="btnFwDown"> <property name="text"> <string>Turn Off</string> @@ -253,13 +253,20 @@ </property> </widget> </item> + <item row="0" column="3"> + <widget class="QPushButton" name="btnEipCancel"> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </item> </layout> </item> </layout> </widget> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> <include location="../../../../../data/resources/icons.qrc"/> + <include location="../../../../../data/resources/flags.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/eippreferences.ui b/src/leap/bitmask/gui/ui/eippreferences.ui index a3050683..1a5fcd24 100644 --- a/src/leap/bitmask/gui/ui/eippreferences.ui +++ b/src/leap/bitmask/gui/ui/eippreferences.ui @@ -14,7 +14,7 @@ <string>Encrypted Internet Preferences</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <layout class="QGridLayout" name="gridLayout_2"> @@ -96,7 +96,7 @@ <tabstop>pbSaveGateway</tabstop> </tabstops> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/loggerwindow.ui b/src/leap/bitmask/gui/ui/loggerwindow.ui index b19ed91a..fd8644c9 100644 --- a/src/leap/bitmask/gui/ui/loggerwindow.ui +++ b/src/leap/bitmask/gui/ui/loggerwindow.ui @@ -14,7 +14,7 @@ <string>Logs</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <layout class="QGridLayout" name="gridLayout"> @@ -180,7 +180,7 @@ </tabstops> <resources> <include location="../../../../../data/resources/loggerwindow.qrc"/> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/login.ui b/src/leap/bitmask/gui/ui/login.ui index 216eca9e..bfd5f9c0 100644 --- a/src/leap/bitmask/gui/ui/login.ui +++ b/src/leap/bitmask/gui/ui/login.ui @@ -33,7 +33,7 @@ <number>0</number> </property> <property name="verticalSpacing"> - <number>-1</number> + <number>6</number> </property> <item row="2" column="0"> <spacer name="horizontalSpacer_2"> @@ -69,24 +69,20 @@ <property name="rightMargin"> <number>24</number> </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string><b>Provider:</b></string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="3" column="0"> + <item row="3" column="1"> <widget class="QPushButton" name="btnLogin"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="text"> <string>Log In</string> </property> </widget> </item> - <item row="3" column="1"> + <item row="2" column="1"> <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QCheckBox" name="chkRemember"> @@ -110,10 +106,7 @@ </item> </layout> </item> - <item row="0" column="1"> - <widget class="QComboBox" name="cmbProviders"/> - </item> - <item row="1" column="0"> + <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string><b>Username:</b></string> @@ -123,10 +116,10 @@ </property> </widget> </item> - <item row="1" column="1"> + <item row="0" column="1"> <widget class="QLineEdit" name="lnUser"/> </item> - <item row="2" column="0"> + <item row="1" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string><b>Password:</b></string> @@ -136,7 +129,7 @@ </property> </widget> </item> - <item row="2" column="1"> + <item row="1" column="1"> <widget class="QLineEdit" name="lnPassword"> <property name="inputMask"> <string/> @@ -164,7 +157,7 @@ <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/user.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/32/user.png</pixmap> </property> <property name="scaledContents"> <bool>false</bool> @@ -198,26 +191,17 @@ </item> <item row="3" column="2" colspan="2"> <widget class="QWidget" name="logged_widget" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <layout class="QGridLayout" name="gridLayout_5"> + <layout class="QHBoxLayout" name="horizontalLayout"> <property name="topMargin"> <number>0</number> </property> + <property name="rightMargin"> + <number>25</number> + </property> <property name="bottomMargin"> - <number>12</number> + <number>18</number> </property> - <item row="0" column="0" colspan="2"> + <item> <widget class="QLabel" name="lblUser"> <property name="font"> <font> @@ -231,22 +215,41 @@ </property> </widget> </item> - <item row="1" column="0"> + <item> + <spacer name="expandingSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </spacer> + </item> + <item> <widget class="QPushButton" name="btnLogout"> <property name="text"> <string>Logout</string> </property> </widget> </item> - <item row="1" column="1"> - <spacer name="horizontalSpacer"> + <item> + <spacer name="fixedSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> <property name="sizeHint" stdset="0"> <size> - <width>40</width> - <height>20</height> + <width>24</width> + <height>24</height> </size> </property> </spacer> @@ -283,7 +286,7 @@ <tabstop>chkRemember</tabstop> </tabstops> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/logout.ui b/src/leap/bitmask/gui/ui/logout.ui new file mode 100644 index 00000000..3faa93b6 --- /dev/null +++ b/src/leap/bitmask/gui/ui/logout.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>Form</class> + <widget class="QWidget" name="Form"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>434</width> + <height>202</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="lblUser"> + <property name="font"> + <font> + <pointsize>15</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item> + <spacer name="expandingSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="btnLogout"> + <property name="text"> + <string>Logout</string> + </property> + </widget> + </item> + <item> + <spacer name="fixedSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>24</width> + <height>24</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui index 22976f39..6fd63aec 100644 --- a/src/leap/bitmask/gui/ui/mail_status.ui +++ b/src/leap/bitmask/gui/ui/mail_status.ui @@ -60,7 +60,7 @@ <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/off.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/off.png</pixmap> </property> <property name="scaledContents"> <bool>true</bool> @@ -104,14 +104,14 @@ <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/black/32/email.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/32/email.png</pixmap> </property> </widget> </item> </layout> </widget> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <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 d755115a..92c13d15 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>524</width> - <height>722</height> + <height>600</height> </rect> </property> <property name="sizePolicy"> @@ -32,7 +32,7 @@ <string>Bitmask</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <property name="inputMethodHints"> @@ -75,7 +75,7 @@ <x>0</x> <y>0</y> <width>524</width> - <height>667</height> + <height>540</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> @@ -86,7 +86,7 @@ <number>0</number> </property> <item> - <widget class="QFrame" name="frame"> + <widget class="QFrame" name="providerFrame"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> @@ -97,29 +97,16 @@ <bool>false</bool> </property> <property name="styleSheet"> - <string notr="true">background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30);</string> + <string notr="true">QFrame#providerFrame {background-color: rgba(0,0,0,20); border-bottom: 1px solid rgba(0,0,0,30);}</string> </property> <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="leftMargin"> - <number>24</number> - </property> - <property name="rightMargin"> - <number>24</number> - </property> <item> - <widget class="QLabel" name="lblLoginProvider"> + <widget class="QComboBox" name="cmbProviders"> <property name="font"> <font> - <weight>75</weight> - <bold>true</bold> + <pointsize>12</pointsize> </font> </property> - <property name="styleSheet"> - <string notr="true">background-color: rgba(255, 255, 255, 0); border: none;</string> - </property> - <property name="text"> - <string>Please Log In</string> - </property> </widget> </item> </layout> @@ -186,7 +173,7 @@ <item> <layout class="QVBoxLayout" name="mailLayout"> <property name="spacing"> - <number>-1</number> + <number>6</number> </property> <property name="margin"> <number>12</number> @@ -216,6 +203,28 @@ </property> </spacer> </item> + <item> + <widget class="QFrame" name="frame"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>16</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true">background-color: rgba(0,0,0,20); border-top: 1px solid rgba(0,0,0,30);</string> + </property> + </widget> + </item> </layout> </widget> </widget> @@ -297,7 +306,7 @@ <x>0</x> <y>0</y> <width>524</width> - <height>23</height> + <height>25</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -377,7 +386,7 @@ </action> </widget> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> <include location="../../../../../data/resources/locale.qrc"/> </resources> <connections/> diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index e187c016..cd4d3a77 100644 --- a/src/leap/bitmask/gui/ui/preferences.ui +++ b/src/leap/bitmask/gui/ui/preferences.ui @@ -14,7 +14,7 @@ <string>Preferences</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <layout class="QGridLayout" name="gridLayout_3"> @@ -174,7 +174,7 @@ </layout> </widget> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> </resources> <connections/> </ui> diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index 8c52897d..0e28ecbf 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -23,10 +23,10 @@ </size> </property> <property name="windowTitle"> - <string>Bitmask first run</string> + <string>Bitmask Provider Setup</string> </property> <property name="windowIcon"> - <iconset resource="../../../../../data/resources/mainwindow.qrc"> + <iconset resource="../../../../../data/resources/icons.qrc"> <normaloff>:/images/mask-icon.png</normaloff>:/images/mask-icon.png</iconset> </property> <property name="modal"> @@ -40,10 +40,10 @@ </property> <widget class="WizardPage" name="introduction_page"> <property name="title"> - <string>Welcome</string> + <string>Welcome to Bitmask</string> </property> <property name="subTitle"> - <string>This is the Bitmask first run wizard</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">0</string> @@ -59,7 +59,7 @@ <item row="0" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> - <string><html><head/><body><p>Now we will guide you through some configuration that is needed before you can connect for the first time.</p><p>If you ever need to modify these options again, you can find the wizard in the <span style=" font-style:italic;">'Bitmask -&gt; Create new account...'</span> menu from the main window.</p><p>Do you want to <span style=" font-weight:600;">sign up</span> for a new account, or <span style=" font-weight:600;">log in</span> with an already existing username?</p></body></html></string> + <string></string> </property> <property name="textFormat"> <enum>Qt::RichText</enum> @@ -109,10 +109,10 @@ </widget> <widget class="WizardPage" name="select_provider_page"> <property name="title"> - <string>Provider selection</string> + <string>Choose a provider</string> </property> <property name="subTitle"> - <string>Please enter the domain of the provider you want to use for your connection</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">1</string> @@ -156,7 +156,7 @@ <item row="3" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> - <string>Getting provider information</string> + <string>Getting provider information.</string> </property> </widget> </item> @@ -177,15 +177,24 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> </size> </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> @@ -199,15 +208,24 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> </size> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> @@ -221,15 +239,24 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> </size> </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> @@ -350,10 +377,10 @@ </widget> <widget class="QWizardPage" name="provider_info_page"> <property name="title"> - <string>Provider Information</string> + <string>About this provider</string> </property> <property name="subTitle"> - <string>Description of services offered by this provider</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">2</string> @@ -495,7 +522,7 @@ <string>Provider setup</string> </property> <property name="subTitle"> - <string>Gathering configuration options for this provider</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">3</string> @@ -517,7 +544,7 @@ <item> <widget class="QLabel" name="lblSetupProviderExpl"> <property name="text"> - <string>We are downloading some bits that we need to establish a secure connection with the provider for the first time.</string> + <string>Bitmask is attempting to establish a secure connection with this provider for the first time.</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -553,15 +580,24 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> </size> </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> @@ -575,36 +611,45 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> </size> </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label_9"> <property name="text"> - <string>Getting info from the Certificate Authority</string> + <string>Fetching provider credentials.</string> </property> </widget> </item> <item row="2" column="0"> <widget class="QLabel" name="label_10"> <property name="text"> - <string>Do we trust this Certificate Authority?</string> + <string>Do we trust these credentials?</string> </property> </widget> </item> <item row="3" column="0"> <widget class="QLabel" name="label_11"> <property name="text"> - <string>Establishing a trust relationship with this provider</string> + <string>Connecting to provider.</string> </property> </widget> </item> @@ -618,15 +663,24 @@ </property> <property name="minimumSize"> <size> - <width>24</width> - <height>24</height> + <width>22</width> + <height>22</height> </size> </property> + <property name="maximumSize"> + <size> + <width>22</width> + <height>22</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> <property name="text"> <string/> </property> <property name="pixmap"> - <pixmap resource="../../../../../data/resources/mainwindow.qrc">:/images/Emblem-question.png</pixmap> + <pixmap resource="../../../../../data/resources/icons.qrc">:/images/black/22/question.png</pixmap> </property> </widget> </item> @@ -666,7 +720,7 @@ <string>Register new user</string> </property> <property name="subTitle"> - <string>Register a new user with provider</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">4</string> @@ -791,7 +845,7 @@ <string>Service selection</string> </property> <property name="subTitle"> - <string>Please select the services you would like to have</string> + <string> </string> </property> <attribute name="pageId"> <string notr="true">5</string> @@ -829,7 +883,7 @@ <tabstop>rdoLogin</tabstop> </tabstops> <resources> - <include location="../../../../../data/resources/mainwindow.qrc"/> + <include location="../../../../../data/resources/icons.qrc"/> <include location="../../../../../data/resources/locale.qrc"/> </resources> <connections> diff --git a/src/leap/bitmask/gui/wizard.py b/src/leap/bitmask/gui/wizard.py index be5bde52..0223c053 100644 --- a/src/leap/bitmask/gui/wizard.py +++ b/src/leap/bitmask/gui/wizard.py @@ -70,9 +70,9 @@ class Wizard(QtGui.QWizard): self.setPixmap(QtGui.QWizard.LogoPixmap, QtGui.QPixmap(":/images/mask-icon.png")) - self.QUESTION_ICON = QtGui.QPixmap(":/images/Emblem-question.png") - self.ERROR_ICON = QtGui.QPixmap(":/images/Dialog-error.png") - self.OK_ICON = QtGui.QPixmap(":/images/Dialog-accept.png") + self.QUESTION_ICON = QtGui.QPixmap(":/images/black/22/question.png") + self.ERROR_ICON = QtGui.QPixmap(":/images/black/22/off.png") + self.OK_ICON = QtGui.QPixmap(":/images/black/22/on.png") self._selected_services = set() self._shown_services = set() @@ -679,7 +679,7 @@ class Wizard(QtGui.QWizard): the user to enable or disable. """ self.ui.grpServices.setTitle( - self.tr("Services by {0}").format(self._provider_details['name'])) + self.tr("Services by {0}").format(self._provider_details['domain'])) services = get_supported(self._provider_details['services']) @@ -723,18 +723,11 @@ class Wizard(QtGui.QWizard): if pageId == self.SETUP_PROVIDER_PAGE: if not self._provider_setup_ok: self._reset_provider_setup() - sub_title = self.tr("Gathering configuration options for {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) self.ui.lblDownloadCaCert.setPixmap(self.QUESTION_ICON) self._provider_setup_defer = self._backend.\ provider_bootstrap(provider=self._domain) if pageId == self.PRESENT_PROVIDER_PAGE: - sub_title = self.tr("Description of services offered by {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) - details = self._provider_details name = "<b>{0}</b>".format(details['name']) domain = "https://{0}".format(details['domain']) @@ -746,9 +739,9 @@ class Wizard(QtGui.QWizard): self.ui.lblProviderPolicy.setText(details['enrollment_policy']) if pageId == self.REGISTER_USER_PAGE: - sub_title = self.tr("Register a new user with {0}") - sub_title = sub_title.format(self._provider_details['name']) - self.page(pageId).setSubTitle(sub_title) + title = self.tr("Register a new user with {0}") + title = title.format(self._provider_details['domain']) + self.page(pageId).setTitle(title) self.ui.chkRemember.setVisible(False) if pageId == self.SERVICES_PAGE: |