def on_verify_token_finished(self, res): if res == OAuth2Session.Success: self.auth_session.save_creds() # switch to next page self.stackedWidget.slideInIdx(2) self.pushButtonDropboxPathSelect.setFocus() self.lineEditAuthCode.clear() # clear since we might come back on unlink # start Maestral after linking to Dropbox account start_maestral_daemon_thread(self._config_name, run=False) self.mdbx = get_maestral_proxy(self._config_name) self.mdbx.reset_sync_state() self.mdbx.get_account_info() elif res == OAuth2Session.InvalidToken: msg = 'Please make sure that you entered the correct authentication token.' msg_box = UserDialog('Authentication failed.', msg, parent=self) msg_box.open() elif res == OAuth2Session.ConnectionFailed: msg = 'Please make sure that you are connected to the internet and try again.' msg_box = UserDialog('Connection failed.', msg, parent=self) msg_box.open() self.progressIndicator.stopAnimation() self.pushButtonAuthPageLink.setEnabled(True) self.lineEditAuthCode.setEnabled(True)
def rebuild_index(config_name: str): """Rebuilds Maestral's index. May take several minutes.""" if not pending_link_cli(config_name): import textwrap width, height = click.get_terminal_size() message1 = textwrap.wrap( 'If you encounter sync issues, please run \'maestral status\' to check for ' 'sync issues which can should be resolved manually, e.g., incompatible file ' 'names or insufficient permissions. After resolving them, please pause and ' 'resume syncing. Only rebuild the index if you continue to have problems ' 'after taking those steps.', width=width, ) message2 = textwrap.wrap( 'Rebuilding the index may take several minutes, depending on the size of ' 'your Dropbox. Please do not modify any items in your local Dropbox folder ' 'during this process. Any changes to local files while rebuilding may be ' 'lost.', width=width) click.echo('\n'.join(message1) + '\n') click.echo('\n'.join(message2) + '\n') click.confirm('Do you want to continue?', abort=True) import time import Pyro5.client from concurrent.futures import ThreadPoolExecutor from maestral.daemon import MaestralProxy, get_maestral_proxy m0 = get_maestral_proxy(config_name, fallback=True) def rebuild_in_thread(): if isinstance(m0, Pyro5.client.Proxy): # rebuild index from separate proxy with MaestralProxy(config_name) as m1: m1.rebuild_index() else: # rebuild index with main instance m0.rebuild_index() with ThreadPoolExecutor(max_workers=1) as executor: future = executor.submit(rebuild_in_thread) while future.running(): # get status updates while rebuilding msg = ('\r' + m0.status).ljust(width) click.echo(msg, nl=False) time.sleep(1.0) future.result() # this will raise any errors during rebuilding click.echo('\rRebuilding complete.'.ljust(width)) del m0 # delete while still in scope else: click.echo('Maestral does not appear to be linked.')
def load_maestral(self): not_linked = pending_link(self.config_name) if not_linked or pending_dropbox_folder(self.config_name): from maestral_qt.setup_dialog import SetupDialog logger.info('Setting up Maestral...') done = SetupDialog.configureMaestral(self.config_name, not_linked) self._started = True if done: logger.info('Successfully set up Maestral') self.mdbx = get_maestral_proxy(self.config_name) self.mdbx.run() self.setup_ui_linked() else: logger.info('Setup aborted.') self.quit() else: self.mdbx = self._get_or_start_maestral_daemon() self.setup_ui_linked()
def _get_or_start_maestral_daemon(self): pid = get_maestral_pid(self.config_name) if pid: self._started = False else: if IS_MACOS_BUNDLE: res = start_maestral_daemon_thread(self.config_name) else: res = start_maestral_daemon_process(self.config_name) if res == Start.Failed: title = 'Could not start Maestral' message = ('Could not start or connect to sync daemon. Please try again ' 'and contact the developer if this issue persists.') show_dialog(title, message, level='error') self.quit() elif res == Start.AlreadyRunning: self._started = False elif res == Start.Ok: self._started = True return get_maestral_proxy(self.config_name)
def __init__(self, config_name='maestral', pending_link=True, parent=None): super().__init__(parent=parent) # load user interface layout from .ui file uic.loadUi(SETUP_DIALOG_PATH, self) self.setWindowFlags(Qt.WindowStaysOnTopHint) self._config_name = config_name self._conf = MaestralConfig(config_name) self._state = MaestralState(config_name) self.app_icon = QtGui.QIcon(APP_ICON_PATH) self.labelIcon_0.setPixmap(icon_to_pixmap(self.app_icon, 150)) self.labelIcon_1.setPixmap(icon_to_pixmap(self.app_icon, 70)) self.labelIcon_2.setPixmap(icon_to_pixmap(self.app_icon, 70)) self.labelIcon_3.setPixmap(icon_to_pixmap(self.app_icon, 120)) self.mdbx = None self.dbx_model = None self.excluded_items = [] # resize dialog buttons width = self.pushButtonAuthPageCancel.width()*1.1 for b in (self.pushButtonAuthPageLink, self.pushButtonDropboxPathUnlink, self.pushButtonDropboxPathSelect, self.pushButtonFolderSelectionBack, self.pushButtonFolderSelectionSelect, self.pushButtonAuthPageCancel, self.pushButtonDropboxPathCalcel, self.pushButtonClose): b.setMinimumWidth(width) b.setMaximumWidth(width) # set up combobox self.dropbox_location = osp.dirname(self._conf.get('main', 'path')) or get_home_dir() relative_path = self.rel_path(self.dropbox_location) folder_icon = get_native_item_icon(self.dropbox_location) self.comboBoxDropboxPath.addItem(folder_icon, relative_path) self.comboBoxDropboxPath.insertSeparator(1) self.comboBoxDropboxPath.addItem(QtGui.QIcon(), 'Other...') self.comboBoxDropboxPath.currentIndexChanged.connect(self.on_combobox) self.dropbox_folder_dialog = QtWidgets.QFileDialog(self) self.dropbox_folder_dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) self.dropbox_folder_dialog.setFileMode(QtWidgets.QFileDialog.Directory) self.dropbox_folder_dialog.setOption(QtWidgets.QFileDialog.ShowDirsOnly, True) self.dropbox_folder_dialog.fileSelected.connect(self.on_new_dbx_folder) self.dropbox_folder_dialog.rejected.connect( lambda: self.comboBoxDropboxPath.setCurrentIndex(0)) # connect buttons to callbacks self.setAttribute(Qt.WA_DeleteOnClose) self.pushButtonLink.clicked.connect(self.on_link) self.pushButtonAuthPageCancel.clicked.connect(self.on_reject_requested) self.pushButtonAuthPageLink.clicked.connect(self.on_auth_clicked) self.pushButtonDropboxPathCalcel.clicked.connect(self.on_reject_requested) self.pushButtonDropboxPathSelect.clicked.connect(self.on_dropbox_location_selected) self.pushButtonDropboxPathUnlink.clicked.connect(self.unlink_and_go_to_start) self.pushButtonFolderSelectionBack.clicked.connect(self.stackedWidget.slideInPrev) self.pushButtonFolderSelectionSelect.clicked.connect(self.on_folders_selected) self.pushButtonClose.clicked.connect(self.on_accept_requested) self.selectAllCheckBox.clicked.connect(self.on_select_all_clicked) default_dir_name = self._conf.get('main', 'default_dir_name') self.labelDropboxPath.setText(self.labelDropboxPath.text().format(default_dir_name)) # check if we are already authenticated, skip authentication if yes if not pending_link: start_maestral_daemon_thread(self._config_name, run=False) self.mdbx = get_maestral_proxy(self._config_name) self.mdbx.get_account_info() self.labelDropboxPath.setText(""" <html><head/><body> <p align="left"> Your Dropbox folder has been moved or deleted from its original location. Maestral will not work properly until you move it back. It used to be located at: </p><p align="left">{0}</p> <p align="left"> To move it back, click "Quit" below, move the Dropbox folder back to its original location, and launch Maestral again. </p> <p align="left"> To re-download your Dropbox, please select a location for your Dropbox folder below. Maestral will create a new folder named "{1}" in the selected location.</p> <p align="left"> To unlink your Dropbox account from Maestral, click "Unlink" below.</p> </body></html> """.format(self._conf.get('main', 'path'), default_dir_name)) self.pushButtonDropboxPathCalcel.setText('Quit') self.stackedWidget.setCurrentIndex(2) self.stackedWidgetButtons.setCurrentIndex(2) else: self.stackedWidget.setCurrentIndex(0) self.stackedWidgetButtons.setCurrentIndex(0)