diff options
Diffstat (limited to 'src/leap/bitmask/gui')
20 files changed, 1137 insertions, 93 deletions
diff --git a/src/leap/bitmask/gui/account.py b/src/leap/bitmask/gui/account.py index 81f96389..b8b9509a 100644 --- a/src/leap/bitmask/gui/account.py +++ b/src/leap/bitmask/gui/account.py @@ -20,6 +20,7 @@ A frontend GUI object to hold the current username and domain. from leap.bitmask.util import make_address from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.services import EIP_SERVICE, MX_SERVICE +from leap.bitmask._components import HAS_EIP, HAS_MAIL class Account(): @@ -42,8 +43,8 @@ class Account(): """ return self._settings.get_enabled_services(self.domain) - def is_email_enabled(self): - return MX_SERVICE in self.services() + def has_email(self): + return HAS_MAIL and MX_SERVICE in self.services() - def is_eip_enabled(self): - return EIP_SERVICE in self.services() + def has_eip(self): + return HAS_EIP and EIP_SERVICE in self.services() diff --git a/src/leap/bitmask/gui/advanced_key_management.py b/src/leap/bitmask/gui/advanced_key_management.py index 2e315d18..bc496a57 100644 --- a/src/leap/bitmask/gui/advanced_key_management.py +++ b/src/leap/bitmask/gui/advanced_key_management.py @@ -94,6 +94,7 @@ class AdvancedKeyManagement(QtGui.QDialog): """ Set the current user's key details into the gui. """ + # XXX: We should avoid the key-id self.ui.leKeyID.setText(details[0]) self.ui.leFingerprint.setText(details[1]) @@ -246,7 +247,7 @@ class AdvancedKeyManagement(QtGui.QDialog): row = keys_table.rowCount() keys_table.insertRow(row) keys_table.setItem(row, 0, QtGui.QTableWidgetItem(key.address)) - keys_table.setItem(row, 1, QtGui.QTableWidgetItem(key.key_id)) + keys_table.setItem(row, 1, QtGui.QTableWidgetItem(key.fingerprint)) def _backend_connect(self): """ diff --git a/src/leap/bitmask/gui/app.py b/src/leap/bitmask/gui/app.py index 97fd0549..1011454e 100644 --- a/src/leap/bitmask/gui/app.py +++ b/src/leap/bitmask/gui/app.py @@ -20,6 +20,7 @@ and the signaler get signals from the backend. """ from PySide import QtCore, QtGui +from leap.bitmask.gui.account import Account from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.backend.backend_proxy import BackendProxy from leap.bitmask.backend.leapsignaler import LeapSignaler @@ -44,12 +45,37 @@ class App(QtGui.QWidget): self.signaler.start() self.soledad_started = False + self.service_tokens = {} + self.login_state = None + self.providers_widget = None # 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) + # store the service tokens for later use, once they are known. + self.signaler.soledad_got_service_token.connect( + self._set_service_tokens) + + def current_account(self): + """ + Alas, the only definitive account information is buried in the memory + of QT widgets. + + :returns: an object representing the current user account. + :rtype: Account + """ + if self.login_state is None or self.providers_widget is None: + return None + + if self.login_state.full_logged_username is not None: + username, domain = self.login_state.full_logged_username.split('@') + return Account(username, domain) + else: + domain = self.providers_widget.get_selected_provider() + return Account(None, domain) + def _check_backend_status(self): """ TRIGGERS: @@ -64,3 +90,11 @@ class App(QtGui.QWidget): self.tr("There is a problem contacting the backend, please " "restart Bitmask.")) self._backend_checker.stop() + + def _set_service_tokens(self, data): + """ + Triggered by signal soledad_got_service_token. + Saves the service tokens. + """ + service, token = data + self.service_tokens[service] = token diff --git a/src/leap/bitmask/gui/eip_status.py b/src/leap/bitmask/gui/eip_status.py index 64a408c4..470ef88a 100644 --- a/src/leap/bitmask/gui/eip_status.py +++ b/src/leap/bitmask/gui/eip_status.py @@ -733,7 +733,7 @@ class EIPStatusWidget(QtGui.QWidget): self.set_eip_status( # XXX this should change to polkit-kde where # applicable. - self.tr("We could not find any authentication agent in your " + self.tr("We could not find any authentication agent on your " "system.<br/>Make sure you have " "<b>polkit-gnome-authentication-agent-1</b> running and " "try again."), diff --git a/src/leap/bitmask/gui/logwindow.py b/src/leap/bitmask/gui/logwindow.py index 718269c9..5d8c99fc 100644 --- a/src/leap/bitmask/gui/logwindow.py +++ b/src/leap/bitmask/gui/logwindow.py @@ -173,7 +173,7 @@ class LoggerWindow(QtGui.QDialog): :type sending: bool """ if sending: - self.ui.btnPastebin.setText(self.tr("Sending to pastebin...")) + self.ui.btnPastebin.setText(self.tr("Sending to Pastebin.com…")) self.ui.btnPastebin.setEnabled(False) else: self.ui.btnPastebin.setText(self.tr("Send to Pastebin.com")) @@ -193,7 +193,7 @@ class LoggerWindow(QtGui.QDialog): # 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) + QtGui.QMessageBox.Information, self.tr("Pastebin is OK"), msg) msgBox.setWindowModality(QtCore.Qt.NonModal) msgBox.show() diff --git a/src/leap/bitmask/gui/mail_status.py b/src/leap/bitmask/gui/mail_status.py index 8b4329d7..419a85c0 100644 --- a/src/leap/bitmask/gui/mail_status.py +++ b/src/leap/bitmask/gui/mail_status.py @@ -186,7 +186,7 @@ class MailStatusWidget(QtGui.QWidget): msg = self.tr("There was an unexpected problem with Soledad.") self._set_mail_status(msg, ready=-1) - def set_soledad_invalid_auth_token(self, event, content): + def set_soledad_invalid_auth_token(self, event, content=None): """ This method is called when the auth token is invalid @@ -233,12 +233,15 @@ class MailStatusWidget(QtGui.QWidget): self._action_mail_status.setText(tray_status) self._update_systray_tooltip() - def _mail_handle_soledad_events(self, event, content): + def _mail_handle_soledad_events(self, event, user_data, content=""): """ Callback for handling events that are emitted from Soledad :param event: The event that triggered the callback. :type event: str + :param user_id: The user_data of the soledad user. Ignored right now, + since we're only contemplating single-user in soledad. + :type user_id: dict :param content: The content of the event. :type content: dict """ @@ -346,7 +349,7 @@ class MailStatusWidget(QtGui.QWidget): logger.warning("don't know to to handle %s" % (event,)) self._set_mail_status(ext_status, ready=1) - def _mail_handle_smtp_events(self, event): + def _mail_handle_smtp_events(self, event, content=""): """ Callback for the SMTP events @@ -380,12 +383,14 @@ class MailStatusWidget(QtGui.QWidget): # ----- XXX deprecate (move to mail conductor) - def _mail_handle_imap_events(self, event, content): + def _mail_handle_imap_events(self, event, uuid, content=""): """ Callback for the IMAP events :param event: The event that triggered the callback. :type event: str + :param uuid: The UUID for the user. Ignored right now. + :type uuid: str :param content: The content of the event. :type content: list """ diff --git a/src/leap/bitmask/gui/mainwindow.py b/src/leap/bitmask/gui/mainwindow.py index a8a4e41d..daf49eb6 100644 --- a/src/leap/bitmask/gui/mainwindow.py +++ b/src/leap/bitmask/gui/mainwindow.py @@ -46,7 +46,6 @@ from leap.bitmask.gui.signaltracker import SignalTracker from leap.bitmask.gui.systray import SysTray from leap.bitmask.gui.wizard import Wizard from leap.bitmask.gui.providers import Providers -from leap.bitmask.gui.account import Account from leap.bitmask.gui.app import App from leap.bitmask.platform_init import IS_WIN, IS_MAC, IS_LINUX @@ -60,6 +59,8 @@ from leap.bitmask.util.keyring_helpers import has_keyring from leap.common.events import register from leap.common.events import catalog +from .qt_browser import PixelatedWindow + from leap.mail.imap.service.imap import IMAP_PORT from ui_mainwindow import Ui_MainWindow @@ -152,6 +153,14 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # Provider List self._providers = Providers(self.ui.cmbProviders) + ## + # tmphack: important state information about the application is stored + # in widgets. Rather than rewrite the UI, for now we simulate this + # info being stored in an application object: + ## + self.app.login_state = self._login_widget._state + self.app.providers_widget = self._providers + # Qt Signal Connections ##################################### # TODO separate logic from ui signals. @@ -218,6 +227,12 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._backend_connect() self.ui.action_preferences.triggered.connect(self._show_preferences) + self.ui.action_pixelated_mail.triggered.connect( + self._show_pixelated_browser) + + pixelated_enabled = self._settings.get_pixelmail_enabled() + self.ui.action_pixelated_mail.setVisible(pixelated_enabled) + self.ui.action_about_leap.triggered.connect(self._about) self.ui.action_quit.triggered.connect(self.quit) self.ui.action_wizard.triggered.connect(self._show_wizard) @@ -294,6 +309,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): self._mail_conductor.connect_mail_signals(self._mail_status) if not init_platform(): + logger.critical('init_platform failed, quitting application.') self.quit() return @@ -436,6 +452,9 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): # Refer to http://www.themacaque.com/?p=1067 for funny details. self._wizard.show() if IS_MAC: + # XXX hack. For some reason, there's a signal that doesn't arrive + # on time, so that the next button is disabled. See #8041 + self._wizard.page(self._wizard.INTRO_PAGE).set_completed() self._wizard.raise_() self._settings.set_skip_first_run(True) @@ -553,17 +572,14 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): Display the preferences window. """ - logged_user = self._login_widget.get_logged_user() - if logged_user is not None: - user, domain = logged_user.split('@') - else: - user = None - domain = self._providers.get_selected_provider() - - account = Account(user, domain) - pref_win = PreferencesWindow(self, account, self.app) + pref_win = PreferencesWindow(self, self.app) pref_win.show() + def _show_pixelated_browser(self): + win = PixelatedWindow(self) + win.show() + win.load_app() + def _update_eip_enabled_status(self, account=None, services=None): """ TRIGGER: @@ -1063,7 +1079,14 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): 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") + + # FIXME on i3, this doens't allow to mouse-select. + # Switch to a dialog in which we can set the QLabel + mail_auth_token = ( + self.app.service_tokens.get('mail_auth', None) or + "??? (log in to unlock)") + mail_password = self.tr("IMAP/SMTP Password:") + " %s" % ( + mail_auth_token,) msg = help_url + self.tr( "<p><strong>{0}</strong></p>" @@ -1076,7 +1099,7 @@ class MainWindow(QtGui.QMainWindow, SignalTracker): "<li> {6}</li>" "</ul></p>").format(email_quick_reference, thunderbird_text, manual_text, manual_imap, manual_smtp, - manual_username, manual_password) + manual_username, mail_password) QtGui.QMessageBox.about(self, self.tr("Bitmask Help"), msg) def _needs_update(self): diff --git a/src/leap/bitmask/gui/passwordwindow.py b/src/leap/bitmask/gui/passwordwindow.py index dedfcb10..fe70b250 100644 --- a/src/leap/bitmask/gui/passwordwindow.py +++ b/src/leap/bitmask/gui/passwordwindow.py @@ -83,7 +83,7 @@ class PasswordWindow(QtGui.QDialog, Flashable): Returns true if the current account needs to change the soledad password as well as the SRP password. """ - return self.account.is_email_enabled() + return self.account.has_email() # # MANAGE WIDGETS diff --git a/src/leap/bitmask/gui/preferences_account_page.py b/src/leap/bitmask/gui/preferences_account_page.py index da9da14d..141523c8 100644 --- a/src/leap/bitmask/gui/preferences_account_page.py +++ b/src/leap/bitmask/gui/preferences_account_page.py @@ -22,6 +22,7 @@ from PySide import QtCore, QtGui from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui import ui_preferences_account_page as ui_pref +from leap.bitmask.gui.preferences_page import PreferencesPage from leap.bitmask.gui.passwordwindow import PasswordWindow from leap.bitmask.services import get_service_display_name from leap.bitmask._components import HAS_EIP @@ -29,7 +30,7 @@ from leap.bitmask._components import HAS_EIP logger = get_logger() -class PreferencesAccountPage(QtGui.QWidget): +class PreferencesAccountPage(PreferencesPage): def __init__(self, parent, account, app): """ @@ -42,20 +43,15 @@ class PreferencesAccountPage(QtGui.QWidget): :param app: the current App object :type app: App """ - QtGui.QWidget.__init__(self, parent) + PreferencesPage.__init__(self, parent, account, app) self.ui = ui_pref.Ui_PreferencesAccountPage() self.ui.setupUi(self) - self.account = account - self.app = app - self._selected_services = set() self.ui.change_password_label.setVisible(False) self.ui.provider_services_label.setVisible(False) - self.ui.change_password_button.clicked.connect( - self._show_change_password) - app.signaler.prov_get_supported_services.connect(self._load_services) + self.setup_connections() app.backend.provider_get_supported_services(domain=account.domain) if account.username is None: @@ -64,6 +60,24 @@ class PreferencesAccountPage(QtGui.QWidget): self.ui.change_password_label.setVisible(True) self.ui.change_password_button.setEnabled(False) + def setup_connections(self): + """ + connect signals + """ + self.ui.change_password_button.clicked.connect( + self._show_change_password) + self.app.signaler.prov_get_supported_services.connect( + self._load_services) + + def teardown_connections(self): + """ + disconnect signals + """ + self.ui.change_password_button.clicked.disconnect( + self._show_change_password) + self.app.signaler.prov_get_supported_services.disconnect( + self._load_services) + def _service_selection_changed(self, service, state): """ TRIGGERS: diff --git a/src/leap/bitmask/gui/preferences_email_page.py b/src/leap/bitmask/gui/preferences_email_page.py index 3087f343..f6d6f036 100644 --- a/src/leap/bitmask/gui/preferences_email_page.py +++ b/src/leap/bitmask/gui/preferences_email_page.py @@ -16,20 +16,212 @@ """ Widget for "email" preferences """ -from PySide import QtGui +from PySide import QtCore, QtGui +from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.ui_preferences_email_page import Ui_PreferencesEmailPage +from leap.bitmask.gui.preferences_page import PreferencesPage +from leap.bitmask.pix import HAS_PIXELATED +from leap.mail.imap.service.imap import IMAP_PORT + logger = get_logger() -class PreferencesEmailPage(QtGui.QWidget): +class PreferencesEmailPage(PreferencesPage): def __init__(self, parent, account, app): - QtGui.QWidget.__init__(self, parent) + """ + :param parent: parent object of the PreferencesWindow. + :parent type: QWidget + + :param account: user account (user + provider or just provider) + :type account: Account + + :param app: the current App object + :type app: App + """ + PreferencesPage.__init__(self, parent, account, app) + self.settings = LeapSettings() self.ui = Ui_PreferencesEmailPage() self.ui.setupUi(self) - self.account = account - self.app = app + # the only way to set the tab titles is to re-add them: + self.ui.email_tabs.addTab(self.ui.config_tab, + self.tr("Mail Client")) + self.ui.email_tabs.addTab(self.ui.my_key_tab, + self.tr("My Key")) + self.ui.email_tabs.addTab(self.ui.other_keys_tab, + self.tr("Other Keys")) + + # set mail client configuration help text + lang = QtCore.QLocale.system().name().replace('_', '-') + thunderbird_extension_url = \ + "https://addons.mozilla.org/{0}/" \ + "thunderbird/addon/bitmask/".format(lang) + self.ui.thunderbird_label.setText(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))) + self.ui.mail_client_label.setText(self.tr( + "Alternatively, you can manually configure your mail client to " + "use Bitmask Email with these options:")) + + self.ui.webmail_label.setText(self.tr( + "This distribution of Bitmask ships an experimental integration " + "of <a href='https://pixelated-project.org/'>Pixelated " + "Mail</a>. Note: at the current state, anyone with access to " + "your device can read your mail without authentication, " + "by opening a browser pointing to http://localhost:9090 ")) + webmail_enabled = self.settings.get_pixelmail_enabled() + self.ui.webmail_checkbox.setChecked(webmail_enabled) + if not HAS_PIXELATED: + self.ui.webmail_box.setVisible(False) + + self.ui.keys_table.horizontalHeader().setResizeMode( + 0, QtGui.QHeaderView.Stretch) + + self.setup_connections() + + def setup_connections(self): + """ + connect signals + """ + self.app.signaler.keymanager_key_details.connect(self._key_details) + self.app.signaler.keymanager_export_ok.connect( + self._keymanager_export_ok) + self.app.signaler.keymanager_export_error.connect( + self._keymanager_export_error) + self.ui.import_button.clicked.connect(self._import_keys) + self.ui.export_button.clicked.connect(self._export_keys) + self.ui.webmail_checkbox.stateChanged.connect(self._toggle_webmail) + + def teardown_connections(self): + """ + disconnect signals + """ + self.app.signaler.keymanager_key_details.disconnect(self._key_details) + self.app.signaler.keymanager_export_ok.disconnect( + self._keymanager_export_ok) + self.app.signaler.keymanager_export_error.disconnect( + self._keymanager_export_error) + + def showEvent(self, event): + """ + called whenever this widget is shown + """ + self.ui.keys_table.clearContents() + + if self.account.username is None: + self.ui.email_tabs.setVisible(False) + self.ui.message_label.setVisible(True) + self.ui.message_label.setText( + self.tr('You must be logged in to edit email settings.')) + else: + self.ui.import_button.setVisible(False) # hide this until working + self.ui.message_label.setVisible(False) + self.ui.email_tabs.setVisible(True) + smtp_port = 2013 + self.ui.imap_port_edit.setText(str(IMAP_PORT)) + self.ui.imap_host_edit.setText("127.0.0.1") + self.ui.smtp_port_edit.setText(str(smtp_port)) + self.ui.smtp_host_edit.setText("127.0.0.1") + self.ui.username_edit.setText(self.account.address) + self.ui.password_edit.setText( + self.app.service_tokens.get('mail_auth', '')) + + self.app.backend.keymanager_list_keys() + self.app.backend.keymanager_get_key_details( + username=self.account.address) + + def _key_details(self, details): + """ + Trigger by signal: keymanager_key_details + Set the current user's key details into the gui. + """ + self.ui.fingerprint_edit.setPlainText( + self._format_fingerprint(details["fingerprint"])) + self.ui.expiration_edit.setText(details["expiry_date"]) + self.ui.uid_edit.setText(" ".join(details["uids"])) + self.ui.public_key_edit.setPlainText(details["key_data"]) + + def _format_fingerprint(self, fingerprint): + """ + formats an openpgp fingerprint in a manner similar to what gpg + produces, wrapped to two lines. + """ + fp = fingerprint.upper() + fp_list = [fp[i:i + 4] for i in range(0, len(fp), 4)] + fp_wrapped = " ".join(fp_list[0:5]) + "\n" + " ".join(fp_list[5:10]) + return fp_wrapped + + def _export_keys(self): + """ + Exports the user's key pair. + """ + file_name, filtr = QtGui.QFileDialog.getSaveFileName( + self, self.tr("Save private key file"), + filter="*.pem", + options=QtGui.QFileDialog.DontUseNativeDialog) + + if file_name: + if not file_name.endswith('.pem'): + file_name += '.pem' + self.app.backend.keymanager_export_keys( + username=self.account.address, + filename=file_name) + else: + logger.debug('Export canceled by the user.') + + def _keymanager_export_ok(self): + """ + TRIGGERS: + Signaler.keymanager_export_ok + + Notify the user that the key export went OK. + """ + QtGui.QMessageBox.information( + self, self.tr("Export Successful"), + self.tr("The key pair was exported successfully.\n" + "Please, store your private key in a safe place.")) + + def _keymanager_export_error(self): + """ + TRIGGERS: + Signaler.keymanager_export_error + + Notify the user that the key export didn't go well. + """ + QtGui.QMessageBox.critical( + self, self.tr("Input/Output error"), + self.tr("There was an error accessing the file.\n" + "Export canceled.")) + + def _import_keys(self): + """ + not yet supported + """ + + def _keymanager_keys_list(self, keys): + """ + TRIGGERS: + Signaler.keymanager_keys_list + + Load the keys given as parameter in the table. + + :param keys: the list of keys to load. + :type keys: list + """ + for key in keys: + row = self.ui.keys_table.rowCount() + self.ui.keys_table.insertRow(row) + self.ui.keys_table.setItem( + row, 0, QtGui.QTableWidgetItem(key.address)) + self.ui.keys_table.setItem( + row, 1, QtGui.QTableWidgetItem(key.fingerprint)) + + def _toggle_webmail(self, state): + value = True if state == QtCore.Qt.Checked else False + self.settings.set_pixelmail_enabled(value) diff --git a/src/leap/bitmask/gui/preferences_page.py b/src/leap/bitmask/gui/preferences_page.py new file mode 100644 index 00000000..a5d811f9 --- /dev/null +++ b/src/leap/bitmask/gui/preferences_page.py @@ -0,0 +1,50 @@ +# -*- 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/>. +""" +Base class for preference pages +""" + +from PySide import QtGui + + +class PreferencesPage(QtGui.QWidget): + + def __init__(self, parent, account=None, app=None): + """ + :param parent: parent object of the EIPPreferencesWindow. + :type parent: QWidget + + :param account: the currently active account + :type account: Account + + :param app: shared App instance + :type app: App + """ + QtGui.QWidget.__init__(self, parent) + self.app = app + self.account = account + + def setup_connections(self): + """ + connect signals + must be overridden by subclass + """ + + def teardown_connections(self): + """ + disconnect signals + must be overridden by subclass + """ diff --git a/src/leap/bitmask/gui/preferences_vpn_page.py b/src/leap/bitmask/gui/preferences_vpn_page.py index 5b5c9604..87b86c4e 100644 --- a/src/leap/bitmask/gui/preferences_vpn_page.py +++ b/src/leap/bitmask/gui/preferences_vpn_page.py @@ -20,11 +20,11 @@ Widget for "vpn" preferences from PySide import QtCore, QtGui from leap.bitmask.gui.ui_preferences_vpn_page import Ui_PreferencesVpnPage -from leap.bitmask.config.leapsettings import LeapSettings from leap.bitmask.gui.flashable import Flashable +from leap.bitmask.gui.preferences_page import PreferencesPage -class PreferencesVpnPage(QtGui.QWidget, Flashable): +class PreferencesVpnPage(PreferencesPage, Flashable): """ Page in the preferences window that shows VPN settings @@ -41,19 +41,24 @@ class PreferencesVpnPage(QtGui.QWidget, Flashable): :param app: shared App instance :type app: App """ - QtGui.QWidget.__init__(self, parent) + PreferencesPage.__init__(self, parent, account, app) self.AUTOMATIC_GATEWAY_LABEL = self.tr("Automatic") - self.account = account - self.app = app - # Load UI self.ui = Ui_PreferencesVpnPage() self.ui.setupUi(self) self.ui.flash_label.setVisible(False) self.hide_flash() - # Connections + self.setup_connections() + + # Trigger update + self.app.backend.eip_get_gateways_list(domain=self.account.domain) + + def setup_connections(self): + """ + connect signals + """ self.ui.gateways_list.clicked.connect(self._save_selected_gateway) sig = self.app.signaler sig.eip_get_gateways_list.connect(self._update_gateways_list) @@ -61,8 +66,16 @@ class PreferencesVpnPage(QtGui.QWidget, Flashable): sig.eip_uninitialized_provider.connect( self._gateways_list_uninitialized) - # Trigger update - self.app.backend.eip_get_gateways_list(domain=self.account.domain) + def teardown_connections(self): + """ + disconnect signals + """ + self.ui.gateways_list.clicked.disconnect(self._save_selected_gateway) + sig = self.app.signaler + sig.eip_get_gateways_list.disconnect(self._update_gateways_list) + sig.eip_get_gateways_list_error.disconnect(self._gateways_list_error) + sig.eip_uninitialized_provider.disconnect( + self._gateways_list_uninitialized) def _save_selected_gateway(self, index): """ diff --git a/src/leap/bitmask/gui/preferenceswindow.py b/src/leap/bitmask/gui/preferenceswindow.py index 44c4641c..82dc8d77 100644 --- a/src/leap/bitmask/gui/preferenceswindow.py +++ b/src/leap/bitmask/gui/preferenceswindow.py @@ -20,11 +20,9 @@ Preferences window """ from PySide import QtCore, QtGui -from leap.bitmask.services import EIP_SERVICE -from leap.bitmask._components import HAS_EIP - from leap.bitmask.logs.utils import get_logger from leap.bitmask.gui.ui_preferences import Ui_Preferences +from leap.bitmask.gui.preferences_page import PreferencesPage 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 @@ -40,39 +38,46 @@ class PreferencesWindow(QtGui.QDialog): _current_window = None # currently visible preferences window - def __init__(self, parent, account, app): + def __init__(self, parent, app): """ :param parent: parent object of the PreferencesWindow. :parent type: QWidget - :param account: the user or provider - :type account: Account - :param app: the current App object :type app: App """ QtGui.QDialog.__init__(self, parent) - self.account = account self.app = app self.ui = Ui_Preferences() self.ui.setupUi(self) - self.ui.close_button.clicked.connect(self.close) - self.ui.account_label.setText(account.address) - - self.app.service_selection_changed.connect(self._update_icons) + self._account_page = None + self._vpn_page = None + self._email_page = None self._add_icons() - self._add_pages() - self._update_icons(self.account, self.account.services()) + self._set_account(app.current_account()) + self._setup_connections() # only allow a single preferences window at a time. if PreferencesWindow._current_window is not None: PreferencesWindow._current_window.close() PreferencesWindow._current_window = self + def _set_account(self, account): + """ + Initially sets, or resets, the currently viewed account. + The account might not represent an authenticated user, but + just a domain. + """ + self.ui.account_label.setText(account.address) + self._add_pages(account) + self._update_icons(account) + self.ui.pages_widget.setCurrentIndex(0) + self.ui.nav_widget.setCurrentRow(0) + def _add_icons(self): """ Adds all the icons for the different configuration categories. @@ -114,22 +119,71 @@ class PreferencesWindow(QtGui.QDialog): email_item.setSizeHint(QtCore.QSize(98, 56)) self._email_item = email_item - self.ui.nav_widget.currentItemChanged.connect(self._change_page) - self.ui.nav_widget.setCurrentRow(0) - - def _add_pages(self): + def _add_pages(self, account): """ Adds the pages for the different configuration categories. """ - self._account_page = PreferencesAccountPage( - self, self.account, self.app) - self._vpn_page = PreferencesVpnPage(self, self.account, self.app) - self._email_page = PreferencesEmailPage(self, self.account, self.app) - + self._remove_pages() # in case different account was loaded. + + # load placeholder widgets if the page should not be loaded. + # the order of the pages is important, and must match the order + # of the nav_widget icons. + self._account_page = PreferencesAccountPage(self, account, self.app) + if account.has_eip(): + self._vpn_page = PreferencesVpnPage(self, account, self.app) + else: + self._vpn_page = PreferencesPage(self) + if account.has_email(): + self._email_page = PreferencesEmailPage(self, account, self.app) + else: + self._email_page = PreferencesPage(self) self.ui.pages_widget.addWidget(self._account_page) self.ui.pages_widget.addWidget(self._vpn_page) self.ui.pages_widget.addWidget(self._email_page) + def _remove_pages(self): + # deleteLater does not seem to cascade to items in stackLayout + # (even with QtCore.Qt.WA_DeleteOnClose attribute). + # so, here we call deleteLater() explicitly. + if self._account_page is not None: + self.ui.pages_widget.removeWidget(self._account_page) + self._account_page.teardown_connections() + self._account_page.deleteLater() + if self._vpn_page is not None: + self.ui.pages_widget.removeWidget(self._vpn_page) + self._vpn_page.teardown_connections() + self._vpn_page.deleteLater() + if self._email_page is not None: + self.ui.pages_widget.removeWidget(self._email_page) + self._email_page.teardown_connections() + self._email_page.deleteLater() + + def _setup_connections(self): + """ + setup signal connections + """ + self.ui.nav_widget.currentItemChanged.connect(self._change_page) + self.ui.close_button.clicked.connect(self.close) + self.app.service_selection_changed.connect(self._update_icons) + sig = self.app.signaler + sig.srp_auth_ok.connect(self._login_status_changed) + sig.srp_logout_ok.connect(self._login_status_changed) + sig.srp_status_logged_in.connect(self._update_account) + sig.srp_status_not_logged_in.connect(self._update_account) + + def _teardown_connections(self): + """ + clean up signal connections + """ + self.ui.nav_widget.currentItemChanged.disconnect(self._change_page) + self.ui.close_button.clicked.disconnect(self.close) + self.app.service_selection_changed.disconnect(self._update_icons) + sig = self.app.signaler + sig.srp_auth_ok.disconnect(self._login_status_changed) + sig.srp_logout_ok.disconnect(self._login_status_changed) + sig.srp_status_logged_in.disconnect(self._update_account) + sig.srp_status_not_logged_in.disconnect(self._update_account) + # # Slots # @@ -144,13 +198,8 @@ class PreferencesWindow(QtGui.QDialog): Close this dialog and destroy it. """ PreferencesWindow._current_window = None - - # deleteLater does not seem to cascade to items in stackLayout - # (even with QtCore.Qt.WA_DeleteOnClose attribute). - # so, here we call deleteLater() explicitly: - self._account_page.deleteLater() - self._vpn_page.deleteLater() - self._email_page.deleteLater() + self._teardown_connections() + self._remove_pages() self.deleteLater() def _change_page(self, current, previous): @@ -170,17 +219,24 @@ class PreferencesWindow(QtGui.QDialog): current = previous self.ui.pages_widget.setCurrentIndex(self.ui.nav_widget.row(current)) - def _update_icons(self, account, services): + def _update_icons(self, account): """ TRIGGERS: self.app.service_selection_changed Change which icons are visible. """ - if account != self.account: - return + self._vpn_item.setHidden(not account.has_eip()) + self._email_item.setHidden(not account.has_email()) + + def _login_status_changed(self): + """ + Triggered by signal srp_auth_ok, srp_logout_ok + """ + self.app.backend.user_get_logged_in_status() - if HAS_EIP: - self._vpn_item.setHidden(EIP_SERVICE not in services) - # self._email_item.setHidden(not MX_SERVICE in services) - # ^^ disable email for now, there is nothing there yet. + def _update_account(self): + """ + Triggered by get srp_status_logged_in, srp_status_not_logged_in + """ + self._set_account(self.app.current_account()) diff --git a/src/leap/bitmask/gui/qt_browser.py b/src/leap/bitmask/gui/qt_browser.py new file mode 100644 index 00000000..c62e7770 --- /dev/null +++ b/src/leap/bitmask/gui/qt_browser.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# qt_browser.py +# Copyright (C) 2016 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/>. +""" +QtWebKit-based browser to display Pixelated User Agent +""" + +from PySide import QtCore, QtWebKit, QtGui + +PIXELATED_URI = 'http://localhost:9090' + + +class PixelatedWindow(QtGui.QDialog): + + def __init__(self, parent): + super(PixelatedWindow, self).__init__(parent) + self.view = QtWebKit.QWebView(self) + + layout = QtGui.QGridLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(self.view) + self.setLayout(layout) + self.setWindowTitle('Bitmask Mail') + + def load_app(self): + self.view.load(QtCore.QUrl(PIXELATED_URI)) diff --git a/src/leap/bitmask/gui/statemachines.py b/src/leap/bitmask/gui/statemachines.py index ab48b756..92c5431d 100644 --- a/src/leap/bitmask/gui/statemachines.py +++ b/src/leap/bitmask/gui/statemachines.py @@ -40,6 +40,7 @@ class SignallingState(QState): """ A state that emits a custom signal on entry. """ + def __init__(self, signal, parent=None, name=None): """ Initializer. @@ -134,6 +135,7 @@ class States(object): class CompositeEvent(QtCore.QEvent): + def __init__(self): super(CompositeEvent, self).__init__( QtCore.QEvent.Type(self.ID)) @@ -174,6 +176,7 @@ class Events(QtCore.QObject): A Wrapper object for containing the events that will be posted to a composite state machine. """ + def __init__(self, parent=None): """ Initializes the QObject with the given parent. @@ -289,6 +292,7 @@ class ConnectionMachineBuilder(object): """ Builder class for state machines made from LEAPConnections. """ + def __init__(self, connection): """ :param connection: an instance of a concrete LEAPConnection @@ -352,7 +356,6 @@ class ConnectionMachineBuilder(object): :rtype: QStateMachine """ # TODO split this method in smaller utility functions. - parent = kwargs.get('parent', None) # 1. create machine machine = CompositeMachine() diff --git a/src/leap/bitmask/gui/ui/mail_status.ui b/src/leap/bitmask/gui/ui/mail_status.ui index 8e8f1848..89e1843f 100644 --- a/src/leap/bitmask/gui/ui/mail_status.ui +++ b/src/leap/bitmask/gui/ui/mail_status.ui @@ -77,7 +77,8 @@ </property> <property name="styleSheet"> <string notr="true">background-color: #e0efd8; -padding: 10px;</string> +padding: 10px; +margin-top:5px;</string> </property> <property name="frameShape"> <enum>QFrame::NoFrame</enum> @@ -89,7 +90,7 @@ padding: 10px;</string> <number>0</number> </property> <property name="text"> - <string>Congratulations! You are ready to use Bitmask to encrypt your email. Go to <a href="https://bitmask.net/en/help/email">https://bitmask.net/en/help/email</a> for instructions on how to set up your mail client.</string> + <string>Bitmask is ready to encrypt your email. Go to <a href="https://bitmask.net/en/help/email">https://bitmask.net/en/help/email</a> for email application setup instructions.</string> </property> <property name="textFormat"> <enum>Qt::AutoText</enum> @@ -109,6 +110,9 @@ padding: 10px;</string> <property name="indent"> <number>-1</number> </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> </widget> </item> <item row="0" column="0"> diff --git a/src/leap/bitmask/gui/ui/mainwindow.ui b/src/leap/bitmask/gui/ui/mainwindow.ui index b1d68c4a..976c0c0a 100644 --- a/src/leap/bitmask/gui/ui/mainwindow.ui +++ b/src/leap/bitmask/gui/ui/mainwindow.ui @@ -315,6 +315,7 @@ </property> <addaction name="action_create_new_account"/> <addaction name="action_advanced_key_management"/> + <addaction name="action_pixelated_mail"/> <addaction name="separator"/> <addaction name="action_preferences"/> <addaction name="separator"/> @@ -370,6 +371,11 @@ <string>Create a new account...</string> </property> </action> + <action name="action_pixelated_mail"> + <property name="text"> + <string>Bitmask Webmail</string> + </property> + </action> <action name="action_advanced_key_management"> <property name="enabled"> <bool>false</bool> diff --git a/src/leap/bitmask/gui/ui/preferences.ui b/src/leap/bitmask/gui/ui/preferences.ui index 5e30ea57..51cad0a1 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>520</width> - <height>439</height> + <width>630</width> + <height>500</height> </rect> </property> <property name="windowTitle"> @@ -60,6 +60,24 @@ <height>16777215</height> </size> </property> + <property name="styleSheet"> + <string notr="true">background: palette(base); border: 1px solid palette(dark); border-radius: 2px;</string> + </property> + <property name="frameShape"> + <enum>QFrame::StyledPanel</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + <property name="lineWidth"> + <number>1</number> + </property> + <property name="midLineWidth"> + <number>0</number> + </property> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> <property name="iconSize"> <size> <width>32</width> diff --git a/src/leap/bitmask/gui/ui/preferences_email_page.ui b/src/leap/bitmask/gui/ui/preferences_email_page.ui index 7cc5bb3c..87e7121d 100644 --- a/src/leap/bitmask/gui/ui/preferences_email_page.ui +++ b/src/leap/bitmask/gui/ui/preferences_email_page.ui @@ -6,13 +6,598 @@ <rect> <x>0</x> <y>0</y> - <width>400</width> - <height>300</height> + <width>526</width> + <height>605</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QTabWidget" name="email_tabs"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="config_tab"> + <property name="accessibleName"> + <string/> + </property> + <property name="accessibleDescription"> + <string/> + </property> + <attribute name="title"> + <string>Tab 1</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <item> + <widget class="QGroupBox" name="webmail_box"> + <property name="title"> + <string>Bitmask Mail Configuration</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QCheckBox" name="webmail_checkbox"> + <property name="text"> + <string>Enable Bitmask Mail (needs restart)</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="webmail_label"> + <property name="text"> + <string>webmail info</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="thunderbird_box"> + <property name="title"> + <string>Thunderbird Configuration</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QLabel" name="thunderbird_label"> + <property name="text"> + <string>thunderbird information</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="imap_box"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Other Mail Clients Configuration</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QLabel" name="mail_client_label"> + <property name="text"> + <string>mail client information</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="1"> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QLabel" name="label_8"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Host</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_9"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Port</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="smtp_host_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="4"> + <widget class="QLabel" name="label_10"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>TLS: off</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="smtp_port_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="5"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>IMAP</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Username</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>SMTP</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Host</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="imap_host_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="label_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Port</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="6"> + <spacer name="horizontalSpacer_2"> + <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 row="1" column="5"> + <widget class="QLabel" name="label_7"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>TLS: off</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLineEdit" name="imap_port_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="username_edit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Password</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="password_edit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <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> + <widget class="QWidget" name="my_key_tab"> + <attribute name="title"> + <string>Tab 2</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QWidget" name="mykey_box" native="true"> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="4" column="0"> + <widget class="QLabel" name="pub_label"> + <property name="text"> + <string>Public Key</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QPlainTextEdit" name="public_key_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <family>Courier</family> + </font> + </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QPlainTextEdit" name="fingerprint_edit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>42</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>48</height> + </size> + </property> + <property name="font"> + <font> + <family>Courier</family> + <weight>50</weight> + <bold>false</bold> + </font> + </property> + <property name="acceptDrops"> + <bool>false</bool> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="plainText"> + <string notr="true"/> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="expiration_label"> + <property name="text"> + <string>Expiration</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="fp_label"> + <property name="text"> + <string>Fingerprint</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="uid_edit"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="uid_label"> + <property name="text"> + <string>Address</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="expiration_edit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="5" column="1"> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="1"> + <widget class="QPushButton" name="export_button"> + <property name="text"> + <string>Export Private Key</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QPushButton" name="import_button"> + <property name="text"> + <string>Import Private Key</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <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> + </layout> + </item> + </layout> + <zorder>uid_edit</zorder> + <zorder>fp_label</zorder> + <zorder>uid_label</zorder> + <zorder>expiration_edit</zorder> + <zorder>expiration_label</zorder> + <zorder>fingerprint_edit</zorder> + <zorder>public_key_edit</zorder> + <zorder>pub_label</zorder> + <zorder></zorder> + </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> + <widget class="QWidget" name="other_keys_tab"> + <attribute name="title"> + <string>Page</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <widget class="QTableWidget" name="keys_table"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::SingleSelection</enum> + </property> + <property name="selectionBehavior"> + <enum>QAbstractItemView::SelectRows</enum> + </property> + <property name="textElideMode"> + <enum>Qt::ElideRight</enum> + </property> + <attribute name="horizontalHeaderStretchLastSection"> + <bool>true</bool> + </attribute> + <column> + <property name="text"> + <string>Email</string> + </property> + </column> + <column> + <property name="text"> + <string>Key ID</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QLabel" name="message_label"> + <property name="text"> + <string>this message should be hidden</string> + </property> + </widget> + </item> + </layout> </widget> <resources/> <connections/> diff --git a/src/leap/bitmask/gui/ui/wizard.ui b/src/leap/bitmask/gui/ui/wizard.ui index b125577e..37226d13 100644 --- a/src/leap/bitmask/gui/ui/wizard.ui +++ b/src/leap/bitmask/gui/ui/wizard.ui @@ -316,7 +316,7 @@ <item row="1" column="1"> <widget class="QLabel" name="label"> <property name="text"> - <string>https://</string> + <string notr="true">https://</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> @@ -339,7 +339,7 @@ <item row="0" column="1"> <widget class="QLabel" name="label_8"> <property name="text"> - <string>https://</string> + <string notr="true">https://</string> </property> <property name="alignment"> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> |