def __init__(self, nodedir=None, executable=None, reactor=None): if reactor is None: from twisted.internet import reactor self.executable = executable self.multi_folder_support = True if nodedir: self.nodedir = os.path.expanduser(nodedir) else: self.nodedir = os.path.join(os.path.expanduser('~'), '.tahoe') self.rootcap_path = os.path.join(self.nodedir, 'private', 'rootcap') self.servers_yaml_path = os.path.join(self.nodedir, 'private', 'servers.yaml') self.config = Config(os.path.join(self.nodedir, 'tahoe.cfg')) self.pidfile = os.path.join(self.nodedir, 'twistd.pid') self.nodeurl = None self.shares_happy = None self.name = os.path.basename(self.nodedir) self.api_token = None self.magic_folders_dir = os.path.join(self.nodedir, 'magic-folders') self.lock = DeferredLock() self.rootcap = None self.magic_folders = defaultdict(dict) self.remote_magic_folders = defaultdict(dict) self.use_tor = False self.monitor = Monitor(self) streamedlogs_maxlen = None debug_settings = global_settings.get('debug') if debug_settings: log_maxlen = debug_settings.get('log_maxlen') if log_maxlen is not None: streamedlogs_maxlen = int(log_maxlen) self.streamedlogs = StreamedLogs(reactor, streamedlogs_maxlen) self.state = Tahoe.STOPPED self.newscap = "" self.newscap_checker = NewscapChecker(self)
def show_message(): message_settings = settings.get("message") if not message_settings: return if get_preference("message", "suppress") == "true": return logging.debug("Showing custom message to user...") msgbox = QMessageBox() icon_type = message_settings.get("type") if icon_type: icon_type = icon_type.lower() if icon_type == "information": msgbox.setIcon(QMessageBox.Information) elif icon_type == "warning": msgbox.setIcon(QMessageBox.Warning) elif icon_type == "critical": msgbox.setIcon(QMessageBox.Critical) if sys.platform == "darwin": msgbox.setText(message_settings.get("title")) msgbox.setInformativeText(message_settings.get("text")) else: msgbox.setWindowTitle(message_settings.get("title")) msgbox.setText(message_settings.get("text")) checkbox = QCheckBox("Do not show this message again") checkbox.stateChanged.connect(lambda state: set_preference( "message", "suppress", ("true" if state else "false"))) msgbox.setCheckBox(checkbox) msgbox.exec_() logging.debug("Custom message closed; proceeding with start...")
def show_message(): message_settings = settings.get('message') if not message_settings: return if get_preference('message', 'suppress') == 'true': return logging.debug("Showing custom message to user...") msgbox = QMessageBox() icon_type = message_settings.get('type') if icon_type: icon_type = icon_type.lower() if icon_type == 'information': msgbox.setIcon(QMessageBox.Information) elif icon_type == 'warning': msgbox.setIcon(QMessageBox.Warning) elif icon_type == 'critical': msgbox.setIcon(QMessageBox.Critical) if sys.platform == 'darwin': msgbox.setText(message_settings.get('title')) msgbox.setInformativeText(message_settings.get('text')) else: msgbox.setWindowTitle(message_settings.get('title')) msgbox.setText(message_settings.get('text')) checkbox = QCheckBox("Do not show this message again") checkbox.stateChanged.connect(lambda state: set_preference( 'message', 'suppress', ('true' if state else 'false'))) msgbox.setCheckBox(checkbox) msgbox.exec_() logging.debug("Custom message closed; proceeding with start...")
def load_newscap(self): news_settings = global_settings.get('news:{}'.format(self.name)) if news_settings: newscap = news_settings.get('newscap') if newscap: self.newscap = newscap return newscap = self.read_cap_from_file( os.path.join(self.nodedir, 'private', 'newscap')) if newscap: self.newscap = newscap
def load_newscap(self): news_settings = global_settings.get("news:{}".format(self.name)) if news_settings: newscap = news_settings.get("newscap") if newscap: self.newscap = newscap return newscap = self.read_cap_from_file( os.path.join(self.nodedir, "private", "newscap")) if newscap: self.newscap = newscap
def __init__(self, args): self.args = args self.gui = None self.gateways = [] self.executable = None self.tahoe_version = None self.operations = [] log_deque_maxlen = 100000 # XXX debug_settings = settings.get("debug") if debug_settings: log_maxlen = debug_settings.get("log_maxlen") if log_maxlen is not None: log_deque_maxlen = int(log_maxlen) self.log_deque = collections.deque(maxlen=log_deque_maxlen)
def __init__(self, gui, show_open_action=True): super(Menu, self).__init__() self.gui = gui self.about_msg = QMessageBox() self.about_msg.setWindowTitle("{} - About".format(APP_NAME)) app_icon = QIcon(resource(settings["application"]["tray_icon"])) self.about_msg.setIconPixmap(app_icon.pixmap(64, 64)) self.about_msg.setText("{} {}".format(APP_NAME, __version__)) self.about_msg.setWindowModality(Qt.WindowModal) if show_open_action: open_action = QAction(QIcon(""), "Open {}".format(APP_NAME), self) open_action.triggered.connect(self.gui.show) self.addAction(open_action) self.addSeparator() preferences_action = QAction(QIcon(""), "Preferences...", self) preferences_action.triggered.connect(self.gui.show_preferences_window) self.addAction(preferences_action) help_menu = QMenu(self) help_menu.setTitle("Help") help_settings = settings.get("help") if help_settings: if help_settings.get("docs_url"): docs_action = QAction(QIcon(""), "Browse Documentation...", self) docs_action.triggered.connect( lambda: webbrowser.open(settings["help"]["docs_url"])) help_menu.addAction(docs_action) if help_settings.get("issues_url"): issue_action = QAction(QIcon(""), "Report Issue...", self) issue_action.triggered.connect( lambda: webbrowser.open(settings["help"]["issues_url"])) help_menu.addAction(issue_action) export_action = QAction(QIcon(""), "Export Debug Information...", self) export_action.triggered.connect(self.gui.show_debug_exporter) help_menu.addAction(export_action) help_menu.addSeparator() about_action = QAction(QIcon(""), "About {}...".format(APP_NAME), self) about_action.triggered.connect(self.about_msg.exec_) help_menu.addAction(about_action) self.addMenu(help_menu) self.addSeparator() quit_action = QAction(QIcon(""), "&Quit {}".format(APP_NAME), self) quit_action.triggered.connect(self.gui.main_window.confirm_quit) self.addAction(quit_action)
def get_tor(reactor): # TODO: Add launch option? tor = None features_settings = settings.get("features") if features_settings: tor_setting = features_settings.get("tor") if tor_setting and tor_setting.lower() == "false": return tor logging.debug("Looking for a running Tor daemon...") try: tor = yield txtorcon.connect(reactor) except RuntimeError: logging.debug("Could not connect to a running Tor daemon.") if tor: logging.debug("Connected to Tor daemon (%s)", tor.version) return tor
def populate(self): self.clear() logging.debug("(Re-)populating systray menu...") open_action = QAction(QIcon(''), "Open {}".format(APP_NAME), self) open_action.triggered.connect(self.gui.show) self.addAction(open_action) gateways = self.gui.main_window.gateways if gateways and len(gateways) > 1: self.export_menu = QMenu(self) self.export_menu.setTitle("Export Recovery Key") for gateway in gateways: self._add_export_action(gateway) self.addMenu(self.export_menu) elif gateways: export_action = QAction(QIcon(''), "Export Recovery Key...", self) export_action.triggered.connect( self.gui.main_window.export_recovery_key) self.addAction(export_action) help_menu = QMenu(self) help_menu.setTitle("Help") help_settings = settings.get('help') if help_settings: if help_settings.get('docs_url'): docs_action = QAction(QIcon(''), "Browse Documentation...", self) docs_action.triggered.connect(open_documentation) help_menu.addAction(docs_action) if help_settings.get('issues_url'): issue_action = QAction(QIcon(''), "Report Issue...", self) issue_action.triggered.connect(open_issue) help_menu.addAction(issue_action) help_menu.addSeparator() about_action = QAction(QIcon(''), "About {}...".format(APP_NAME), self) about_action.triggered.connect(self.about_msg.exec_) help_menu.addAction(about_action) self.addMenu(help_menu) self.addSeparator() quit_action = QAction(QIcon(''), "&Quit {}".format(APP_NAME), self) quit_action.triggered.connect(self.gui.main_window.confirm_quit) self.addAction(quit_action)
def __init__(self, gateway): super().__init__() self.gateway = gateway self._started = False self.check_delay_min = 30 self.check_delay_max = 60 * 60 * 24 # 24 hours newscap_settings = settings.get("news:{}".format(self.gateway.name)) if newscap_settings: check_delay_min = newscap_settings.get("check_delay_min") if check_delay_min: self.check_delay_min = int(check_delay_min) check_delay_max = newscap_settings.get("check_delay_max") if check_delay_max: self.check_delay_max = int(check_delay_max) if self.check_delay_max < self.check_delay_min: self.check_delay_max = self.check_delay_min self._last_checked_path = os.path.join(self.gateway.nodedir, "private", "newscap.last_checked")
def populate(self): self.clear() logging.debug("(Re-)populating systray menu...") open_action = QAction(QIcon(''), "Open {}".format(APP_NAME), self) open_action.triggered.connect(self.gui.show) self.addAction(open_action) self.addSeparator() preferences_action = QAction(QIcon(''), "Preferences...", self) preferences_action.triggered.connect(self.gui.show_preferences_window) self.addAction(preferences_action) help_menu = QMenu(self) help_menu.setTitle("Help") help_settings = settings.get('help') if help_settings: if help_settings.get('docs_url'): docs_action = QAction(QIcon(''), "Browse Documentation...", self) docs_action.triggered.connect(open_documentation) help_menu.addAction(docs_action) if help_settings.get('issues_url'): issue_action = QAction(QIcon(''), "Report Issue...", self) issue_action.triggered.connect(open_issue) help_menu.addAction(issue_action) help_menu.addSeparator() about_action = QAction(QIcon(''), "About {}...".format(APP_NAME), self) about_action.triggered.connect(self.about_msg.exec_) help_menu.addAction(about_action) self.addMenu(help_menu) self.addSeparator() quit_action = QAction(QIcon(''), "&Quit {}".format(APP_NAME), self) quit_action.triggered.connect(self.gui.main_window.confirm_quit) self.addAction(quit_action)
def on_right_click(self, position): # noqa: max-complexity if not position: # From left-click on "Action" button position = self.viewport().mapFromGlobal(QCursor().pos()) self.deselect_remote_folders() self.deselect_local_folders() cur_item = self.model().itemFromIndex(self.indexAt(position)) if not cur_item: return cur_folder = self.model().item(cur_item.row(), 0).text() if self.gateway.magic_folders.get(cur_folder): # is local folder selection_is_remote = False self.deselect_remote_folders() else: selection_is_remote = True self.deselect_local_folders() selected = self.get_selected_folders() if not selected: selected = [cur_folder] menu = QMenu() if selection_is_remote: download_action = QAction(QIcon(resource("download.png")), "Download...") download_action.triggered.connect( lambda: self.select_download_location(selected)) menu.addAction(download_action) menu.addSeparator() open_action = QAction(self.model().icon_folder_gray, "Open") open_action.triggered.connect(lambda: self.open_folders(selected)) share_menu = QMenu() share_menu.setIcon(QIcon(resource("laptop.png"))) share_menu.setTitle("Sync with device") # XXX Rephrase? invite_action = QAction(QIcon(resource("invite.png")), "Create Invite Code...") invite_action.triggered.connect( lambda: self.open_invite_sender_dialog(selected)) share_menu.addAction(invite_action) remove_action = QAction(QIcon(resource("close.png")), "Remove from Recovery Key...") menu.addAction(open_action) features_settings = settings.get("features") if features_settings: invites_setting = features_settings.get("invites") if invites_setting and invites_setting.lower() != "false": menu.addMenu(share_menu) else: menu.addMenu(share_menu) menu.addSeparator() menu.addAction(remove_action) if selection_is_remote: open_action.setEnabled(False) share_menu.setEnabled(False) remove_action.triggered.connect( lambda: self.confirm_unlink(selected)) else: for folder in selected: if not self.gateway.magic_folders[folder]["admin_dircap"]: share_menu.setEnabled(False) share_menu.setTitle( "Sync with device (disabled; no admin access)") remove_action.setText("Stop syncing...") remove_action.triggered.connect( lambda: self.confirm_stop_syncing(selected)) menu.exec_(self.viewport().mapToGlobal(position))
def __init__(self, gui): # noqa: max-complexity super().__init__() self.gui = gui self.gateways = [] self.welcome_dialog = None self.recovery_key_exporter = None self.setWindowTitle(APP_NAME) self.setMinimumSize(QSize(600, 400)) self.setUnifiedTitleAndToolBarOnMac(True) self.setContextMenuPolicy(Qt.NoContextMenu) if sys.platform == "darwin": # To disable the broken/buggy "full screen" mode on macOS. # See https://github.com/gridsync/gridsync/issues/241 self.setWindowFlags(Qt.Dialog) grid_invites_enabled = True invites_enabled = True multiple_grids_enabled = True features_settings = settings.get("features") if features_settings: grid_invites = features_settings.get("grid_invites") if grid_invites and grid_invites.lower() == "false": grid_invites_enabled = False invites = features_settings.get("invites") if invites and invites.lower() == "false": invites_enabled = False multiple_grids = features_settings.get("multiple_grids") if multiple_grids and multiple_grids.lower() == "false": multiple_grids_enabled = False if multiple_grids_enabled: self.shortcut_new = QShortcut(QKeySequence.New, self) self.shortcut_new.activated.connect(self.show_welcome_dialog) self.shortcut_open = QShortcut(QKeySequence.Open, self) self.shortcut_open.activated.connect(self.select_folder) self.shortcut_preferences = QShortcut(QKeySequence.Preferences, self) self.shortcut_preferences.activated.connect( self.gui.show_preferences_window) 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.confirm_quit) self.central_widget = CentralWidget(self.gui) self.setCentralWidget(self.central_widget) font = Font(8) folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir)) folder_icon_composite = CompositePixmap( folder_icon_default.pixmap(256, 256), resource("green-plus.png")) folder_icon = QIcon(folder_icon_composite) folder_action = QAction(folder_icon, "Add Folder", self) folder_action.setToolTip("Add a Folder...") folder_action.setFont(font) folder_action.triggered.connect(self.select_folder) if grid_invites_enabled: invites_action = QAction(QIcon(resource("invite.png")), "Invites", self) invites_action.setToolTip("Enter or Create an Invite Code") invites_action.setFont(font) enter_invite_action = QAction(QIcon(), "Enter Invite Code...", self) enter_invite_action.setToolTip("Enter an Invite Code...") enter_invite_action.triggered.connect(self.open_invite_receiver) create_invite_action = QAction(QIcon(), "Create Invite Code...", self) create_invite_action.setToolTip("Create on Invite Code...") create_invite_action.triggered.connect( self.open_invite_sender_dialog) invites_menu = QMenu(self) invites_menu.addAction(enter_invite_action) invites_menu.addAction(create_invite_action) invites_button = QToolButton(self) invites_button.setDefaultAction(invites_action) invites_button.setMenu(invites_menu) invites_button.setPopupMode(2) invites_button.setStyleSheet( "QToolButton::menu-indicator { image: none }") invites_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) elif invites_enabled: invite_action = QAction(QIcon(resource("invite.png")), "Enter Code", self) invite_action.setToolTip("Enter an Invite Code...") invite_action.setFont(font) invite_action.triggered.connect(self.open_invite_receiver) spacer_left = QWidget() spacer_left.setSizePolicy(QSizePolicy.Expanding, 0) self.combo_box = ComboBox() self.combo_box.currentIndexChanged.connect(self.on_grid_selected) if not multiple_grids_enabled: self.combo_box.hide() spacer_right = QWidget() spacer_right.setSizePolicy(QSizePolicy.Expanding, 0) history_action = QAction(QIcon(resource("time.png")), "History", self) history_action.setToolTip("Show/Hide History") history_action.setFont(font) history_action.triggered.connect(self.on_history_button_clicked) self.history_button = QToolButton(self) self.history_button.setDefaultAction(history_action) self.history_button.setCheckable(True) self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) recovery_action = QAction(QIcon(resource("key.png")), "Recovery", self) recovery_action.setToolTip("Import or Export a Recovery Key") recovery_action.setFont(font) import_action = QAction(QIcon(), "Import Recovery Key...", self) import_action.setToolTip("Import Recovery Key...") import_action.triggered.connect(self.import_recovery_key) export_action = QAction(QIcon(), "Export Recovery Key...", self) export_action.setToolTip("Export Recovery Key...") export_action.setShortcut(QKeySequence.Save) export_action.triggered.connect(self.export_recovery_key) recovery_menu = QMenu(self) recovery_menu.addAction(import_action) recovery_menu.addAction(export_action) recovery_button = QToolButton(self) recovery_button.setDefaultAction(recovery_action) recovery_button.setMenu(recovery_menu) recovery_button.setPopupMode(2) recovery_button.setStyleSheet( "QToolButton::menu-indicator { image: none }") recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar = self.addToolBar("") p = self.palette() dimmer_grey = BlendedColor(p.windowText().color(), p.window().color(), 0.7).name() if sys.platform != "darwin": self.toolbar.setStyleSheet(""" QToolBar {{ border: 0px }} QToolButton {{ color: {} }} """.format(dimmer_grey)) else: self.toolbar.setStyleSheet( "QToolButton {{ color: {} }}".format(dimmer_grey)) self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar.setIconSize(QSize(24, 24)) self.toolbar.setMovable(False) self.toolbar.addAction(folder_action) if grid_invites_enabled: self.toolbar.addWidget(invites_button) elif invites_enabled: self.toolbar.addAction(invite_action) self.toolbar.addWidget(spacer_left) self.toolbar.addWidget(self.combo_box) self.toolbar.addWidget(spacer_right) self.toolbar.addWidget(self.history_button) self.toolbar.addWidget(recovery_button) if sys.platform != "win32": # Text is getting clipped on Windows 10 for action in self.toolbar.actions(): widget = self.toolbar.widgetForAction(action) if isinstance(widget, QToolButton): widget.setMaximumWidth(68) self.active_invite_sender_dialogs = [] self.active_invite_receiver_dialogs = [] self.pending_news_message = ()
def __init__(self, gui): super(MainWindow, self).__init__() self.gui = gui self.gateways = [] self.welcome_dialog = None self.recovery_key_exporter = None self.setWindowTitle(APP_NAME) self.setMinimumSize(QSize(600, 400)) self.setUnifiedTitleAndToolBarOnMac(True) self.shortcut_new = QShortcut(QKeySequence.New, self) self.shortcut_new.activated.connect(self.show_welcome_dialog) self.shortcut_open = QShortcut(QKeySequence.Open, self) self.shortcut_open.activated.connect(self.select_folder) self.shortcut_preferences = QShortcut(QKeySequence.Preferences, self) self.shortcut_preferences.activated.connect( self.gui.show_preferences_window) 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.confirm_quit) self.central_widget = CentralWidget(self.gui) self.setCentralWidget(self.central_widget) font = QFont() if sys.platform == 'darwin': font.setPointSize(11) else: font.setPointSize(8) folder_icon_default = QFileIconProvider().icon(QFileInfo(config_dir)) folder_icon_composite = CompositePixmap( folder_icon_default.pixmap(256, 256), resource('green-plus.png')) folder_icon = QIcon(folder_icon_composite) folder_action = QAction(folder_icon, "Add Folder", self) folder_action.setToolTip("Add a Folder...") folder_action.setFont(font) folder_action.triggered.connect(self.select_folder) grid_invites_enabled = True features_settings = settings.get('features') if features_settings: grid_invites = features_settings.get('grid_invites') if grid_invites and grid_invites.lower() == 'false': grid_invites_enabled = False if grid_invites_enabled: invites_action = QAction(QIcon(resource('invite.png')), "Invites", self) invites_action.setToolTip("Enter or Create an Invite Code") invites_action.setFont(font) enter_invite_action = QAction(QIcon(), "Enter Invite Code...", self) enter_invite_action.setToolTip("Enter an Invite Code...") enter_invite_action.triggered.connect(self.open_invite_receiver) create_invite_action = QAction(QIcon(), "Create Invite Code...", self) create_invite_action.setToolTip("Create on Invite Code...") create_invite_action.triggered.connect( self.open_invite_sender_dialog) invites_menu = QMenu(self) invites_menu.addAction(enter_invite_action) invites_menu.addAction(create_invite_action) invites_button = QToolButton(self) invites_button.setDefaultAction(invites_action) invites_button.setMenu(invites_menu) invites_button.setPopupMode(2) invites_button.setStyleSheet( 'QToolButton::menu-indicator { image: none }') invites_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) else: invite_action = QAction(QIcon(resource('invite.png')), "Enter Code", self) invite_action.setToolTip("Enter an Invite Code...") invite_action.setFont(font) invite_action.triggered.connect(self.open_invite_receiver) spacer_left = QWidget() spacer_left.setSizePolicy(QSizePolicy.Expanding, 0) self.combo_box = ComboBox() self.combo_box.currentIndexChanged.connect(self.on_grid_selected) spacer_right = QWidget() spacer_right.setSizePolicy(QSizePolicy.Expanding, 0) history_action = QAction(QIcon(resource('time.png')), 'History', self) history_action.setToolTip("Show/Hide History") history_action.setFont(font) history_action.triggered.connect(self.on_history_button_clicked) self.history_button = QToolButton(self) self.history_button.setDefaultAction(history_action) self.history_button.setCheckable(True) self.history_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) recovery_action = QAction(QIcon(resource('key.png')), "Recovery", self) recovery_action.setToolTip("Import or Export a Recovery Key") recovery_action.setFont(font) import_action = QAction(QIcon(), "Import Recovery Key...", self) import_action.setToolTip("Import Recovery Key...") import_action.triggered.connect(self.import_recovery_key) export_action = QAction(QIcon(), "Export Recovery Key...", self) export_action.setToolTip("Export Recovery Key...") export_action.setShortcut(QKeySequence.Save) export_action.triggered.connect(self.export_recovery_key) recovery_menu = QMenu(self) recovery_menu.addAction(import_action) recovery_menu.addAction(export_action) recovery_button = QToolButton(self) recovery_button.setDefaultAction(recovery_action) recovery_button.setMenu(recovery_menu) recovery_button.setPopupMode(2) recovery_button.setStyleSheet( 'QToolButton::menu-indicator { image: none }') recovery_button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar = self.addToolBar('') if sys.platform != 'darwin': self.toolbar.setStyleSheet(""" QToolBar { border: 0px } QToolButton { color: rgb(50, 50, 50) } """) else: self.toolbar.setStyleSheet( "QToolButton { color: rgb(50, 50, 50) }") self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.toolbar.setIconSize(QSize(24, 24)) self.toolbar.setMovable(False) self.toolbar.addAction(folder_action) if grid_invites_enabled: self.toolbar.addWidget(invites_button) else: self.toolbar.addAction(invite_action) self.toolbar.addWidget(spacer_left) self.toolbar.addWidget(self.combo_box) self.toolbar.addWidget(spacer_right) self.toolbar.addWidget(self.history_button) self.toolbar.addWidget(recovery_button) if sys.platform != 'win32': # Text is getting clipped on Windows 10 for action in self.toolbar.actions(): widget = self.toolbar.widgetForAction(action) if isinstance(widget, QToolButton): widget.setMaximumWidth(68) self.active_invite_sender_dialogs = [] self.active_invite_receiver_dialogs = []