def __init__(self, gui): super(SetupForm, self).__init__() self.gui = gui self.gateway = None self.setup_runner = None self.resize(400, 500) self.setWindowTitle(APP_NAME) self.page_1 = CodeEntryWidget(self) self.page_2 = ProgressBarWidget() self.page_3 = TahoeConfigForm() self.addWidget(self.page_1) self.addWidget(self.page_2) self.addWidget(self.page_3) self.lineedit = self.page_1.lineedit self.cancel_button = self.page_2.cancel_button self.finish_button = self.page_2.finish_button self.buttonbox = self.page_3.buttonbox self.help = self.page_1.help self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.close) self.lineedit.go.connect(self.go) self.lineedit.error.connect(self.show_error) self.cancel_button.clicked.connect(self.cancel_button_clicked) self.finish_button.clicked.connect(self.finish_button_clicked) self.buttonbox.accepted.connect(self.on_accepted) self.buttonbox.rejected.connect(self.reset) self.help.linkActivated.connect(self.on_link_activated)
def __init__(self, gui, known_gateways=None): super(WelcomeDialog, self).__init__() self.gui = gui self.known_gateways = known_gateways self.gateway = None self.setup_runner = None self.recovery_key_importer = None self.use_tor = False self.prompt_to_export = True self.resize(400, 500) self.setWindowTitle(APP_NAME) self.page_1 = WelcomeWidget(self) self.page_2 = ProgressBarWidget() self.page_3 = TahoeConfigForm() self.addWidget(self.page_1) self.addWidget(self.page_2) self.addWidget(self.page_3) self.lineedit = self.page_1.lineedit self.tor_checkbox = self.page_1.invite_code_widget.tor_checkbox self.restore_link = self.page_1.restore_link self.configure_link = self.page_1.configure_link self.preferences_button = self.page_1.preferences_button self.progressbar = self.page_2.progressbar self.cancel_button = self.page_2.cancel_button self.finish_button = self.page_2.finish_button self.buttonbox = self.page_3.buttonbox self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.close) self.lineedit.go.connect(self.go) self.lineedit.error.connect(self.show_error) self.restore_link.linkActivated.connect(self.on_restore_link_activated) self.configure_link.linkActivated.connect( self.on_configure_link_activated) self.preferences_button.clicked.connect( self.gui.show_preferences_window) self.cancel_button.clicked.connect(self.cancel_button_clicked) self.finish_button.clicked.connect(self.finish_button_clicked) self.buttonbox.accepted.connect(self.on_accepted) self.buttonbox.rejected.connect(self.reset)
class WelcomeDialog(QStackedWidget): def __init__(self, gui, known_gateways=None): super(WelcomeDialog, self).__init__() self.gui = gui self.known_gateways = known_gateways self.gateway = None self.setup_runner = None self.recovery_key_importer = None self.use_tor = False self.prompt_to_export = True self.resize(400, 500) self.setWindowTitle(APP_NAME) self.page_1 = WelcomeWidget(self) self.page_2 = ProgressBarWidget() self.page_3 = TahoeConfigForm() self.addWidget(self.page_1) self.addWidget(self.page_2) self.addWidget(self.page_3) self.lineedit = self.page_1.lineedit self.checkbox = self.page_1.invite_code_widget.checkbox self.cancel_button = self.page_2.cancel_button self.finish_button = self.page_2.finish_button self.buttonbox = self.page_3.buttonbox self.restore_link = self.page_1.restore_link self.configure_link = self.page_1.configure_link self.preferences_button = self.page_1.preferences_button self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.close) self.lineedit.go.connect(self.go) self.lineedit.error.connect(self.show_error) self.checkbox.stateChanged.connect(self.on_checkbox_state_changed) self.cancel_button.clicked.connect(self.cancel_button_clicked) self.finish_button.clicked.connect(self.finish_button_clicked) self.buttonbox.accepted.connect(self.on_accepted) self.buttonbox.rejected.connect(self.reset) self.restore_link.linkActivated.connect(self.on_restore_link_activated) self.configure_link.linkActivated.connect( self.on_configure_link_activated) self.preferences_button.clicked.connect( self.gui.show_preferences_window) def on_checkbox_state_changed(self, state): self.use_tor = bool(state) log.debug("use_tor=%s", self.use_tor) if state: self.page_2.tor_label.show() self.page_2.progressbar.setStyleSheet( 'QProgressBar::chunk { background-color: #7D4698; }') else: self.page_2.tor_label.hide() self.page_2.progressbar.setStyleSheet('') def on_configure_link_activated(self): self.setCurrentIndex(2) def update_progress(self, message): self.page_2.update_progress(message) def show_error(self, message): self.page_1.show_error(message) def reset(self): self.page_1.reset() self.page_2.reset() self.page_3.reset() self.setCurrentIndex(0) def load_service_icon(self, filepath): pixmap = QPixmap(filepath).scaled(100, 100) self.page_2.icon_overlay.setPixmap(pixmap) def handle_failure(self, failure): log.error(str(failure)) if failure.type == CancelledError: if self.page_2.progressbar.value() <= 2: show_failure(failure, self) self.show_error("Invite timed out") self.reset() return show_failure(failure, self) if failure.type == ServerConnectionError: self.show_error("Server connection error") if failure.type == WelcomeError: self.show_error("Invite refused") elif failure.type == WrongPasswordError: self.show_error("Invite confirmation failed") elif failure.type == UpgradeRequiredError: self.show_error("Upgrade required") else: self.show_error(str(failure.type.__name__)) self.reset() def on_done(self, gateway): self.gateway = gateway self.page_2.progressbar.setValue(self.page_2.progressbar.maximum()) self.finish_button.show() def on_already_joined(self, grid_name): QMessageBox.information( self, "Already connected", 'You are already connected to "{}"'.format(grid_name)) self.close() def verify_settings(self, settings, from_wormhole=True): self.show() self.raise_() settings = validate_settings(settings, self.known_gateways, self, from_wormhole) self.setup_runner = SetupRunner(self.known_gateways, self.use_tor) steps = self.setup_runner.calculate_total_steps(settings) + 2 self.page_2.progressbar.setMaximum(steps) self.setup_runner.grid_already_joined.connect(self.on_already_joined) self.setup_runner.update_progress.connect(self.update_progress) self.setup_runner.got_icon.connect(self.load_service_icon) self.setup_runner.client_started.connect( lambda gateway: self.gui.populate([gateway])) self.setup_runner.done.connect(self.on_done) d = self.setup_runner.run(settings) d.addErrback(self.handle_failure) def on_import_done(self, settings): if settings.get('hide-ip'): self.on_checkbox_state_changed(1) # Toggle Tor checkbox "on" self.setCurrentIndex(1) self.page_2.progressbar.setValue(1) self.update_progress('Verifying invitation code...') self.prompt_to_export = False self.verify_settings(settings, from_wormhole=False) def on_restore_link_activated(self): self.recovery_key_importer = RecoveryKeyImporter(self.page_1) self.recovery_key_importer.done.connect(self.on_import_done) self.recovery_key_importer.do_import() def go(self, code): self.setCurrentIndex(1) self.page_2.progressbar.setValue(1) self.update_progress('Verifying invitation code...') if code.split('-')[0] == "0": settings = get_settings_from_cheatcode(code[2:]) if settings: self.verify_settings(settings) return d = wormhole_receive(code, self.use_tor) # pylint: disable=assignment-from-no-return d.addCallback(self.verify_settings) d.addErrback(self.handle_failure) reactor.callLater(30, d.cancel) def cancel_button_clicked(self): if self.page_2.is_complete(): self.finish_button_clicked() return msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle("Cancel setup?") msgbox.setText("Are you sure you wish to cancel the setup process?") msgbox.setInformativeText( "If you cancel, you may need to obtain a new invite code.") msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msgbox.setDefaultButton(QMessageBox.No) if msgbox.exec_() == QMessageBox.Yes: self.reset() def on_accepted(self): settings = self.page_3.get_settings() msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(APP_NAME) msg.setStandardButtons(QMessageBox.Ok) if not settings['nickname']: msg.setText("Please enter a name.") msg.exec_() elif not settings['introducer']: msg.setText("Please enter an Introducer fURL.") msg.exec_() elif not is_valid_furl(settings['introducer']): msg.setText("Please enter a valid Introducer fURL.") msg.exec_() else: self.setCurrentIndex(1) self.verify_settings(settings, from_wormhole=False) def prompt_for_export(self, gateway): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.Yes) button_export = msg.button(QMessageBox.Yes) button_export.setText("&Export...") button_skip = msg.button(QMessageBox.No) button_skip.setText("&Skip") msg.setWindowTitle("Export Recovery Key?") # "Now that {} is configured..." msg.setText( "Before uploading any folders to {}, it is recommended that you " "export a Recovery Key and store it in a safe location (such as " "an encrypted USB drive or password manager).".format( gateway.name)) msg.setInformativeText( "{} does not have access to your folders, and cannot restore " "access to them. But with a Recovery Key, you can restore access " "to uploaded folders in case something goes wrong (e.g., hardware " "failure, accidental data-loss).<p><p><a href={}>More information." "..</a>".format(gateway.name, global_settings['help']['recovery_url'])) #msg.setText( # "Before uploading any folders to {}, it is <b>strongly " # "recommended</b> that you <i>export a Recovery Key</i> and store " # "it in a safe and secure location (such as an encrypted USB drive)" # ".<p><p>Possessing a Recovery Key will allow you to restore " # "access to any of the folders you've uploaded to {} in the event " # "that something goes wrong (e.g., hardware failure, accidental " # "data-loss).".format(gateway.name, gateway.name)) #msg.setDetailedText( # "A 'Recovery Key' is a small file that contains enough information" # " to re-establish a connection with your storage provider and " # "restore your previously-uploaded folders. Because access to this " # "file is sufficient to access to any of the the data you've " # "stored, it is important that you keep this file safe and secure; " # "do not share your Recovery Key with anybody!") reply = msg.exec_() if reply == QMessageBox.Yes: self.gui.main_window.export_recovery_key() # XXX else: # TODO: Nag user; "Are you sure?" pass def finish_button_clicked(self): self.gui.show() self.close() if self.prompt_to_export: self.prompt_for_export(self.gateway) self.reset() def enterEvent(self, event): event.accept() self.lineedit.update_action_button() def closeEvent(self, event): if self.gui.main_window.gateways: event.accept() else: event.ignore() msgbox = QMessageBox(self) msgbox.setIcon(QMessageBox.Question) msgbox.setWindowTitle("Exit setup?") msgbox.setText("Are you sure you wish to exit?") msgbox.setInformativeText( "{} has not yet been configured.".format(APP_NAME)) msgbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msgbox.setDefaultButton(QMessageBox.No) if msgbox.exec_() == QMessageBox.Yes: QCoreApplication.instance().quit()
class SetupForm(QStackedWidget): def __init__(self, gui): super(SetupForm, self).__init__() self.gui = gui self.gateway = None self.setup_runner = None self.resize(400, 500) self.setWindowTitle(APP_NAME) self.page_1 = CodeEntryWidget(self) self.page_2 = ProgressBarWidget() self.page_3 = TahoeConfigForm() self.addWidget(self.page_1) self.addWidget(self.page_2) self.addWidget(self.page_3) self.lineedit = self.page_1.lineedit self.cancel_button = self.page_2.cancel_button self.finish_button = self.page_2.finish_button self.buttonbox = self.page_3.buttonbox self.help = self.page_1.help self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.close) self.lineedit.go.connect(self.go) self.lineedit.error.connect(self.show_error) self.cancel_button.clicked.connect(self.cancel_button_clicked) self.finish_button.clicked.connect(self.finish_button_clicked) self.buttonbox.accepted.connect(self.on_accepted) self.buttonbox.rejected.connect(self.reset) self.help.linkActivated.connect(self.on_link_activated) def on_link_activated(self): self.setCurrentIndex(2) def update_progress(self, step, message): self.page_2.update_progress(step, message) def show_error(self, message): self.page_1.show_error(message) def reset(self): self.page_1.reset() self.page_2.reset() self.page_3.reset() self.setCurrentIndex(0) def load_service_icon(self, filepath): pixmap = QPixmap(filepath).scaled(100, 100) self.page_2.icon_overlay.setPixmap(pixmap) def show_failure(self, failure): log.error(str(failure)) msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setStandardButtons(QMessageBox.Retry) msg.setEscapeButton(QMessageBox.Retry) msg.setDetailedText(str(failure)) if failure.type == WelcomeError: self.show_error("Invite refused") msg.setWindowTitle("Invite refused") msg.setText( "The server negotiating your invitation is online but is " "currently refusing to process any invitations. This may " "indicate that your version of {} is out-of-date, in which " "case you should upgrade to the latest version and try again.". format(APP_NAME)) elif failure.type == WrongPasswordError: self.show_error("Invite confirmation failed") msg.setWindowTitle("Invite confirmation failed") msg.setText( "Either you mistyped your invite code or a potential " "attacker tried to guess your code and failed. To try " "again, you will need to obtain a new invite code from " "your inviter.") # or "service provider"? elif failure.type == json.decoder.JSONDecodeError: self.show_error("Invalid response") msg.setIcon(QMessageBox.Critical) msg.setWindowTitle("Invalid response") msg.setText( "Your invite code worked but your inviter did not provide " "the information needed to complete the invitation process. " "Please let them know about the error, and try again later " "with a new invite code.") elif failure.type == CancelledError and self.page_2.step == 1: self.show_error("Invite timed out") msg.setWindowTitle("Invite timed out") msg.setText( "The invitation process has timed out. Your invite code may " "have expired. Please request a new invite code from your " "inviter and try again.") elif failure.type == UpgradeRequiredError: self.show_error("Upgrade required") msg.setWindowTitle("Upgrade required") msg.setText( "Your version of {} is out-of-date. Please upgrade to the " "latest version and try again with a new invite code.".format( APP_NAME)) msg.setIcon(QMessageBox.Critical) msg.setStandardButtons(QMessageBox.Ok) elif failure.type == ServerConnectionError: self.show_error("Server Connection Error") msg.setWindowTitle("Server Connection Error") msg.setText( "An error occured while connecting to the server. This could " "mean that the server is currently down or that there is some " "other problem with your connection. Please try again later.") else: self.show_error(str(failure.type.__name__)) msg.setWindowTitle(str(failure.type.__name__)) msg.setText(str(failure.value)) msg.exec_() self.reset() def on_done(self, gateway): self.gateway = gateway self.gui.populate([gateway]) self.finish_button.show() def verify_settings(self, settings): nickname = settings['nickname'] while os.path.isdir(os.path.join(config_dir, nickname)): title = "{} - Choose a name".format(APP_NAME) label = "Please choose a different name for this connection:" if nickname: label = '{} is already connected to "{}".\n\n{}'.format( APP_NAME, nickname, label) nickname, _ = QInputDialog.getText(self, title, label, 0, nickname) settings['nickname'] = nickname self.setup_runner = Setup() self.setup_runner.update_progress.connect(self.update_progress) self.setup_runner.got_icon.connect(self.load_service_icon) self.setup_runner.done.connect(self.on_done) d = self.setup_runner.run(settings) d.addErrback(self.show_failure) def go(self, code): self.setCurrentIndex(1) self.update_progress(1, 'Verifying invitation code...') d = wormhole_receive(code) d.addCallback(self.verify_settings) d.addErrback(self.show_failure) reactor.callLater(60, d.cancel) def cancel_button_clicked(self): if self.page_2.is_complete(): self.finish_button_clicked() return reply = QMessageBox.question( self, "Cancel setup?", "Are you sure you wish to cancel the {} setup process? " "If you do, you may need to obtain a new invite code.".format( APP_NAME), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.reset() def on_accepted(self): settings = self.page_3.get_settings() msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(APP_NAME) msg.setStandardButtons(QMessageBox.Ok) if not settings['nickname']: msg.setText("Please enter a name.") msg.exec_() elif not settings['introducer']: msg.setText("Please enter an Introducer fURL.") msg.exec_() elif not is_valid_furl(settings['introducer']): msg.setText("Please enter a valid Introducer fURL.") msg.exec_() else: self.setCurrentIndex(1) self.verify_settings(settings) def prompt_for_export(self, gateway): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.Yes) button_export = msg.button(QMessageBox.Yes) button_export.setText("Export...") button_skip = msg.button(QMessageBox.No) button_skip.setText("Skip") msg.setWindowTitle("Export Recovery Key?") # "Now that {} is configured..." msg.setText( "Before uploading any folders to {}, it is <b>strongly " "recommended</b> that you <i>export a Recovery Key</i> and store " "it in a safe and secure location (such as an encrypted USB drive)" ".<p><p>Possessing a Recovery Key will allow you to restore " "access to any of the folders you've uploaded to {} in the event " "that something goes wrong (e.g., hardware failure, accidental " "data-loss).".format(gateway.name, gateway.name)) msg.setDetailedText( "A 'Recovery Key' is a small file that contains enough information" " (a Tahoe-LAFS 'Introducer fURL' and 'rootcap') to re-establish " "a connection with your storage provider and restore your " "previously-uploaded folders. Because access to this file is " "sufficient to access to any of the the data you've stored, it is " "important that you keep this file safe and secure; do not share " "your Recovery Key with anybody!") reply = msg.exec_() if reply == QMessageBox.Yes: self.gui.main_window.export_recovery_key() # XXX else: # TODO: Nag user; "Are you sure?" pass def finish_button_clicked(self): self.gui.show() self.close() self.prompt_for_export(self.gateway) self.reset() def closeEvent(self, event): if self.gui.main_window.gateways: event.accept() else: event.ignore() reply = QMessageBox.question( self, "Exit setup?", "{} has not yet been configured. " "Are you sure you wish to exit?".format(APP_NAME), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: reactor.stop()
def test_tahoe_config_form_get_settings(): widget = TahoeConfigForm() widget.connection_settings.introducer_text_edit.setPlainText('test') assert widget.get_settings()['introducer'] == 'test'
class WelcomeDialog(QStackedWidget): def __init__(self, gui, known_gateways=None): super(WelcomeDialog, self).__init__() self.gui = gui self.known_gateways = known_gateways self.gateway = None self.setup_runner = None self.resize(400, 500) self.setWindowTitle(APP_NAME) self.page_1 = WelcomeWidget(self) self.page_2 = ProgressBarWidget() self.page_3 = TahoeConfigForm() self.page_4 = PreferencesWidget() self.addWidget(self.page_1) self.addWidget(self.page_2) self.addWidget(self.page_3) self.addWidget(self.page_4) self.lineedit = self.page_1.lineedit self.cancel_button = self.page_2.cancel_button self.finish_button = self.page_2.finish_button self.buttonbox = self.page_3.buttonbox self.help = self.page_1.help self.preferences_button = self.page_1.preferences_button self.shortcut_close = QShortcut(QKeySequence.Close, self) self.shortcut_close.activated.connect(self.close) self.shortcut_quit = QShortcut(QKeySequence.Quit, self) self.shortcut_quit.activated.connect(self.close) self.lineedit.go.connect(self.go) self.lineedit.error.connect(self.show_error) self.cancel_button.clicked.connect(self.cancel_button_clicked) self.finish_button.clicked.connect(self.finish_button_clicked) self.buttonbox.accepted.connect(self.on_accepted) self.buttonbox.rejected.connect(self.reset) self.help.linkActivated.connect(self.on_link_activated) self.preferences_button.clicked.connect( self.on_preferences_button_clicked) self.page_4.accepted.connect(self.on_preferences_accepted) def on_link_activated(self): self.setCurrentIndex(2) def on_preferences_button_clicked(self): self.setCurrentIndex(3) def on_preferences_accepted(self): self.setCurrentIndex(0) def update_progress(self, message): self.page_2.update_progress(message) def show_error(self, message): self.page_1.show_error(message) def reset(self): self.page_1.reset() self.page_2.reset() self.page_3.reset() self.setCurrentIndex(0) def load_service_icon(self, filepath): pixmap = QPixmap(filepath).scaled(100, 100) self.page_2.icon_overlay.setPixmap(pixmap) def handle_failure(self, failure): log.error(str(failure)) if failure.type == CancelledError: if self.page_2.progressbar.value() <= 2: show_failure(failure, self) self.show_error("Invite timed out") self.reset() return show_failure(failure, self) if failure.type == ServerConnectionError: self.show_error("Server connection error") if failure.type == WelcomeError: self.show_error("Invite refused") elif failure.type == WrongPasswordError: self.show_error("Invite confirmation failed") elif failure.type == UpgradeRequiredError: self.show_error("Upgrade required") else: self.show_error(str(failure.type.__name__)) self.reset() def on_done(self, gateway): self.gateway = gateway self.gui.populate([gateway]) self.page_2.progressbar.setValue(self.page_2.progressbar.maximum()) self.finish_button.show() def on_already_joined(self, grid_name): QMessageBox.information( self, "Already connected", 'You are already connected to "{}"'.format(grid_name)) self.close() def verify_settings(self, settings, from_wormhole=True): settings = validate_settings(settings, self.known_gateways, self, from_wormhole) self.setup_runner = SetupRunner(self.known_gateways) steps = self.setup_runner.calculate_total_steps(settings) + 2 self.page_2.progressbar.setMaximum(steps) self.setup_runner.grid_already_joined.connect(self.on_already_joined) self.setup_runner.update_progress.connect(self.update_progress) self.setup_runner.got_icon.connect(self.load_service_icon) self.setup_runner.done.connect(self.on_done) d = self.setup_runner.run(settings) d.addErrback(self.handle_failure) def go(self, code): self.setCurrentIndex(1) self.page_2.progressbar.setValue(1) self.update_progress('Verifying invitation code...') if code.split('-')[0] == "0": settings = get_settings_from_cheatcode(code[2:]) if settings: self.verify_settings(settings) return d = wormhole_receive(code) d.addCallback(self.verify_settings) d.addErrback(self.handle_failure) reactor.callLater(30, d.cancel) def cancel_button_clicked(self): if self.page_2.is_complete(): self.finish_button_clicked() return reply = QMessageBox.question( self, "Cancel setup?", "Are you sure you wish to cancel the {} setup process? " "If you do, you may need to obtain a new invite code.".format( APP_NAME), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: self.reset() def on_accepted(self): settings = self.page_3.get_settings() msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(APP_NAME) msg.setStandardButtons(QMessageBox.Ok) if not settings['nickname']: msg.setText("Please enter a name.") msg.exec_() elif not settings['introducer']: msg.setText("Please enter an Introducer fURL.") msg.exec_() elif not is_valid_furl(settings['introducer']): msg.setText("Please enter a valid Introducer fURL.") msg.exec_() else: self.setCurrentIndex(1) self.verify_settings(settings, from_wormhole=False) def prompt_for_export(self, gateway): msg = QMessageBox(self) msg.setIcon(QMessageBox.Warning) msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) msg.setDefaultButton(QMessageBox.Yes) button_export = msg.button(QMessageBox.Yes) button_export.setText("Export...") button_skip = msg.button(QMessageBox.No) button_skip.setText("Skip") msg.setWindowTitle("Export Recovery Key?") # "Now that {} is configured..." msg.setText( "Before uploading any folders to {}, it is <b>strongly " "recommended</b> that you <i>export a Recovery Key</i> and store " "it in a safe and secure location (such as an encrypted USB drive)" ".<p><p>Possessing a Recovery Key will allow you to restore " "access to any of the folders you've uploaded to {} in the event " "that something goes wrong (e.g., hardware failure, accidental " "data-loss).".format(gateway.name, gateway.name)) msg.setDetailedText( "A 'Recovery Key' is a small file that contains enough information" " (a Tahoe-LAFS 'Introducer fURL' and 'rootcap') to re-establish " "a connection with your storage provider and restore your " "previously-uploaded folders. Because access to this file is " "sufficient to access to any of the the data you've stored, it is " "important that you keep this file safe and secure; do not share " "your Recovery Key with anybody!") reply = msg.exec_() if reply == QMessageBox.Yes: self.gui.main_window.export_recovery_key() # XXX else: # TODO: Nag user; "Are you sure?" pass def finish_button_clicked(self): self.gui.show() self.close() self.prompt_for_export(self.gateway) self.reset() def closeEvent(self, event): if self.gui.main_window.gateways: event.accept() else: event.ignore() reply = QMessageBox.question( self, "Exit setup?", "{} has not yet been configured. " "Are you sure you wish to exit?".format(APP_NAME), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: QCoreApplication.instance().quit()