Ejemplo n.º 1
0
    def __init__(self):
        component.Component.__init__(self, "ToolBar")
        log.debug("ToolBar Init..")
        self.window = component.get("MainWindow")
        self.toolbar = self.window.main_glade.get_widget("toolbar")
        self.config = ConfigManager("gtkui.conf")
        ### Connect Signals ###
        self.window.main_glade.signal_autoconnect({
            "on_toolbutton_add_clicked": self.on_toolbutton_add_clicked,
            "on_toolbutton_remove_clicked": self.on_toolbutton_remove_clicked,
            "on_toolbutton_pause_clicked": self.on_toolbutton_pause_clicked,
            "on_toolbutton_resume_clicked": self.on_toolbutton_resume_clicked,
            "on_toolbutton_preferences_clicked": \
                self.on_toolbutton_preferences_clicked,
            "on_toolbutton_connectionmanager_clicked": \
                self.on_toolbutton_connectionmanager_clicked,
            "on_toolbutton_queue_up_clicked": self.on_toolbutton_queue_up_clicked,
            "on_toolbutton_queue_down_clicked": self.on_toolbutton_queue_down_clicked
        })
        self.change_sensitivity = [
            "toolbutton_add", "toolbutton_remove", "toolbutton_pause",
            "toolbutton_resume", "toolbutton_queue_up",
            "toolbutton_queue_down", "toolbutton_filter", "find_menuitem"
        ]

        self.config.register_set_function("classic_mode",
                                          self._on_classic_mode, True)

        # Hide if necessary
        self.visible(self.config["show_toolbar"])
Ejemplo n.º 2
0
    def __init__(self):
        component.Component.__init__(self, "ConnectionManager")
        self.gtkui_config = ConfigManager("gtkui.conf")

        self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)

        self.running = False
Ejemplo n.º 3
0
    def __init__(self):
        component.Component.__init__(self, 'SystemTray', interval=4)
        self.mainwindow = component.get('MainWindow')
        self.config = ConfigManager('gtk3ui.conf')
        # List of widgets that need to be hidden when not connected to a host
        self.hide_widget_list = [
            'menuitem_add_torrent',
            'menuitem_pause_session',
            'menuitem_resume_session',
            'menuitem_download_limit',
            'menuitem_upload_limit',
            'menuitem_quitdaemon',
            'separatormenuitem1',
            'separatormenuitem2',
            'separatormenuitem3',
            'separatormenuitem4',
        ]
        self.config.register_set_function('enable_system_tray',
                                          self.on_enable_system_tray_set)
        # bit of a hack to prevent function from doing something on startup
        self.__enabled_set_once = False
        self.config.register_set_function('enable_appindicator',
                                          self.on_enable_appindicator_set)

        self.max_download_speed = -1.0
        self.download_rate = 0.0
        self.max_upload_speed = -1.0
        self.upload_rate = 0.0

        self.config_value_changed_dict = {
            'max_download_speed': self._on_max_download_speed,
            'max_upload_speed': self._on_max_upload_speed,
        }
Ejemplo n.º 4
0
    def enable(self):
        log.info("*** Start Label plugin ***")
        self.plugin = component.get("CorePluginManager")
        self.plugin.register_status_field("label", self._status_get_label)

        #__init__
        core = component.get("Core")
        self.config = ConfigManager("label.conf", defaults=CONFIG_DEFAULTS)
        self.core_cfg = ConfigManager("core.conf")

        #reduce typing, assigning some values to self...
        self.torrents = core.torrentmanager.torrents
        self.labels = self.config["labels"]
        self.torrent_labels = self.config["torrent_labels"]

        self.clean_initial_config()

        component.get("EventManager").register_event_handler(
            "TorrentAddedEvent", self.post_torrent_add)
        component.get("EventManager").register_event_handler(
            "TorrentRemovedEvent", self.post_torrent_remove)

        #register tree:
        component.get("FilterManager").register_tree_field(
            "label", self.init_filter_dict)

        log.debug("Label plugin enabled..")
Ejemplo n.º 5
0
Archivo: core.py Proyecto: zluca/deluge
    def enable(self):
        self.config = ConfigManager('execute.conf', DEFAULT_CONFIG)
        event_manager = component.get('EventManager')
        self.registered_events = {}
        self.preremoved_cache = {}

        # Go through the commands list and register event handlers
        for command in self.config['commands']:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id, *arg):
                    self.execute_commands(torrent_id, event, *arg)

                return event_handler

            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event],
                                                 event_handler)
            if event == 'removed':
                event_manager.register_event_handler('PreTorrentRemovedEvent',
                                                     self.on_preremoved)
            self.registered_events[event] = event_handler

        log.debug('Execute core plugin enabled!')
Ejemplo n.º 6
0
    def enable(self):
        self.config = ConfigManager("execute.conf", DEFAULT_CONFIG)
        event_manager = component.get("EventManager")
        self.registered_events = {}
        self.preremoved_cache = {}

        # Go through the commands list and register event handlers
        for command in self.config["commands"]:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id, *arg):
                    #log.debug("Bleh %s", *arg)
                    #log.debug("Bleh %s", arg)
                    self.execute_commands(torrent_id, event, *arg)

                return event_handler

            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event],
                                                 event_handler)
            if event == "removed":
                event_manager.register_event_handler("PreTorrentRemovedEvent",
                                                     self.on_preremoved)
            self.registered_events[event] = event_handler

        log.debug("Execute core plugin enabled!")
Ejemplo n.º 7
0
    def enable(self):
        log.info('*** Start Label plugin ***')
        self.plugin = component.get('CorePluginManager')
        self.plugin.register_status_field('label', self._status_get_label)

        # __init__
        core = component.get('Core')
        self.config = ConfigManager('label.conf', defaults=CONFIG_DEFAULTS)
        self.core_cfg = ConfigManager('core.conf')

        # reduce typing, assigning some values to self...
        self.torrents = core.torrentmanager.torrents
        self.labels = self.config['labels']
        self.torrent_labels = self.config['torrent_labels']

        self.clean_initial_config()

        component.get('EventManager').register_event_handler(
            'TorrentAddedEvent', self.post_torrent_add
        )
        component.get('EventManager').register_event_handler(
            'TorrentRemovedEvent', self.post_torrent_remove
        )

        # register tree:
        component.get('FilterManager').register_tree_field(
            'label', self.init_filter_dict
        )

        log.debug('Label plugin enabled..')
Ejemplo n.º 8
0
    def __init__(self):
        component.Component.__init__(self, "SystemTray", interval=4)
        self.window = component.get("MainWindow")
        self.config = ConfigManager("gtkui.conf")
        # List of widgets that need to be hidden when not connected to a host
        self.hide_widget_list = [
            "menuitem_add_torrent", "menuitem_pause_all",
            "menuitem_resume_all", "menuitem_download_limit",
            "menuitem_upload_limit", "menuitem_quitdaemon",
            "separatormenuitem1", "separatormenuitem2", "separatormenuitem3",
            "separatormenuitem4"
        ]
        self.config.register_set_function("enable_system_tray",
                                          self.on_enable_system_tray_set)
        # bit of a hack to prevent function from doing something on startup
        self.__enabled_set_once = False
        self.config.register_set_function("enable_appindicator",
                                          self.on_enable_appindicator_set)

        self.max_download_speed = -1.0
        self.download_rate = 0.0
        self.max_upload_speed = -1.0
        self.upload_rate = 0.0

        self.config_value_changed_dict = {
            "max_download_speed": self._on_max_download_speed,
            "max_upload_speed": self._on_max_upload_speed
        }
Ejemplo n.º 9
0
 def __init__(self, stdscr, encoding=None):
     self.popup = None
     self.statuses = {}
     self.messages = deque()
     self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
     BaseMode.__init__(self, stdscr, encoding)
     self.__update_statuses()
     self.__update_popup()
Ejemplo n.º 10
0
class AutoAdd(component.Component):
    def __init__(self):
        component.Component.__init__(self, "AutoAdd", depend=["TorrentManager"], interval=5)
        # Get the core config
        self.config = ConfigManager("core.conf")

        # A list of filenames
        self.invalid_torrents = []
        # Filename:Attempts
        self.attempts = {}

        # Register set functions
        self.config.register_set_function("autoadd_enable",
            self._on_autoadd_enable, apply_now=True)
        self.config.register_set_function("autoadd_location",
            self._on_autoadd_location)

    def update(self):
        if not self.config["autoadd_enable"]:
            # We shouldn't be updating because autoadd is not enabled
            component.pause("AutoAdd")
            return

        # Check the auto add folder for new torrents to add
        if not os.path.isdir(self.config["autoadd_location"]):
            log.warning("Invalid AutoAdd folder: %s", self.config["autoadd_location"])
            component.pause("AutoAdd")
            return

        for filename in os.listdir(self.config["autoadd_location"]):
            try:
                filepath = os.path.join(self.config["autoadd_location"], filename)
            except UnicodeDecodeError, e:
                log.error("Unable to auto add torrent due to improper filename encoding: %s", e)
                continue
            if os.path.isfile(filepath) and filename.endswith(".torrent"):
                try:
                    filedump = self.load_torrent(filepath)
                except (RuntimeError, Exception), e:
                    # If the torrent is invalid, we keep track of it so that we
                    # can try again on the next pass.  This is because some
                    # torrents may not be fully saved during the pass.
                    log.debug("Torrent is invalid: %s", e)
                    if filename in self.invalid_torrents:
                        self.attempts[filename] += 1
                        if self.attempts[filename] >= MAX_NUM_ATTEMPTS:
                            os.rename(filepath, filepath + ".invalid")
                            del self.attempts[filename]
                            self.invalid_torrents.remove(filename)
                    else:
                        self.invalid_torrents.append(filename)
                        self.attempts[filename] = 1
                    continue

                # The torrent looks good, so lets add it to the session
                component.get("TorrentManager").add(filedump=filedump, filename=filename)

                os.remove(filepath)
Ejemplo n.º 11
0
 def __init__(self):
     super(WebApi, self).__init__("Web", depend=["SessionProxy"])
     self.host_list = ConfigManager("hostlist.conf.1.2", DEFAULT_HOSTS)
     if not os.path.isfile(self.host_list.config_file):
         self.host_list.save()
     self.core_config = CoreConfig()
     self.event_queue = EventQueue()
     try:
         self.sessionproxy = component.get("SessionProxy")
     except KeyError:
         self.sessionproxy = SessionProxy()
Ejemplo n.º 12
0
    def __init__(self):
        if wnck:
            self.screen = wnck.screen_get_default()
        component.Component.__init__(self, 'MainWindow', interval=2)
        self.config = ConfigManager('gtkui.conf')
        self.main_builder = gtk.Builder()

        # Patch this GtkBuilder to avoid connecting signals from elsewhere
        #
        # Think about splitting up  mainwindow gtkbuilder file into the necessary parts
        # to avoid GtkBuilder monkey patch. Those parts would then need adding to mainwindow 'by hand'.
        self.gtk_builder_signals_holder = _GtkBuilderSignalsHolder()
        self.main_builder.prev_connect_signals = copy.deepcopy(self.main_builder.connect_signals)

        def patched_connect_signals(*a, **k):
            raise RuntimeError('In order to connect signals to this GtkBuilder instance please use '
                               '"component.get(\'MainWindow\').connect_signals()"')
        self.main_builder.connect_signals = patched_connect_signals

        # Get Gtk Builder files Main Window, New release dialog, and Tabs.
        for filename in ('main_window.ui', 'main_window.new_release.ui', 'main_window.tabs.ui',
                         'main_window.tabs.menu_file.ui', 'main_window.tabs.menu_peer.ui'):
            self.main_builder.add_from_file(
                resource_filename('deluge.ui.gtkui', os.path.join('glade', filename)))

        self.window = self.main_builder.get_object('main_window')
        self.window.set_icon(deluge.ui.gtkui.common.get_deluge_icon())
        self.vpaned = self.main_builder.get_object('vpaned')
        self.initial_vpaned_position = self.config['window_pane_position']

        # Keep a list of components to pause and resume when changing window state.
        self.child_components = ['TorrentView', 'StatusBar', 'TorrentDetails']

        # Load the window state
        self.load_window_state()

        # Keep track of window minimization state so we don't update UI when it is minimized.
        self.is_minimized = False
        self.restart = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 80)], ACTION_COPY)

        # Connect events
        self.window.connect('window-state-event', self.on_window_state_event)
        self.window.connect('configure-event', self.on_window_configure_event)
        self.window.connect('delete-event', self.on_window_delete_event)
        self.window.connect('drag-data-received', self.on_drag_data_received_event)
        self.vpaned.connect('notify::position', self.on_vpaned_position_event)
        self.window.connect('expose-event', self.on_expose_event)

        self.config.register_set_function('show_rate_in_title', self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler('NewVersionAvailableEvent', self.on_newversionavailable_event)
Ejemplo n.º 13
0
 def get_labels(self, torrent_id):
     labels = []
     label_config = ConfigManager('label.conf', defaults=False)
     if label_config is not False:
         if 'torrent_labels' in label_config:
             if torrent_id in label_config['torrent_labels']:
                 labels.append(label_config['torrent_labels'][torrent_id])
     label_plus_config = ConfigManager('labelplus.conf', defaults=False)
     if label_plus_config is not False:
         if 'mappings' in label_plus_config:
             if torrent_id in label_plus_config['mappings']:
               mapping = label_plus_config['mappings'][torrent_id]
               labels.append(label_plus_config['labels'][mapping]['name'])
     return labels
Ejemplo n.º 14
0
    def __init__(self):
        super(StatusTab, self).__init__('Status', 'status_tab', 'status_tab_label')

        self.config = ConfigManager('gtk3ui.conf')

        self.progressbar = self.main_builder.get_object('progressbar')
        self.piecesbar = None

        self.add_tab_widget('summary_availability', fratio, ('distributed_copies',))
        self.add_tab_widget(
            'summary_total_downloaded',
            ftotal_sized,
            ('all_time_download', 'total_payload_download'),
        )
        self.add_tab_widget(
            'summary_total_uploaded',
            ftotal_sized,
            ('total_uploaded', 'total_payload_upload'),
        )
        self.add_tab_widget(
            'summary_download_speed',
            fspeed_max,
            ('download_payload_rate', 'max_download_speed'),
        )
        self.add_tab_widget(
            'summary_upload_speed',
            fspeed_max,
            ('upload_payload_rate', 'max_upload_speed'),
        )
        self.add_tab_widget('summary_seeds', fpeer, ('num_seeds', 'total_seeds'))
        self.add_tab_widget('summary_peers', fpeer, ('num_peers', 'total_peers'))
        self.add_tab_widget('summary_eta', ftime_or_dash, ('eta',))
        self.add_tab_widget('summary_share_ratio', fratio, ('ratio',))
        self.add_tab_widget('summary_active_time', ftime_or_dash, ('active_time',))
        self.add_tab_widget('summary_seed_time', ftime_or_dash, ('seeding_time',))
        self.add_tab_widget(
            'summary_seed_rank', fseed_rank_or_dash, ('seed_rank', 'seeding_time')
        )
        self.add_tab_widget('progressbar', fpcnt, ('progress', 'state', 'message'))
        self.add_tab_widget(
            'summary_last_seen_complete', fdate_or_never, ('last_seen_complete',)
        )
        self.add_tab_widget(
            'summary_last_transfer', ftime_or_dash, ('time_since_transfer',)
        )

        self.config.register_set_function(
            'show_piecesbar', self.on_show_piecesbar_config_changed, apply_now=True
        )
Ejemplo n.º 15
0
    def __load_config(self):
        auth_file = deluge.configmanager.get_config_dir("auth")
        if not os.path.exists(auth_file):
            from deluge.common import create_localclient_account
            create_localclient_account()

        localclient_username, localclient_password = get_localhost_auth()
        DEFAULT_CONFIG = {
            "hosts":
            [(hashlib.sha1(str(time.time())).hexdigest(), DEFAULT_HOST,
              DEFAULT_PORT, localclient_username, localclient_password)]
        }
        config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
        config.run_converter((0, 1), 2, self.__migrate_config_1_to_2)
        return config
Ejemplo n.º 16
0
    def __init__(self):
        if Wnck:
            self.screen = Wnck.Screen.get_default()
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        # Get the glade file for the main window
        self.main_glade = Gtk.Builder()
        self.main_glade.add_from_file(
            pkg_resources.resource_filename("deluge.ui.gtkui",
                                            "builder/main_window.ui"))

        self.window_signals = {}

        self.window = self.main_glade.get_object("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_glade.get_object("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(
            Gtk.DestDefaults.ALL,
            [Gtk.TargetEntry.new('text/uri-list', 0, 80)], Gdk.DragAction.COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received",
                            self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("draw", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title",
                                          self._on_set_show_rate_in_title,
                                          apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent",
                                      self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent",
                                      self.on_torrentfinished_event)
Ejemplo n.º 17
0
    def __init__(self, parent):
        QtGui.QDialog.__init__(
            self, parent,
            QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint)

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setupUi(self)

        self.ui_config = ConfigManager("qtui.conf")
        self.default_options = {}
        self._selected_item = None

        self.download_location_browse.setVisible(client.is_localhost())

        self.EMPTY_FILE_MODEL = TorrentFileModel([], self)
        self.tree_files.setModel(self.EMPTY_FILE_MODEL)
        header = self.tree_files.header()
        header.setStretchLastSection(False)
        header.setMinimumSectionSize(header.fontMetrics().width("M") * 10)
        header.setResizeMode(0, QtGui.QHeaderView.Stretch)
        header.setResizeMode(
            1, QtGui.QHeaderView.Fixed)  # NB: ResizeToContents is slow

        HeightFixItemDelegate.install(self.tree_files)

        self._update_default_options()
Ejemplo n.º 18
0
    def __init__(self):
        component.Component.__init__(self, "ToolBar")
        log.debug("ToolBar Init..")
        self.window = component.get("MainWindow")
        self.toolbar = self.window.main_glade.get_widget("toolbar")
        self.config = ConfigManager("gtkui.conf")
        ### Connect Signals ###
        self.window.main_glade.signal_autoconnect({
            "on_toolbutton_add_clicked": self.on_toolbutton_add_clicked,
            "on_toolbutton_remove_clicked": self.on_toolbutton_remove_clicked,
            "on_toolbutton_pause_clicked": self.on_toolbutton_pause_clicked,
            "on_toolbutton_resume_clicked": self.on_toolbutton_resume_clicked,
            "on_toolbutton_preferences_clicked": \
                self.on_toolbutton_preferences_clicked,
            "on_toolbutton_connectionmanager_clicked": \
                self.on_toolbutton_connectionmanager_clicked,
            "on_toolbutton_queue_up_clicked": self.on_toolbutton_queue_up_clicked,
            "on_toolbutton_queue_down_clicked": self.on_toolbutton_queue_down_clicked
        })
        self.change_sensitivity = [
            "toolbutton_add",
            "toolbutton_remove",
            "toolbutton_pause",
            "toolbutton_resume",
            "toolbutton_queue_up",
            "toolbutton_queue_down"
        ]

        self.config.register_set_function("classic_mode", self._on_classic_mode, True)

        # Hide if necessary
        self.visible(self.config["show_toolbar"])
Ejemplo n.º 19
0
    def __init__(self):
        super(StatusTab, self).__init__('Status', 'status_tab', 'status_tab_label')

        self.config = ConfigManager('gtkui.conf')

        self.progressbar = self.main_builder.get_object('progressbar')
        self.piecesbar = None

        self.add_tab_widget('summary_availability', fratio, ('distributed_copies',))
        self.add_tab_widget('summary_total_downloaded', ftotal_sized,
                            ('all_time_download', 'total_payload_download'))
        self.add_tab_widget('summary_total_uploaded', ftotal_sized,
                            ('total_uploaded', 'total_payload_upload'))
        self.add_tab_widget('summary_download_speed', fspeed_max,
                            ('download_payload_rate', 'max_download_speed'))
        self.add_tab_widget('summary_upload_speed', fspeed_max,
                            ('upload_payload_rate', 'max_upload_speed'))
        self.add_tab_widget('summary_seeds', fpeer, ('num_seeds', 'total_seeds'))
        self.add_tab_widget('summary_peers', fpeer, ('num_peers', 'total_peers'))
        self.add_tab_widget('summary_eta', ftime_or_dash, ('eta',))
        self.add_tab_widget('summary_share_ratio', fratio, ('ratio',))
        self.add_tab_widget('summary_active_time', ftime_or_dash, ('active_time',))
        self.add_tab_widget('summary_seed_time', ftime_or_dash, ('seeding_time',))
        self.add_tab_widget('summary_seed_rank', fseed_rank_or_dash, ('seed_rank', 'seeding_time'))
        self.add_tab_widget('progressbar', fpcnt, ('progress', 'state', 'message'))
        self.add_tab_widget('summary_last_seen_complete', fdate_or_never, ('last_seen_complete',))
        self.add_tab_widget('summary_last_transfer', ftime_or_dash, ('time_since_transfer',))

        self.config.register_set_function('show_piecesbar', self.on_show_piecesbar_config_changed, apply_now=True)
Ejemplo n.º 20
0
    def __init__(self):
        super(PiecesBar, self).__init__()
        # Get progress bar styles, in order to keep font consistency
        pb = ProgressBar()
        pb_style = pb.get_style_context()
        # Get a copy of Pango.FontDescription since original needs freed.
        self.text_font = pb_style.get_property('font',
                                               StateFlags.NORMAL).copy()
        self.text_font.set_weight(Weight.BOLD)
        # Done with the ProgressBar styles, don't keep refs of it
        del pb, pb_style

        self.set_size_request(-1, 25)
        self.gtkui_config = ConfigManager('gtk3ui.conf')

        self.width = self.prev_width = 0
        self.height = self.prev_height = 0
        self.pieces = self.prev_pieces = ()
        self.num_pieces = None
        self.text = self.prev_text = ''
        self.fraction = self.prev_fraction = 0
        self.progress_overlay = self.text_overlay = self.pieces_overlay = None
        self.cr = None

        self.connect('size-allocate', self.do_size_allocate_event)
        self.show()
Ejemplo n.º 21
0
    def __init__(self):
        component.Component.__init__(self, 'SystemTray', interval=4)
        self.mainwindow = component.get('MainWindow')
        self.config = ConfigManager('gtkui.conf')
        # List of widgets that need to be hidden when not connected to a host
        self.hide_widget_list = [
            'menuitem_add_torrent',
            'menuitem_pause_session',
            'menuitem_resume_session',
            'menuitem_download_limit',
            'menuitem_upload_limit',
            'menuitem_quitdaemon',
            'separatormenuitem1',
            'separatormenuitem2',
            'separatormenuitem3',
            'separatormenuitem4'
        ]
        self.config.register_set_function('enable_system_tray', self.on_enable_system_tray_set)
        # bit of a hack to prevent function from doing something on startup
        self.__enabled_set_once = False
        self.config.register_set_function('enable_appindicator', self.on_enable_appindicator_set)

        self.max_download_speed = -1.0
        self.download_rate = 0.0
        self.max_upload_speed = -1.0
        self.upload_rate = 0.0

        self.config_value_changed_dict = {
            'max_download_speed': self._on_max_download_speed,
            'max_upload_speed': self._on_max_upload_speed
        }
Ejemplo n.º 22
0
    def __init__(self):
        gtk.DrawingArea.__init__(self)
        # Get progress bar styles, in order to keep font consistency
        pb = gtk.ProgressBar()
        pb_style = pb.get_style()
        self.__text_font = pb_style.font_desc
        self.__text_font.set_weight(pango.WEIGHT_BOLD)
        # Done with the ProgressBar styles, don't keep refs of it
        del pb, pb_style

        self.set_size_request(-1, 25)
        self.gtkui_config = ConfigManager("gtkui.conf")
        self.__width = self.__old_width = 0
        self.__height = self.__old_height = 0
        self.__pieces = self.__old_pieces = ()
        self.__num_pieces = self.__old_num_pieces = None
        self.__text = self.__old_text = ""
        self.__fraction = self.__old_fraction = 0.0
        self.__state = self.__old_state = None
        self.__progress_overlay = self.__text_overlay = self.__pieces_overlay = None
        self.__cr = None

        self.connect('size-allocate', self.do_size_allocate_event)
        self.set_colormap(self.get_screen().get_rgba_colormap())
        self.show()
Ejemplo n.º 23
0
    def __init__(self):
        super(PiecesBar, self).__init__()
        # Get progress bar styles, in order to keep font consistency
        pb = ProgressBar()
        pb_style = pb.get_style()
        self.text_font = pb_style.font_desc
        self.text_font.set_weight(WEIGHT_BOLD)
        # Done with the ProgressBar styles, don't keep refs of it
        del pb, pb_style

        self.set_size_request(-1, 25)
        self.gtkui_config = ConfigManager('gtkui.conf')

        self.width = self.prev_width = 0
        self.height = self.prev_height = 0
        self.pieces = self.prev_pieces = ()
        self.num_pieces = None
        self.text = self.prev_text = ''
        self.fraction = self.prev_fraction = 0
        self.progress_overlay = self.text_overlay = self.pieces_overlay = None
        self.cr = None

        self.connect('size-allocate', self.do_size_allocate_event)
        self.set_colormap(colormap_get_system())
        self.show()
Ejemplo n.º 24
0
    def update_config(self):
        self.config = ConfigManager("console.conf",DEFAULT_PREFS)
        s_primary = self.config["sort_primary"]
        s_secondary = self.config["sort_secondary"]
        self.__cols_to_show = [
            pref for pref in column_pref_names
                if ("show_%s" % pref) not in self.config
                or self.config["show_%s"%pref]
        ]

        self.__columns = [prefs_to_names[col] for col in self.__cols_to_show]
        self.__status_fields = column.get_required_fields(self.__columns)

        # we always need these, even if we're not displaying them
        for rf in ["state", "name", "queue", "progress"]:
            if rf not in self.__status_fields:
                self.__status_fields.append(rf)

        # same with sort keys
        if s_primary and (s_primary not in self.__status_fields):
            self.__status_fields.append(s_primary)
        if s_secondary and (s_secondary not in self.__status_fields):
            self.__status_fields.append(s_secondary)

        self.__update_columns()
Ejemplo n.º 25
0
    def show(self, available_version):
        self.config = ConfigManager("gtkui.conf")
        glade = component.get("MainWindow").main_glade
        self.dialog = glade.get_object("new_release_dialog")
        # Set the version labels
        if deluge.common.windows_check() or deluge.common.osx_check():
            glade.get_object("image_new_release").set_from_file(
                deluge.common.get_pixmap("deluge16.png"))
        else:
            glade.get_object("image_new_release").set_from_icon_name(
                "deluge", 4)
        glade.get_object("label_available_version").set_text(available_version)
        glade.get_object("label_client_version").set_text(
            deluge.common.get_version())
        self.chk_not_show_dialog = glade.get_object(
            "chk_do_not_show_new_release")
        glade.get_object("button_goto_downloads").connect(
            "clicked", self._on_button_goto_downloads)
        glade.get_object("button_close_new_release").connect(
            "clicked", self._on_button_close_new_release)

        if client.connected():

            def on_info(version):
                glade.get_object("label_server_version").set_text(version)
                glade.get_object("label_server_version").show()
                glade.get_object("label_server_version_text").show()

            if not client.is_classicmode():
                glade.get_object("label_client_version_text").set_label(
                    _("<i>Client Version</i>"))
                client.daemon.info().addCallback(on_info)

        self.dialog.show()
Ejemplo n.º 26
0
    def __init__(self):
        component.Component.__init__(self, "ToolBar")
        log.debug("ToolBar Init..")
        self.window = component.get("MainWindow")
        self.toolbar = self.window.main_glade.get_object("toolbar")
        self.config = ConfigManager("gtkui.conf")
        ### Connect Signals ###
        self.window.insert_signals({
            "on_toolbutton_add_clicked": self.on_toolbutton_add_clicked,
            "on_toolbutton_remove_clicked": self.on_toolbutton_remove_clicked,
            "on_toolbutton_pause_clicked": self.on_toolbutton_pause_clicked,
            "on_toolbutton_resume_clicked": self.on_toolbutton_resume_clicked,
            "on_toolbutton_preferences_clicked": \
                self.on_toolbutton_preferences_clicked,
            "on_toolbutton_connectionmanager_clicked": \
                self.on_toolbutton_connectionmanager_clicked,
            "on_toolbutton_queue_up_clicked": self.on_toolbutton_queue_up_clicked,
            "on_toolbutton_queue_down_clicked": self.on_toolbutton_queue_down_clicked
        })
        self.change_sensitivity = [
            "toolbutton_add", "toolbutton_remove", "toolbutton_pause",
            "toolbutton_resume", "toolbutton_queue_up", "toolbutton_queue_down"
        ]

        # Hide if necessary
        self.visible(self.config["show_toolbar"])
Ejemplo n.º 27
0
    def __init__(self):
        component.Component.__init__(self,
                                     'QueuedTorrents',
                                     depend=['StatusBar', 'AddTorrentDialog'])
        self.queue = []
        self.status_item = None

        self.config = ConfigManager('gtkui.conf')
        self.builder = Builder()
        self.builder.add_from_file(
            deluge.common.resource_filename(
                'deluge.ui.gtkui', os.path.join('glade', 'queuedtorrents.ui')))
        self.builder.get_object('chk_autoadd').set_active(
            self.config['autoadd_queued'])
        self.dialog = self.builder.get_object('queued_torrents_dialog')
        self.dialog.set_icon(get_logo(32))

        self.builder.connect_signals(self)

        self.treeview = self.builder.get_object('treeview')
        self.treeview.append_column(
            TreeViewColumn(_('Torrent'), CellRendererText(), text=0))

        self.liststore = ListStore(str, str)
        self.treeview.set_model(self.liststore)
        self.treeview.set_tooltip_column(1)
Ejemplo n.º 28
0
    def __init__(self):
        component.Component.__init__(self, "SystemTray", interval=4)
        self.window = component.get("MainWindow")
        self.config = ConfigManager("gtkui.conf")
        # List of widgets that need to be hidden when not connected to a host
        self.hide_widget_list = [
            "menuitem_add_torrent",
            "menuitem_pause_all",
            "menuitem_resume_all",
            "menuitem_download_limit",
            "menuitem_upload_limit",
            "menuitem_quitdaemon",
            "separatormenuitem1",
            "separatormenuitem2",
            "separatormenuitem3",
            "separatormenuitem4"
        ]
        self.config.register_set_function("enable_system_tray", self.on_enable_system_tray_set)
        # bit of a hack to prevent function from doing something on startup
        self.__enabled_set_once = False
        self.config.register_set_function("enable_appindicator", self.on_enable_appindicator_set)

        self.max_download_speed = -1.0
        self.download_rate = 0.0
        self.max_upload_speed = -1.0
        self.upload_rate = 0.0

        self.config_value_changed_dict = {
            "max_download_speed": self._on_max_download_speed,
            "max_upload_speed": self._on_max_upload_speed
        }
Ejemplo n.º 29
0
 def on_menuitem_move_activate(self, data=None):
     log.debug("on_menuitem_move_activate")
     if client.is_localhost():
         from deluge.configmanager import ConfigManager
         config = ConfigManager("gtkui.conf")
         chooser = gtk.FileChooserDialog(
             _("Choose a directory to move files to"),
             component.get("MainWindow").window,
             gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
             buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK,
                      gtk.RESPONSE_OK))
         chooser.set_local_only(True)
         if not deluge.common.windows_check():
             chooser.set_icon(common.get_deluge_icon())
             chooser.set_property("skip-taskbar-hint", True)
         chooser.set_current_folder(config["choose_directory_dialog_path"])
         if chooser.run() == gtk.RESPONSE_OK:
             result = chooser.get_filename()
             config["choose_directory_dialog_path"] = result
             client.core.move_storage(
                 component.get("TorrentView").get_selected_torrents(),
                 result)
         chooser.destroy()
     else:
         component.get("SessionProxy").get_torrent_status(
             component.get("TorrentView").get_selected_torrent(),
             ["save_path"]).addCallback(self.show_move_storage_dialog)
Ejemplo n.º 30
0
    def __init__(self):
        component.Component.__init__(self,
                                     "QueuedTorrents",
                                     depend=["StatusBar", "AddTorrentDialog"])
        self.queue = []
        self.status_item = None

        self.config = ConfigManager("gtkui.conf")
        self.glade = gtk.glade.XML(
            pkg_resources.resource_filename("deluge.ui.gtkui",
                                            "glade/queuedtorrents.glade"))
        self.glade.get_widget("chk_autoadd").set_active(
            self.config["autoadd_queued"])
        self.dialog = self.glade.get_widget("queued_torrents_dialog")
        self.dialog.set_icon(common.get_logo(32))

        self.glade.signal_autoconnect({
            "on_button_remove_clicked":
            self.on_button_remove_clicked,
            "on_button_clear_clicked":
            self.on_button_clear_clicked,
            "on_button_close_clicked":
            self.on_button_close_clicked,
            "on_button_add_clicked":
            self.on_button_add_clicked,
            "on_chk_autoadd_toggled":
            self.on_chk_autoadd_toggled
        })

        self.treeview = self.glade.get_widget("treeview")
        self.treeview.append_column(
            gtk.TreeViewColumn(_("Torrent"), gtk.CellRendererText(), text=0))

        self.liststore = gtk.ListStore(str, str)
        self.treeview.set_model(self.liststore)
Ejemplo n.º 31
0
    def run(self, stdscr):
        """This method is called by the curses.wrapper to start the mainloop and screen.

        Args:
            stdscr (_curses.curses window): curses screen passed in from curses.wrapper.

        """
        # We want to do an interactive session, so start up the curses screen and
        # pass it the function that handles commands
        colors.init_colors()
        self.stdscr = stdscr
        self.config = ConfigManager('console.conf', defaults=DEFAULT_CONSOLE_PREFS, file_version=2)
        self.config.run_converter((0, 1), 2, self._migrate_config_1_to_2)

        self.statusbars = StatusBars()
        from deluge.ui.console.modes.connectionmanager import ConnectionManager
        self.register_mode(ConnectionManager(stdscr, self.encoding), set_mode=True)

        torrentlist = self.register_mode(TorrentList(self.stdscr, self.encoding))
        self.register_mode(CmdLine(self.stdscr, self.encoding))
        self.register_mode(EventView(torrentlist, self.stdscr, self.encoding))
        self.register_mode(TorrentDetail(torrentlist, self.stdscr, self.config, self.encoding))
        self.register_mode(Preferences(torrentlist, self.stdscr, self.config, self.encoding))
        self.register_mode(AddTorrents(torrentlist, self.stdscr, self.config, self.encoding))

        self.eventlog = EventLog()

        self.active_mode.topbar = '{!status!}Deluge ' + deluge.common.get_version() + ' Console'
        self.active_mode.bottombar = '{!status!}'
        self.active_mode.refresh()
        # Start the twisted mainloop
        reactor.run()
Ejemplo n.º 32
0
 def __init__(self, stdscr, encoding=None):
     self.popup = None
     self.statuses = {}
     self.messages = deque()
     self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
     BaseMode.__init__(self, stdscr, encoding)
     self.__update_statuses()
     self.__update_popup()
Ejemplo n.º 33
0
 def update_config(self):
     self.config = ConfigManager("console.conf",DEFAULT_PREFS)
     self.__cols_to_show = [pref for pref in column_pref_names if self.config["show_%s"%pref]]
     self.__columns = [prefs_to_names[col] for col in self.__cols_to_show]
     self.__status_fields = column.get_required_fields(self.__columns)
     for rf in ["state","name","queue"]: # we always need these, even if we're not displaying them
         if not rf in self.__status_fields: self.__status_fields.append(rf)
     self.__update_columns()
Ejemplo n.º 34
0
def menubar_osx(gtkui, osxapp):
    main_builder = gtkui.mainwindow.get_builder()
    menubar = main_builder.get_object('menubar')
    group = accel_groups_from_object(gtkui.mainwindow.window)[0]

    config = ConfigManager('gtk3ui.conf')

    # NOTE: accel maps doesn't work with glade file format
    # because of libglade not setting MenuItem accel groups
    # That's why we remove / set accelerators by hand... (dirty)
    # Clean solution: migrate glades files to gtkbuilder format
    file_menu = main_builder.get_object('menu_file').get_submenu()
    file_items = file_menu.get_children()
    accel_meta(file_items[0], group, 'o')
    accel_meta(file_items[1], group, 'n')
    quit_all_item = file_items[3]
    accel_swap(
        quit_all_item,
        group,
        'q',
        ModifierType.SHIFT_MASK | ModifierType.CONTROL_MASK,
        'q',
        ModifierType.SHIFT_MASK | ModifierType.META_MASK,
    )
    for item in range(2, len(file_items)):  # remove quits
        file_menu.remove(file_items[item])

    menu_widget = main_builder.get_object('menu_edit')
    edit_menu = menu_widget.get_submenu()
    edit_items = edit_menu.get_children()
    pref_item = edit_items[0]
    accel_swap(pref_item, group, 'p', ModifierType.CONTROL_MASK, ',',
               ModifierType.META_MASK)
    edit_menu.remove(pref_item)

    conn_item = edit_items[1]
    accel_meta(conn_item, group, 'm')
    edit_menu.remove(conn_item)

    menubar.remove(menu_widget)

    help_menu = main_builder.get_object('menu_help').get_submenu()
    help_items = help_menu.get_children()
    about_item = help_items[4]
    help_menu.remove(about_item)
    help_menu.remove(help_items[3])  # separator

    menubar.hide()
    osxapp.set_menu_bar(menubar)
    # populate app menu
    osxapp.insert_app_menu_item(about_item, 0)
    osxapp.insert_app_menu_item(SeparatorMenuItem(), 1)
    osxapp.insert_app_menu_item(pref_item, 2)
    if not config['standalone']:
        osxapp.insert_app_menu_item(conn_item, 3)
    if quit_all_item.get_visible():
        osxapp.insert_app_menu_item(SeparatorMenuItem(), 4)
        osxapp.insert_app_menu_item(quit_all_item, 5)
Ejemplo n.º 35
0
    def __init__(self):
        if wnck:
            self.screen = wnck.screen_get_default()
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        # Get the glade file for the main window
        self.main_glade = gtk.glade.XML(
            pkg_resources.resource_filename("deluge.ui.gtkui",
                                            "glade/main_window.glade"))

        self.window = self.main_glade.get_widget("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_glade.get_widget("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL,
                                  [('text/uri-list', 0, 80)],
                                  gtk.gdk.ACTION_COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received",
                            self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("expose-event", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title",
                                          self._on_set_show_rate_in_title,
                                          apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent",
                                      self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent",
                                      self.on_torrentfinished_event)
Ejemplo n.º 36
0
def process_args(args):
    """Process arguments sent to already running Deluge"""
    # Make sure args is a list
    args = list(args)
    log.debug("Processing args from other process: %s", args)
    if not client.connected():
        # We're not connected so add these to the queue
        log.debug("Not connected to host.. Adding to queue.")
        component.get("QueuedTorrents").add_to_queue(args)
        return
    config = ConfigManager("gtkui.conf")

    for arg in args:
        if not arg.strip():
            continue
        log.debug("arg: %s", arg)

        if deluge.common.is_url(arg):
            log.debug("Attempting to add url (%s) from external source...",
                      arg)
            if config["interactive_add"]:
                component.get("AddTorrentDialog").add_from_url(arg)
                component.get("AddTorrentDialog").show(
                    config["focus_add_dialog"])
            else:
                client.core.add_torrent_url(arg, None)

        elif deluge.common.is_magnet(arg):
            log.debug("Attempting to add magnet (%s) from external source...",
                      arg)
            if config["interactive_add"]:
                component.get("AddTorrentDialog").add_from_magnets([arg])
                component.get("AddTorrentDialog").show(
                    config["focus_add_dialog"])
            else:
                client.core.add_torrent_magnet(arg, {})

        else:
            log.debug("Attempting to add file (%s) from external source...",
                      arg)
            if urlparse(arg).scheme == "file":
                arg = url2pathname(urlparse(arg).path)
            path = os.path.abspath(deluge.common.decode_string(arg))

            if not os.path.exists(path):
                log.error("No such file: %s", path)
                continue

            if config["interactive_add"]:
                component.get("AddTorrentDialog").add_from_files([path])
                component.get("AddTorrentDialog").show(
                    config["focus_add_dialog"])
            else:
                with open(path, "rb") as _file:
                    filedump = base64.encodestring(_file.read())
                client.core.add_torrent_file(
                    os.path.split(path)[-1], filedump, None)
Ejemplo n.º 37
0
def process_args(args):
    """Process arguments sent to already running Deluge"""
    # Make sure args is a list
    args = list(args)
    log.debug('Processing args from other process: %s', args)
    if not client.connected():
        # We're not connected so add these to the queue
        log.debug('Not connected to host.. Adding to queue.')
        component.get('QueuedTorrents').add_to_queue(args)
        return
    config = ConfigManager('gtkui.conf')

    for arg in args:
        if not arg.strip():
            continue
        log.debug('arg: %s', arg)

        if is_url(arg):
            log.debug('Attempting to add url (%s) from external source...',
                      arg)
            if config['interactive_add']:
                component.get('AddTorrentDialog').add_from_url(arg)
                component.get('AddTorrentDialog').show(
                    config['focus_add_dialog'])
            else:
                client.core.add_torrent_url(arg, None)

        elif is_magnet(arg):
            log.debug('Attempting to add magnet (%s) from external source...',
                      arg)
            if config['interactive_add']:
                component.get('AddTorrentDialog').add_from_magnets([arg])
                component.get('AddTorrentDialog').show(
                    config['focus_add_dialog'])
            else:
                client.core.add_torrent_magnet(arg, {})

        else:
            log.debug('Attempting to add file (%s) from external source...',
                      arg)
            if urlparse(arg).scheme == 'file':
                arg = url2pathname(urlparse(arg).path)
            path = os.path.abspath(decode_bytes(arg))

            if not os.path.exists(path):
                log.error('No such file: %s', path)
                continue

            if config['interactive_add']:
                component.get('AddTorrentDialog').add_from_files([path])
                component.get('AddTorrentDialog').show(
                    config['focus_add_dialog'])
            else:
                with open(path, 'rb') as _file:
                    filedump = b64encode(_file.read())
                client.core.add_torrent_file(
                    os.path.split(path)[-1], filedump, None)
Ejemplo n.º 38
0
    def __init__(self):
        component.Component.__init__(self, "Web.PluginManager")
        self.config = ConfigManager("web.conf")
        PluginManagerBase.__init__(self, "web.conf", "deluge.plugin.web")

        client.register_event_handler("PluginEnabledEvent",
                                      self._on_plugin_enabled_event)
        client.register_event_handler("PluginDisabledEvent",
                                      self._on_plugin_disabled_event)
Ejemplo n.º 39
0
    def __load_config(self):
        auth_file = deluge.configmanager.get_config_dir("auth")
        if not os.path.exists(auth_file):
            from deluge.common import create_localclient_account
            create_localclient_account()

        localclient_username, localclient_password = get_localhost_auth()
        DEFAULT_CONFIG = {
            "hosts": [(
                hashlib.sha1(str(time.time())).hexdigest(),
                 DEFAULT_HOST,
                 DEFAULT_PORT,
                 localclient_username,
                 localclient_password
            )]
        }
        config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)
        config.run_converter((0, 1), 2, self.__migrate_config_1_to_2)
        return config
Ejemplo n.º 40
0
 def __init__(self):
     super(WebApi, self).__init__("Web", depend=["SessionProxy"])
     self.host_list = ConfigManager("hostlist.conf.1.2", DEFAULT_HOSTS)
     if not os.path.isfile(self.host_list.config_file):
         self.host_list.save()
     self.core_config = CoreConfig()
     self.event_queue = EventQueue()
     try:
         self.sessionproxy = component.get("SessionProxy")
     except KeyError:
         self.sessionproxy = SessionProxy()
Ejemplo n.º 41
0
    def __init__(self):
        component.Component.__init__(self, "AutoAdd", depend=["TorrentManager"], interval=5)
        # Get the core config
        self.config = ConfigManager("core.conf")

        # A list of filenames
        self.invalid_torrents = []
        # Filename:Attempts
        self.attempts = {}

        # Register set functions
        self.config.register_set_function("autoadd_enable",
            self._on_autoadd_enable, apply_now=True)
        self.config.register_set_function("autoadd_location",
            self._on_autoadd_location)
Ejemplo n.º 42
0
    def __init__(self):
        if Wnck:
            self.screen = Wnck.Screen.get_default()
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        # Get the glade file for the main window
        self.main_glade = Gtk.Builder()
        self.main_glade.add_from_file(
                    pkg_resources.resource_filename("deluge.ui.gtkui",
                                                    "builder/main_window.ui"))

        self.window_signals = {}

        self.window = self.main_glade.get_object("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_glade.get_object("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(Gtk.DestDefaults.ALL, [Gtk.TargetEntry.new('text/uri-list', 0,
            80)], Gdk.DragAction.COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received", self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("draw", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title", self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent", self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent", self.on_torrentfinished_event)
Ejemplo n.º 43
0
    def enable(self):
        self.config = ConfigManager("execute.conf", DEFAULT_CONFIG)
        event_manager = component.get("EventManager")
        self.registered_events = {}

        # Go through the commands list and register event handlers
        for command in self.config["commands"]:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id):
                    self.execute_commands(torrent_id, event)
                return event_handler
            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event], event_handler)
            self.registered_events[event] = event_handler

        log.debug("Execute core plugin enabled!")
Ejemplo n.º 44
0
    def __init__(self):
        if wnck:
            self.screen = wnck.screen_get_default()
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        # Get the glade file for the main window
        self.main_glade = gtk.glade.XML(
                    pkg_resources.resource_filename("deluge.ui.gtkui",
                                                    "glade/main_window.glade"))

        self.window = self.main_glade.get_widget("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_glade.get_widget("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0,
            80)], gtk.gdk.ACTION_COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received", self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("expose-event", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title", self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent", self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent", self.on_torrentfinished_event)
Ejemplo n.º 45
0
    def enable(self):
        self.config = ConfigManager('execute.conf', DEFAULT_CONFIG)
        event_manager = component.get('EventManager')
        self.registered_events = {}
        self.preremoved_cache = {}

        # Go through the commands list and register event handlers
        for command in self.config['commands']:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id, *arg):
                    self.execute_commands(torrent_id, event, *arg)
                return event_handler
            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event], event_handler)
            if event == 'removed':
                event_manager.register_event_handler('PreTorrentRemovedEvent', self.on_preremoved)
            self.registered_events[event] = event_handler

        log.debug('Execute core plugin enabled!')
Ejemplo n.º 46
0
    def enable(self):
        log.info("*** Start Label plugin ***")
        self.plugin = component.get("CorePluginManager")
        self.plugin.register_status_field("label", self._status_get_label)

        #__init__
        core = component.get("Core")
        self.config = ConfigManager("label.conf", defaults=CONFIG_DEFAULTS)
        self.core_cfg = ConfigManager("core.conf")

        #reduce typing, assigning some values to self...
        self.torrents = core.torrentmanager.torrents
        self.labels = self.config["labels"]
        self.torrent_labels = self.config["torrent_labels"]

        self.clean_initial_config()

        component.get("EventManager").register_event_handler("TorrentAddedEvent", self.post_torrent_add)
        component.get("EventManager").register_event_handler("TorrentRemovedEvent", self.post_torrent_remove)

        #register tree:
        component.get("FilterManager").register_tree_field("label", self.init_filter_dict)

        log.debug("Label plugin enabled..")
Ejemplo n.º 47
0
class MainWindow(component.Component):
    def __init__(self):
        if wnck:
            self.screen = wnck.screen_get_default()
        component.Component.__init__(self, 'MainWindow', interval=2)
        self.config = ConfigManager('gtkui.conf')
        self.main_builder = gtk.Builder()

        # Patch this GtkBuilder to avoid connecting signals from elsewhere
        #
        # Think about splitting up  mainwindow gtkbuilder file into the necessary parts
        # to avoid GtkBuilder monkey patch. Those parts would then need adding to mainwindow 'by hand'.
        self.gtk_builder_signals_holder = _GtkBuilderSignalsHolder()
        self.main_builder.prev_connect_signals = copy.deepcopy(self.main_builder.connect_signals)

        def patched_connect_signals(*a, **k):
            raise RuntimeError('In order to connect signals to this GtkBuilder instance please use '
                               '"component.get(\'MainWindow\').connect_signals()"')
        self.main_builder.connect_signals = patched_connect_signals

        # Get Gtk Builder files Main Window, New release dialog, and Tabs.
        for filename in ('main_window.ui', 'main_window.new_release.ui', 'main_window.tabs.ui',
                         'main_window.tabs.menu_file.ui', 'main_window.tabs.menu_peer.ui'):
            self.main_builder.add_from_file(
                resource_filename('deluge.ui.gtkui', os.path.join('glade', filename)))

        self.window = self.main_builder.get_object('main_window')
        self.window.set_icon(deluge.ui.gtkui.common.get_deluge_icon())
        self.vpaned = self.main_builder.get_object('vpaned')
        self.initial_vpaned_position = self.config['window_pane_position']

        # Keep a list of components to pause and resume when changing window state.
        self.child_components = ['TorrentView', 'StatusBar', 'TorrentDetails']

        # Load the window state
        self.load_window_state()

        # Keep track of window minimization state so we don't update UI when it is minimized.
        self.is_minimized = False
        self.restart = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0, 80)], ACTION_COPY)

        # Connect events
        self.window.connect('window-state-event', self.on_window_state_event)
        self.window.connect('configure-event', self.on_window_configure_event)
        self.window.connect('delete-event', self.on_window_delete_event)
        self.window.connect('drag-data-received', self.on_drag_data_received_event)
        self.vpaned.connect('notify::position', self.on_vpaned_position_event)
        self.window.connect('expose-event', self.on_expose_event)

        self.config.register_set_function('show_rate_in_title', self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler('NewVersionAvailableEvent', self.on_newversionavailable_event)

    def connect_signals(self, mapping_or_class):
        self.gtk_builder_signals_holder.connect_signals(mapping_or_class)

    def first_show(self):
        self.main_builder.prev_connect_signals(self.gtk_builder_signals_holder)
        self.vpaned.set_position(self.initial_vpaned_position)
        if not (
                self.config['start_in_tray'] and self.config['enable_system_tray']
        ) and not self.window.get_property('visible'):
            log.debug('Showing window')
            self.show()

        while gtk.events_pending():
            gtk.main_iteration()

    def show(self):
        component.resume(self.child_components)
        self.window.show()

    def hide(self):
        component.get('TorrentView').save_state()
        component.pause(self.child_components)

        # Store the x, y positions for when we restore the window
        self.config['window_x_pos'], self.config['window_y_pos'] = self.window.get_position()
        self.window.hide()

    def present(self):
        def restore():
            # Restore the proper x,y coords for the window prior to showing it
            component.resume(self.child_components)
            self.window.present()
            self.load_window_state()

        if self.config['lock_tray'] and not self.visible():
            dialog = PasswordDialog(_('Enter your password to show Deluge...'))

            def on_dialog_response(response_id):
                if response_id == gtk.RESPONSE_OK:
                    if self.config['tray_password'] == sha(dialog.get_password()).hexdigest():
                        restore()
            dialog.run().addCallback(on_dialog_response)
        else:
            restore()

    def active(self):
        """Returns True if the window is active, False if not."""
        return self.window.is_active()

    def visible(self):
        """Returns True if window is visible, False if not."""
        return self.window.get_property('visible')

    def get_builder(self):
        """Returns a reference to the main window GTK builder object."""
        return self.main_builder

    def quit(self, shutdown=False, restart=False):
        """Quits the GtkUI application.

        Args:
            shutdown (bool): Whether or not to shutdown the daemon as well.
            restart (bool): Whether or not to restart the application after closing.

        """

        def quit_gtkui():
            def stop_gtk_reactor(result=None):
                self.restart = restart
                try:
                    reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')
                except ReactorNotRunning:
                    log.debug('Attempted to stop the reactor but it is not running...')

            if shutdown:
                client.daemon.shutdown().addCallback(stop_gtk_reactor)
            elif not client.is_standalone() and client.connected():
                client.disconnect().addCallback(stop_gtk_reactor)
            else:
                stop_gtk_reactor()

        if self.config['lock_tray'] and not self.visible():
            dialog = PasswordDialog(_('Enter your password to Quit Deluge...'))

            def on_dialog_response(response_id):
                if response_id == gtk.RESPONSE_OK:
                    if self.config['tray_password'] == sha(dialog.get_password()).hexdigest():
                        quit_gtkui()
            dialog.run().addCallback(on_dialog_response)
        else:
            quit_gtkui()

    def load_window_state(self):
        if self.config['window_x_pos'] == -32000 or self.config['window_x_pos'] == -32000:
            self.config['window_x_pos'] = self.config['window_y_pos'] = 0

        self.window.move(self.config['window_x_pos'], self.config['window_y_pos'])
        self.window.resize(self.config['window_width'], self.config['window_height'])
        if self.config['window_maximized']:
            self.window.maximize()

    def on_window_configure_event(self, widget, event):
        if not self.config['window_maximized'] and self.visible:
            self.config['window_x_pos'], self.config['window_y_pos'] = self.window.get_position()
            self.config['window_width'] = event.width
            self.config['window_height'] = event.height

    def on_window_state_event(self, widget, event):
        if event.changed_mask & WINDOW_STATE_MAXIMIZED:
            if event.new_window_state & WINDOW_STATE_MAXIMIZED:
                log.debug('pos: %s', self.window.get_position())
                self.config['window_maximized'] = True
            elif not event.new_window_state & WINDOW_STATE_WITHDRAWN:
                self.config['window_maximized'] = False
        if event.changed_mask & WINDOW_STATE_ICONIFIED:
            if event.new_window_state & WINDOW_STATE_ICONIFIED:
                log.debug('MainWindow is minimized..')
                component.get('TorrentView').save_state()
                component.pause(self.child_components)
                self.is_minimized = True
            else:
                log.debug('MainWindow is not minimized..')
                component.resume(self.child_components)
                self.is_minimized = False
        return False

    def on_window_delete_event(self, widget, event):
        if self.config['close_to_tray'] and self.config['enable_system_tray']:
            self.hide()
        else:
            self.quit()

        return True

    def on_vpaned_position_event(self, obj, param):
        self.config['window_pane_position'] = self.vpaned.get_position()

    def on_drag_data_received_event(self, widget, drag_context, x, y, selection_data, info, timestamp):
        log.debug('Selection(s) dropped on main window %s', selection_data.get_text())
        if selection_data.get_uris():
            process_args(selection_data.get_uris())
        else:
            process_args(selection_data.get_text().split())
        drag_context.finish(True, True, timestamp)

    def on_expose_event(self, widget, event):
        component.get('SystemTray').blink(False)

    def stop(self):
        self.window.set_title('Deluge')

    def update(self):
        # Update the window title
        def _on_get_session_status(status):
            download_rate = fspeed(status['payload_download_rate'], precision=0, shortform=True)
            upload_rate = fspeed(status['payload_upload_rate'], precision=0, shortform=True)
            self.window.set_title(_('D: %s U: %s - Deluge' % (download_rate, upload_rate)))
        if self.config['show_rate_in_title']:
            client.core.get_session_status(
                ['payload_download_rate', 'payload_upload_rate']
                ).addCallback(_on_get_session_status)

    def _on_set_show_rate_in_title(self, key, value):
        if value:
            self.update()
        else:
            self.window.set_title(_('Deluge'))

    def on_newversionavailable_event(self, new_version):
        if self.config['show_new_releases']:
            from deluge.ui.gtkui.new_release_dialog import NewReleaseDialog
            reactor.callLater(5.0, NewReleaseDialog().show, new_version)

    def is_on_active_workspace(self):
        """Determines if MainWindow is on the active workspace.

        Returns:
            bool: True if on active workspace (or wnck module not available), otherwise False.

        """
        if wnck:
            self.screen.force_update()
            win = wnck.window_get(self.window.get_window().xid)
            if win:
                active_wksp = win.get_screen().get_active_workspace()
                if active_wksp:
                    return win.is_on_workspace(active_wksp)
                return False
        return True
Ejemplo n.º 48
0
    def __init__(self):
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        self.gtk_builder_signals_holder = _GtkBuilderSignalsHolder()
        self.main_builder = gtk.Builder()
        # Patch this GtkBuilder to avoid connecting signals from elsewhere
        #
        # Think about splitting up the main window gtkbuilder file into the necessary parts
        # in order not to have to monkey patch GtkBuilder. Those parts would then need to
        # be added to the main window "by hand".
        self.main_builder.prev_connect_signals = copy.deepcopy(self.main_builder.connect_signals)

        def patched_connect_signals(*a, **k):
            raise RuntimeError(
                "In order to connect signals to this GtkBuilder instance please use "
                "'component.get(\"MainWindow\").connect_signals()'"
            )

        self.main_builder.connect_signals = patched_connect_signals

        # Get the gtk builder file for the main window
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.ui"))
        )
        # The new release dialog
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.new_release.ui"))
        )
        # The move storage dialog
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.move_storage.ui"))
        )
        # The tabs
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.ui"))
        )
        # The tabs file menu
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.menu_file.ui"))
        )
        # The tabs peer menu
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.menu_peer.ui"))
        )

        self.window = self.main_builder.get_object("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_builder.get_object("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("text/uri-list", 0, 80)], gtk.gdk.ACTION_COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received", self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("expose-event", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title", self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent", self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent", self.on_torrentfinished_event)
Ejemplo n.º 49
0
class ConnectionManager(component.Component):
    def __init__(self):
        component.Component.__init__(self, "ConnectionManager")
        self.gtkui_config = ConfigManager("gtkui.conf")

        self.config = ConfigManager("hostlist.conf.1.2", DEFAULT_CONFIG)

        self.running = False

    # Component overrides
    def start(self):
        pass

    def stop(self):
        # Close this dialog when we are shutting down
        if self.running:
            self.connection_manager.response(gtk.RESPONSE_CLOSE)

    def shutdown(self):
        pass

    # Public methods
    def show(self):
        """
        Show the ConnectionManager dialog.
        """
        # Get the glade file for the connection manager
        self.glade = gtk.glade.XML(
                    pkg_resources.resource_filename("deluge.ui.gtkui",
                                            "glade/connection_manager.glade"))
        self.window = component.get("MainWindow")

        # Setup the ConnectionManager dialog
        self.connection_manager = self.glade.get_widget("connection_manager")
        self.connection_manager.set_transient_for(self.window.window)

        self.connection_manager.set_icon(common.get_deluge_icon())

        self.glade.get_widget("image1").set_from_pixbuf(common.get_logo(32))

        self.hostlist = self.glade.get_widget("hostlist")

        # Create status pixbufs
        if not HOSTLIST_PIXBUFS:
            for stock_id in (gtk.STOCK_NO, gtk.STOCK_YES, gtk.STOCK_CONNECT):
                HOSTLIST_PIXBUFS.append(self.connection_manager.render_icon(stock_id, gtk.ICON_SIZE_MENU))

        # Create the host list gtkliststore
        # id-hash, hostname, port, status, username, password, version
        self.liststore = gtk.ListStore(str, str, int, str, str, str, str)

        # Setup host list treeview
        self.hostlist.set_model(self.liststore)
        render = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn(_("Status"), render)
        column.set_cell_data_func(render, cell_render_status, 3)
        self.hostlist.append_column(column)
        render = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Host"), render, text=HOSTLIST_COL_HOST)
        column.set_cell_data_func(render, cell_render_host, (1, 2, 4))
        column.set_expand(True)
        self.hostlist.append_column(column)
        render = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_("Version"), render, text=HOSTLIST_COL_VERSION)
        self.hostlist.append_column(column)

        # Load any saved host entries
        self.__load_hostlist()
        self.__load_options()

        # Select the first host if possible
        if len(self.liststore) > 0:
            self.hostlist.get_selection().select_path("0")

        # Connect the signals to the handlers
        self.glade.signal_autoconnect(self)
        self.hostlist.get_selection().connect("changed", self.on_hostlist_selection_changed)

        self.__update_list()

        self.running = True
        response = self.connection_manager.run()
        self.running = False

        # Save the toggle options
        self.__save_options()
        self.__save_hostlist()

        self.connection_manager.destroy()
        del self.glade
        del self.window
        del self.connection_manager
        del self.liststore
        del self.hostlist

    def add_host(self, host, port, username="", password=""):
        """
        Adds a host to the list.

        :param host: str, the hostname
        :param port: int, the port
        :param username: str, the username to login as
        :param password: str, the password to login with

        """
        # Check to see if there is already an entry for this host and return
        # if thats the case
        for entry in self.liststore:
            if [entry[HOSTLIST_COL_HOST], entry[HOSTLIST_COL_PORT], entry[HOSTLIST_COL_USER]] == [host, port, username]:
                raise Exception("Host already in list!")

        # Host isn't in the list, so lets add it
        row = self.liststore.append()
        import time
        import hashlib
        self.liststore[row][HOSTLIST_COL_ID] = hashlib.sha1(str(time.time())).hexdigest()
        self.liststore[row][HOSTLIST_COL_HOST] = host
        self.liststore[row][HOSTLIST_COL_PORT] = port
        self.liststore[row][HOSTLIST_COL_USER] = username
        self.liststore[row][HOSTLIST_COL_PASS] = password
        self.liststore[row][HOSTLIST_COL_STATUS] = "Offline"

        # Save the host list to file
        self.__save_hostlist()

        # Update the status of the hosts
        self.__update_list()

    # Private methods
    def __save_hostlist(self):
        """
        Save the current hostlist to the config file.
        """
        # Grab the hosts from the liststore
        self.config["hosts"] = []
        for row in self.liststore:
            self.config["hosts"].append((row[HOSTLIST_COL_ID], row[HOSTLIST_COL_HOST], row[HOSTLIST_COL_PORT], row[HOSTLIST_COL_USER], row[HOSTLIST_COL_PASS]))

        self.config.save()

    def __load_hostlist(self):
        """
        Load saved host entries
        """
        for host in self.config["hosts"]:
            new_row = self.liststore.append()
            self.liststore[new_row][HOSTLIST_COL_ID] = host[0]
            self.liststore[new_row][HOSTLIST_COL_HOST] = host[1]
            self.liststore[new_row][HOSTLIST_COL_PORT] = host[2]
            self.liststore[new_row][HOSTLIST_COL_USER] = host[3]
            self.liststore[new_row][HOSTLIST_COL_PASS] = host[4]
            self.liststore[new_row][HOSTLIST_COL_STATUS] = "Offline"

    def __get_host_row(self, host_id):
        """
        Returns the row in the liststore for `:param:host_id` or None

        """
        for row in self.liststore:
            if host_id == row[HOSTLIST_COL_ID]:
                return row
        return None

    def __update_list(self):
        """Updates the host status"""
        if not hasattr(self, "liststore"):
            # This callback was probably fired after the window closed
            return

        def on_connect(result, c, host_id):
            # Return if the deferred callback was done after the dialog was closed
            if not self.running:
                return

            row = self.__get_host_row(host_id)
            def on_info(info, c):
                if not self.running:
                    return
                if row:
                    row[HOSTLIST_COL_STATUS] = "Online"
                    row[HOSTLIST_COL_VERSION] = info
                    self.__update_buttons()
                c.disconnect()

            def on_info_fail(reason, c):
                if not self.running:
                    return
                if row:
                    row[HOSTLIST_COL_STATUS] = "Offline"
                    self.__update_buttons()
                c.disconnect()

            d = c.daemon.info()
            d.addCallback(on_info, c)
            d.addErrback(on_info_fail, c)

        def on_connect_failed(reason, host_id):
            if not self.running:
                return
            row = self.__get_host_row(host_id)
            if row:
                row[HOSTLIST_COL_STATUS] = "Offline"
                self.__update_buttons()

        for row in self.liststore:
            host_id = row[HOSTLIST_COL_ID]
            host = row[HOSTLIST_COL_HOST]
            port = row[HOSTLIST_COL_PORT]
            user = row[HOSTLIST_COL_USER]
            password = row[HOSTLIST_COL_PASS]

            if client.connected() and \
                (host, port, "localclient" if not user and host in ("127.0.0.1", "localhost") else user) == client.connection_info():
                def on_info(info):
                    if not self.running:
                        return
                    row[HOSTLIST_COL_VERSION] = info
                    self.__update_buttons()
                row[HOSTLIST_COL_STATUS] = "Connected"
                client.daemon.info().addCallback(on_info)
                continue

            # Create a new Client instance
            c = deluge.ui.client.Client()
            d = c.connect(host, port, user, password)
            d.addCallback(on_connect, c, host_id)
            d.addErrback(on_connect_failed, host_id)

    def __load_options(self):
        """
        Set the widgets to show the correct options from the config.
        """
        self.glade.get_widget("chk_autoconnect").set_active(self.gtkui_config["autoconnect"])
        self.glade.get_widget("chk_autostart").set_active(self.gtkui_config["autostart_localhost"])
        self.glade.get_widget("chk_donotshow").set_active(not self.gtkui_config["show_connection_manager_on_start"])

    def __save_options(self):
        """
        Set options in gtkui config from the toggle buttons.
        """
        self.gtkui_config["autoconnect"] = self.glade.get_widget("chk_autoconnect").get_active()
        self.gtkui_config["autostart_localhost"] = self.glade.get_widget("chk_autostart").get_active()
        self.gtkui_config["show_connection_manager_on_start"] = not self.glade.get_widget("chk_donotshow").get_active()

    def __update_buttons(self):
        """
        Updates the buttons states.
        """
        if len(self.liststore) == 0:
            # There is nothing in the list
            self.glade.get_widget("button_startdaemon").set_sensitive(True)
            self.glade.get_widget("button_connect").set_sensitive(False)
            self.glade.get_widget("button_removehost").set_sensitive(False)
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text("_Start Daemon")

        model, row = self.hostlist.get_selection().get_selected()
        if not row:
            return

        # Get some values about the selected host
        status = model[row][HOSTLIST_COL_STATUS]
        host = model[row][HOSTLIST_COL_HOST]

        log.debug("Status: %s", status)
        # Check to see if we have a localhost entry selected
        localhost = False
        if host in ("127.0.0.1", "localhost"):
            localhost = True

        # Make sure buttons are sensitive at start
        self.glade.get_widget("button_startdaemon").set_sensitive(True)
        self.glade.get_widget("button_connect").set_sensitive(True)
        self.glade.get_widget("button_removehost").set_sensitive(True)

        # See if this is the currently connected host
        if status == "Connected":
            # Display a disconnect button if we're connected to this host
            self.glade.get_widget("button_connect").set_label("gtk-disconnect")
            self.glade.get_widget("button_removehost").set_sensitive(False)
        else:
            self.glade.get_widget("button_connect").set_label("gtk-connect")
            if status == "Offline" and not localhost:
                self.glade.get_widget("button_connect").set_sensitive(False)

        # Check to see if the host is online
        if status == "Connected" or status == "Online":
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_STOP, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text(
                _("_Stop Daemon"))

        # Update the start daemon button if the selected host is localhost
        if localhost and status == "Offline":
            # The localhost is not online
            self.glade.get_widget("image_startdaemon").set_from_stock(
                gtk.STOCK_EXECUTE, gtk.ICON_SIZE_MENU)
            self.glade.get_widget("label_startdaemon").set_text(
                _("_Start Daemon"))

        if not localhost:
            # An offline host
            self.glade.get_widget("button_startdaemon").set_sensitive(False)

        # Make sure label is displayed correctly using mnemonics
        self.glade.get_widget("label_startdaemon").set_use_underline(
            True)

    def start_daemon(self, port, config):
        """
        Attempts to start a daemon process and will show an ErrorDialog if unable
        to.
        """
        try:
            return client.start_daemon(port, config)
        except OSError, e:
            from errno import ENOENT
            if e.errno == ENOENT:
                dialogs.ErrorDialog(
                    _("Unable to start daemon!"),
                    _("Deluge cannot find the 'deluged' executable, it is likely \
that you forgot to install the deluged package or it's not in your PATH.")).run()
            else:
                raise e
        except Exception, e:
            import traceback
            import sys
            tb = sys.exc_info()
            dialogs.ErrorDialog(
                _("Unable to start daemon!"),
                _("Please examine the details for more information."),
                details=traceback.format_exc(tb[2])).run()
Ejemplo n.º 50
0
class GtkUI(object):
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler
            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application
            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':
            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])
            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx
            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)

    def start(self):
        reactor.callWhenRunning(self._on_reactor_start)

        # Initialize gdk threading
        threads_enter()
        reactor.run()
        # Reactor no longer running so async callbacks (Deferreds) cannot be
        # processed after this point.
        threads_leave()

    def shutdown(self, *args, **kwargs):
        log.debug('GTKUI shutting down...')
        # Shutdown all components
        if client.is_standalone:
            return component.shutdown()

    @defer.inlineCallbacks
    def close(self):
        if self.closing:
            return
        self.closing = True
        # Make sure the config is saved.
        self.config.save()
        # Ensure columns state is saved
        self.torrentview.save_state()
        # Shut down components
        yield self.shutdown()

        # The gtk modal dialogs (e.g. Preferences) can prevent the application
        # quitting, so force exiting by destroying MainWindow. Must be done here
        # to avoid hanging when quitting with SIGINT (CTRL-C).
        self.mainwindow.window.destroy()

        reactor.stop()

        # Restart the application after closing if MainWindow restart attribute set.
        if component.get('MainWindow').restart:
            os.execv(sys.argv[0], sys.argv)

    def log_rpc_stats(self):
        """Log RPC statistics for thinclient mode."""
        if not client.connected():
            return

        t = time.time()
        recv = client.get_bytes_recv()
        sent = client.get_bytes_sent()
        delta_time = t - self.daemon_bps[0]
        delta_sent = sent - self.daemon_bps[1]
        delta_recv = recv - self.daemon_bps[2]
        self.daemon_bps = (t, sent, recv)
        sent_rate = fspeed(delta_sent / delta_time)
        recv_rate = fspeed(delta_recv / delta_time)
        log.debug('RPC: Sent %s (%s) Recv %s (%s)', fsize(sent), sent_rate, fsize(recv), recv_rate)

    def _on_reactor_start(self):
        log.debug('_on_reactor_start')
        self.mainwindow.first_show()

        if not self.config['standalone']:
            return self._start_thinclient()

        err_msg = ''
        try:
            client.start_standalone()
        except DaemonRunningError:
            err_msg = _('A Deluge daemon (deluged) is already running.\n'
                        'To use Standalone mode, stop local daemon and restart Deluge.')
        except ImportError as ex:
            if 'No module named libtorrent' in ex.message:
                err_msg = _('Only Thin Client mode is available because libtorrent is not installed.\n'
                            'To use Standalone mode, please install libtorrent package.')
            else:
                log.exception(ex)
                err_msg = _('Only Thin Client mode is available due to unknown Import Error.\n'
                            'To use Standalone mode, please see logs for error details.')
        except Exception as ex:
            log.exception(ex)
            err_msg = _('Only Thin Client mode is available due to unknown Import Error.\n'
                        'To use Standalone mode, please see logs for error details.')
        else:
            component.start()
            return

        def on_dialog_response(response):
            """User response to switching mode dialog."""
            if response == RESPONSE_YES:
                # Turning off standalone
                self.config['standalone'] = False
                self._start_thinclient()
            else:
                # User want keep Standalone Mode so just quit.
                self.mainwindow.quit()

        # An error occurred so ask user to switch from Standalone to Thin Client mode.
        err_msg += '\n\n' + _('Continue in Thin Client mode?')
        d = YesNoDialog(_('Change User Interface Mode'), err_msg).run()
        d.addCallback(on_dialog_response)

    def _start_thinclient(self):
        """Start the gtkui in thinclient mode"""
        if log.isEnabledFor(logging.DEBUG):
            self.rpc_stats.start(10)

        # Check to see if we need to start the localhost daemon
        if self.config['autostart_localhost']:
            def on_localhost_status(status_info, port):
                if status_info[1] == 'Offline':
                    log.debug('Autostarting localhost: %s', host_config[0:3])
                    self.connectionmanager.start_daemon(port, get_config_dir())

            for host_config in self.connectionmanager.hostlist.config['hosts']:
                if host_config[1] in LOCALHOST:
                    d = self.connectionmanager.hostlist.get_host_status(host_config[0])
                    d.addCallback(on_localhost_status, host_config[2])
                    break

        # Autoconnect to a host
        if self.config['autoconnect']:
            for host_config in self.connectionmanager.hostlist.config['hosts']:
                host_id, host, port, user, __ = host_config
                if host_id == self.config['autoconnect_host_id']:
                    log.debug('Trying to connect to %s@%s:%s', user, host, port)
                    self.connectionmanager._connect(host_id, try_counter=6)
                    break

        if self.config['show_connection_manager_on_start']:
            # Dialog is blocking so call last.
            self.connectionmanager.show()

    def __on_disconnect(self):
        """
        Called when disconnected from the daemon.  We basically just stop all
        the components here.
        """
        self.daemon_bps = (0, 0, 0)
        component.stop()
Ejemplo n.º 51
0
class MainWindow(component.Component):
    def __init__(self):
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        self.gtk_builder_signals_holder = _GtkBuilderSignalsHolder()
        self.main_builder = gtk.Builder()
        # Patch this GtkBuilder to avoid connecting signals from elsewhere
        #
        # Think about splitting up the main window gtkbuilder file into the necessary parts
        # in order not to have to monkey patch GtkBuilder. Those parts would then need to
        # be added to the main window "by hand".
        self.main_builder.prev_connect_signals = copy.deepcopy(self.main_builder.connect_signals)

        def patched_connect_signals(*a, **k):
            raise RuntimeError(
                "In order to connect signals to this GtkBuilder instance please use "
                "'component.get(\"MainWindow\").connect_signals()'"
            )

        self.main_builder.connect_signals = patched_connect_signals

        # Get the gtk builder file for the main window
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.ui"))
        )
        # The new release dialog
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.new_release.ui"))
        )
        # The move storage dialog
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.move_storage.ui"))
        )
        # The tabs
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.ui"))
        )
        # The tabs file menu
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.menu_file.ui"))
        )
        # The tabs peer menu
        self.main_builder.add_from_file(
            deluge.common.resource_filename("deluge.ui.gtkui", os.path.join("glade", "main_window.tabs.menu_peer.ui"))
        )

        self.window = self.main_builder.get_object("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_builder.get_object("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [("text/uri-list", 0, 80)], gtk.gdk.ACTION_COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received", self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("expose-event", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title", self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent", self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent", self.on_torrentfinished_event)

    def connect_signals(self, mapping_or_class):
        self.gtk_builder_signals_holder.connect_signals(mapping_or_class)

    def first_show(self):
        if not (self.config["start_in_tray"] and self.config["enable_system_tray"]) and not self.window.get_property(
            "visible"
        ):
            log.debug("Showing window")
            self.main_builder.prev_connect_signals(self.gtk_builder_signals_holder)
            self.show()
            while gtk.events_pending():
                gtk.main_iteration(False)
            self.vpaned.set_position(self.initial_vpaned_position)

    def show(self):
        try:
            component.resume("TorrentView")
            component.resume("StatusBar")
            component.resume("TorrentDetails")
        except:
            pass

        self.window.show()

    def hide(self):
        component.pause("TorrentView")
        component.get("TorrentView").save_state()
        component.pause("StatusBar")
        component.pause("TorrentDetails")
        # Store the x, y positions for when we restore the window
        self.window_x_pos = self.window.get_position()[0]
        self.window_y_pos = self.window.get_position()[1]
        self.window.hide()

    def present(self):
        # Restore the proper x,y coords for the window prior to showing it
        try:
            self.config["window_x_pos"] = self.window_x_pos
            self.config["window_y_pos"] = self.window_y_pos
        except:
            pass
        try:
            component.resume("TorrentView")
            component.resume("StatusBar")
            component.resume("TorrentDetails")
        except:
            pass

        self.window.present()
        self.load_window_state()

    def active(self):
        """Returns True if the window is active, False if not."""
        return self.window.is_active()

    def visible(self):
        """Returns True if window is visible, False if not."""
        return self.window.get_property("visible")

    def get_builder(self):
        """Returns a reference to the main window GTK builder object."""
        return self.main_builder

    def quit(self, shutdown=False):
        """
        Quits the GtkUI

        :param shutdown: whether or not to shutdown the daemon as well
        :type shutdown: boolean
        """
        if shutdown:

            def on_daemon_shutdown(result):
                try:
                    reactor.stop()
                except ReactorNotRunning:
                    log.debug("Attempted to stop the reactor but it is not running...")

            client.daemon.shutdown().addCallback(on_daemon_shutdown)
            return
        if client.is_classicmode():
            reactor.stop()
            return
        if not client.connected():
            reactor.stop()
            return

        def on_client_disconnected(result):
            reactor.stop()

        client.disconnect().addCallback(on_client_disconnected)

    def load_window_state(self):
        x = self.config["window_x_pos"]
        y = self.config["window_y_pos"]
        w = self.config["window_width"]
        h = self.config["window_height"]
        self.window.move(x, y)
        self.window.resize(w, h)
        if self.config["window_maximized"]:
            self.window.maximize()

    def on_window_configure_event(self, widget, event):
        if not self.config["window_maximized"] and self.visible:
            self.config["window_x_pos"] = self.window.get_position()[0]
            self.config["window_y_pos"] = self.window.get_position()[1]
            self.config["window_width"] = event.width
            self.config["window_height"] = event.height

    def on_window_state_event(self, widget, event):
        if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED:
            if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED:
                log.debug("pos: %s", self.window.get_position())
                self.config["window_maximized"] = True
            elif not event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
                self.config["window_maximized"] = False
        if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
            if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
                log.debug("MainWindow is minimized..")
                component.pause("TorrentView")
                component.pause("StatusBar")
                self.is_minimized = True
            else:
                log.debug("MainWindow is not minimized..")
                try:
                    component.resume("TorrentView")
                    component.resume("StatusBar")
                except:
                    pass
                self.is_minimized = False
        return False

    def on_window_delete_event(self, widget, event):
        if self.config["close_to_tray"] and self.config["enable_system_tray"]:
            self.hide()
        else:
            self.quit()

        return True

    def on_vpaned_position_event(self, obj, param):
        self.config["window_pane_position"] = self.vpaned.get_position()

    def on_drag_data_received_event(self, widget, drag_context, x, y, selection_data, info, timestamp):
        log.debug("Selection(s) dropped on main window %s", selection_data.data)
        if selection_data.get_uris():
            process_args(selection_data.get_uris())
        else:
            process_args(selection_data.data.split())
        drag_context.finish(True, True)

    def on_expose_event(self, widget, event):
        component.get("SystemTray").blink(False)

    def stop(self):
        self.window.set_title("Deluge")

    def update(self):
        # Update the window title
        def _on_get_session_status(status):
            download_rate = deluge.common.fsize_short(status["payload_download_rate"])
            upload_rate = deluge.common.fsize_short(status["payload_upload_rate"])
            self.window.set_title("%s%s %s%s - Deluge" % (_("D:"), download_rate, _("U:"), upload_rate))

        if self.config["show_rate_in_title"]:
            client.core.get_session_status(["payload_download_rate", "payload_upload_rate"]).addCallback(
                _on_get_session_status
            )

    def _on_set_show_rate_in_title(self, key, value):
        if value:
            self.update()
        else:
            self.window.set_title("Deluge")

    def on_newversionavailable_event(self, new_version):
        if self.config["show_new_releases"]:
            from deluge.ui.gtkui.new_release_dialog import NewReleaseDialog

            reactor.callLater(5.0, NewReleaseDialog().show, new_version)

    def on_torrentfinished_event(self, torrent_id):
        from deluge.ui.gtkui.notification import Notification

        Notification().notify(torrent_id)
Ejemplo n.º 52
0
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler
            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application
            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':
            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])
            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx
            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)
Ejemplo n.º 53
0
class MainWindow(component.Component):
    def __init__(self):
        if wnck:
            self.screen = wnck.screen_get_default()
        component.Component.__init__(self, "MainWindow", interval=2)
        self.config = ConfigManager("gtkui.conf")
        # Get the glade file for the main window
        self.main_glade = gtk.glade.XML(
                    pkg_resources.resource_filename("deluge.ui.gtkui",
                                                    "glade/main_window.glade"))

        self.window = self.main_glade.get_widget("main_window")

        self.window.set_icon(common.get_deluge_icon())

        self.vpaned = self.main_glade.get_widget("vpaned")
        self.initial_vpaned_position = self.config["window_pane_position"]

        # Load the window state
        self.load_window_state()

        # Keep track of window's minimization state so that we don't update the
        # UI when it is minimized.
        self.is_minimized = False

        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, [('text/uri-list', 0,
            80)], gtk.gdk.ACTION_COPY)

        # Connect events
        self.window.connect("window-state-event", self.on_window_state_event)
        self.window.connect("configure-event", self.on_window_configure_event)
        self.window.connect("delete-event", self.on_window_delete_event)
        self.window.connect("drag-data-received", self.on_drag_data_received_event)
        self.vpaned.connect("notify::position", self.on_vpaned_position_event)
        self.window.connect("expose-event", self.on_expose_event)

        self.config.register_set_function("show_rate_in_title", self._on_set_show_rate_in_title, apply_now=False)

        client.register_event_handler("NewVersionAvailableEvent", self.on_newversionavailable_event)
        client.register_event_handler("TorrentFinishedEvent", self.on_torrentfinished_event)

    def first_show(self):
        if not(self.config["start_in_tray"] and \
               self.config["enable_system_tray"]) and not \
                self.window.get_property("visible"):
            log.debug("Showing window")
            self.show()
            while gtk.events_pending():
                gtk.main_iteration(False)
            self.vpaned.set_position(self.initial_vpaned_position)

    def show(self):
        try:
            component.resume("TorrentView")
            component.resume("StatusBar")
            component.resume("TorrentDetails")
        except:
            pass
        self.window.show()

    def hide(self):
        component.pause("TorrentView")
        component.get("TorrentView").save_state()
        component.pause("StatusBar")
        component.pause("TorrentDetails")
        # Store the x, y positions for when we restore the window
        self.window_x_pos = self.window.get_position()[0]
        self.window_y_pos = self.window.get_position()[1]
        self.window.hide()

    def present(self):
        def restore():
            # Restore the proper x,y coords for the window prior to showing it
            try:
                if self.window_x_pos == -32000 or self.window_y_pos == -32000:
                    self.config["window_x_pos"] = 0
                    self.config["window_y_pos"] = 0
                else:
                    self.config["window_x_pos"] = self.window_x_pos
                    self.config["window_y_pos"] = self.window_y_pos
            except:
                pass
            try:
                component.resume("TorrentView")
                component.resume("StatusBar")
                component.resume("TorrentDetails")
            except:
                pass

            self.window.present()
            self.load_window_state()

        if self.config["lock_tray"] and not self.visible():
            dialog = PasswordDialog(_("Enter your password to show Deluge..."))
            def on_dialog_response(response_id):
                if response_id == gtk.RESPONSE_OK:
                    if self.config["tray_password"] == sha(dialog.get_password()).hexdigest():
                        restore()
            dialog.run().addCallback(on_dialog_response)
        else:
            restore()

    def active(self):
        """Returns True if the window is active, False if not."""
        return self.window.is_active()

    def visible(self):
        """Returns True if window is visible, False if not."""
        return self.window.get_property("visible")

    def get_glade(self):
        """Returns a reference to the main window glade object."""
        return self.main_glade

    def quit(self, shutdown=False):
        """
        Quits the GtkUI

        :param shutdown: whether or not to shutdown the daemon as well
        :type shutdown: boolean
        """
        def quit_gtkui():
            def shutdown_daemon(result):
                return client.daemon.shutdown()

            def disconnect_client(result):
                return client.disconnect()

            def stop_reactor(result):
                try:
                    reactor.stop()
                except ReactorNotRunning:
                    log.debug("Attempted to stop the reactor but it is not running...")

            def log_failure(failure, action):
                log.error("Encountered error attempting to %s: %s" % \
                          (action, failure.getErrorMessage()))

            d = defer.succeed(None)
            if shutdown:
                d.addCallback(shutdown_daemon)
                d.addErrback(log_failure, "shutdown daemon")
            if not client.is_classicmode() and client.connected():
                d.addCallback(disconnect_client)
                d.addErrback(log_failure, "disconnect client")
            d.addBoth(stop_reactor)

        if self.config["lock_tray"] and not self.visible():
            dialog = PasswordDialog(_("Enter your password to Quit Deluge..."))
            def on_dialog_response(response_id):
                if response_id == gtk.RESPONSE_OK:
                    if self.config["tray_password"] == sha(dialog.get_password()).hexdigest():
                        quit_gtkui()
            dialog.run().addCallback(on_dialog_response)
        else:
            quit_gtkui()

    def load_window_state(self):
        x = self.config["window_x_pos"]
        y = self.config["window_y_pos"]
        w = self.config["window_width"]
        h = self.config["window_height"]
        self.window.move(x, y)
        self.window.resize(w, h)
        if self.config["window_maximized"]:
            self.window.maximize()

    def on_window_configure_event(self, widget, event):
        if not self.config["window_maximized"] and self.visible:
            self.config["window_x_pos"] = self.window.get_position()[0]
            self.config["window_y_pos"] = self.window.get_position()[1]
            self.config["window_width"] = event.width
            self.config["window_height"] = event.height

    def on_window_state_event(self, widget, event):
        if event.changed_mask & gtk.gdk.WINDOW_STATE_MAXIMIZED:
            if event.new_window_state & gtk.gdk.WINDOW_STATE_MAXIMIZED:
                log.debug("pos: %s", self.window.get_position())
                self.config["window_maximized"] = True
            elif not event.new_window_state & gtk.gdk.WINDOW_STATE_WITHDRAWN:
                self.config["window_maximized"] = False
        if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
            if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
                log.debug("MainWindow is minimized..")
                component.pause("TorrentView")
                component.pause("StatusBar")
                self.is_minimized = True
            else:
                log.debug("MainWindow is not minimized..")
                try:
                    component.resume("TorrentView")
                    component.resume("StatusBar")
                except:
                    pass
                self.is_minimized = False
        return False

    def on_window_delete_event(self, widget, event):
        if self.config["close_to_tray"] and self.config["enable_system_tray"]:
            self.hide()
        else:
            self.quit()

        return True

    def on_vpaned_position_event(self, obj, param):
        self.config["window_pane_position"] = self.vpaned.get_position()

    def on_drag_data_received_event(self, widget, drag_context, x, y, selection_data, info, timestamp):
        log.debug("Selection(s) dropped on main window %s", selection_data.data)
        if selection_data.get_uris():
            process_args(selection_data.get_uris())
        else:
            process_args(selection_data.data.split())
        drag_context.finish(True, True)

    def on_expose_event(self, widget, event):
        component.get("SystemTray").blink(False)

    def stop(self):
        self.window.set_title("SharkByte")

    def update(self):
        # Update the window title
        def _on_get_session_status(status):
            download_rate = deluge.common.fsize_short(status["payload_download_rate"])
            upload_rate = deluge.common.fsize_short(status["payload_upload_rate"])
            self.window.set_title("%s%s %s%s - Deluge" % (_("D:"), download_rate, _("U:"), upload_rate))
        if self.config["show_rate_in_title"]:
            client.core.get_session_status(["payload_download_rate", "payload_upload_rate"]).addCallback(_on_get_session_status)

    def _on_set_show_rate_in_title(self, key, value):
        if value:
            self.update()
        else:
            self.window.set_title("SharkByte")

    def on_newversionavailable_event(self, new_version):
        if self.config["show_new_releases"]:
            from deluge.ui.gtkui.new_release_dialog import NewReleaseDialog
            reactor.callLater(5.0, NewReleaseDialog().show, new_version)

    def on_torrentfinished_event(self, torrent_id):
        from deluge.ui.gtkui.notification import Notification
        Notification().notify(torrent_id)

    def is_on_active_workspace(self):
        """Determines if MainWindow is on the active workspace.

        Returns:
            bool: True if on active workspace (or wnck module not available), otherwise False.

        """
        if wnck:
            self.screen.force_update()
            win = wnck.window_get(self.window.window.xid)
            if win:
                active_wksp = win.get_screen().get_active_workspace()
                if active_wksp:
                    return win.is_on_workspace(active_wksp)
                else:
                    return False
        return True
Ejemplo n.º 54
0
    def __init__(self):
        component.Component.__init__(self, "TorrentManager", interval=5, depend=["CorePluginManager"])
        log.debug("TorrentManager init..")
        # Set the libtorrent session
        self.session = component.get("Core").session
        # Set the alertmanager
        self.alerts = component.get("AlertManager")
        # Get the core config
        self.config = ConfigManager("core.conf")

        # Make sure the state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), "state")):
            os.makedirs(os.path.join(get_config_dir(), "state"))

        # Create the torrents dict { torrent_id: Torrent }
        self.torrents = {}
        self.queued_torrents = set()

        # This is a list of torrent_id when we shutdown the torrentmanager.
        # We use this list to determine if all active torrents have been paused
        # and that their resume data has been written.
        self.shutdown_torrent_pause_list = []

        # self.num_resume_data used to save resume_data in bulk
        self.num_resume_data = 0

        # Keep track of torrents finished but moving storage
        self.waiting_on_finish_moving = []

        # Keeps track of resume data that needs to be saved to disk
        self.resume_data = {}

        # Workaround to determine if TorrentAddedEvent is from state file
        self.session_started = False

        # Register set functions
        self.config.register_set_function("max_connections_per_torrent",
            self.on_set_max_connections_per_torrent)
        self.config.register_set_function("max_upload_slots_per_torrent",
            self.on_set_max_upload_slots_per_torrent)
        self.config.register_set_function("max_upload_speed_per_torrent",
            self.on_set_max_upload_speed_per_torrent)
        self.config.register_set_function("max_download_speed_per_torrent",
            self.on_set_max_download_speed_per_torrent)

        # Register alert functions
        self.alerts.register_handler("torrent_finished_alert",
            self.on_alert_torrent_finished)
        self.alerts.register_handler("torrent_paused_alert",
            self.on_alert_torrent_paused)
        self.alerts.register_handler("torrent_checked_alert",
            self.on_alert_torrent_checked)
        self.alerts.register_handler("tracker_reply_alert",
            self.on_alert_tracker_reply)
        self.alerts.register_handler("tracker_announce_alert",
            self.on_alert_tracker_announce)
        self.alerts.register_handler("tracker_warning_alert",
            self.on_alert_tracker_warning)
        self.alerts.register_handler("tracker_error_alert",
            self.on_alert_tracker_error)
        self.alerts.register_handler("storage_moved_alert",
            self.on_alert_storage_moved)
        self.alerts.register_handler("storage_moved_failed_alert",
            self.on_alert_storage_moved_failed)
        self.alerts.register_handler("torrent_resumed_alert",
            self.on_alert_torrent_resumed)
        self.alerts.register_handler("state_changed_alert",
            self.on_alert_state_changed)
        self.alerts.register_handler("save_resume_data_alert",
            self.on_alert_save_resume_data)
        self.alerts.register_handler("save_resume_data_failed_alert",
            self.on_alert_save_resume_data_failed)
        self.alerts.register_handler("file_renamed_alert",
            self.on_alert_file_renamed)
        self.alerts.register_handler("metadata_received_alert",
            self.on_alert_metadata_received)
        self.alerts.register_handler("file_error_alert",
            self.on_alert_file_error)
        self.alerts.register_handler("file_completed_alert",
            self.on_alert_file_completed)
Ejemplo n.º 55
0
class TorrentManager(component.Component):
    """
    TorrentManager contains a list of torrents in the current libtorrent
    session.  This object is also responsible for saving the state of the
    session for use on restart.
    """

    def __init__(self):
        component.Component.__init__(self, "TorrentManager", interval=5, depend=["CorePluginManager"])
        log.debug("TorrentManager init..")
        # Set the libtorrent session
        self.session = component.get("Core").session
        # Set the alertmanager
        self.alerts = component.get("AlertManager")
        # Get the core config
        self.config = ConfigManager("core.conf")

        # Make sure the state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), "state")):
            os.makedirs(os.path.join(get_config_dir(), "state"))

        # Create the torrents dict { torrent_id: Torrent }
        self.torrents = {}
        self.queued_torrents = set()

        # This is a list of torrent_id when we shutdown the torrentmanager.
        # We use this list to determine if all active torrents have been paused
        # and that their resume data has been written.
        self.shutdown_torrent_pause_list = []

        # self.num_resume_data used to save resume_data in bulk
        self.num_resume_data = 0

        # Keep track of torrents finished but moving storage
        self.waiting_on_finish_moving = []

        # Keeps track of resume data that needs to be saved to disk
        self.resume_data = {}

        # Workaround to determine if TorrentAddedEvent is from state file
        self.session_started = False

        # Register set functions
        self.config.register_set_function("max_connections_per_torrent",
            self.on_set_max_connections_per_torrent)
        self.config.register_set_function("max_upload_slots_per_torrent",
            self.on_set_max_upload_slots_per_torrent)
        self.config.register_set_function("max_upload_speed_per_torrent",
            self.on_set_max_upload_speed_per_torrent)
        self.config.register_set_function("max_download_speed_per_torrent",
            self.on_set_max_download_speed_per_torrent)

        # Register alert functions
        self.alerts.register_handler("torrent_finished_alert",
            self.on_alert_torrent_finished)
        self.alerts.register_handler("torrent_paused_alert",
            self.on_alert_torrent_paused)
        self.alerts.register_handler("torrent_checked_alert",
            self.on_alert_torrent_checked)
        self.alerts.register_handler("tracker_reply_alert",
            self.on_alert_tracker_reply)
        self.alerts.register_handler("tracker_announce_alert",
            self.on_alert_tracker_announce)
        self.alerts.register_handler("tracker_warning_alert",
            self.on_alert_tracker_warning)
        self.alerts.register_handler("tracker_error_alert",
            self.on_alert_tracker_error)
        self.alerts.register_handler("storage_moved_alert",
            self.on_alert_storage_moved)
        self.alerts.register_handler("storage_moved_failed_alert",
            self.on_alert_storage_moved_failed)
        self.alerts.register_handler("torrent_resumed_alert",
            self.on_alert_torrent_resumed)
        self.alerts.register_handler("state_changed_alert",
            self.on_alert_state_changed)
        self.alerts.register_handler("save_resume_data_alert",
            self.on_alert_save_resume_data)
        self.alerts.register_handler("save_resume_data_failed_alert",
            self.on_alert_save_resume_data_failed)
        self.alerts.register_handler("file_renamed_alert",
            self.on_alert_file_renamed)
        self.alerts.register_handler("metadata_received_alert",
            self.on_alert_metadata_received)
        self.alerts.register_handler("file_error_alert",
            self.on_alert_file_error)
        self.alerts.register_handler("file_completed_alert",
            self.on_alert_file_completed)

    def start(self):
        # Get the pluginmanager reference
        self.plugins = component.get("CorePluginManager")

        # Run the old state upgrader before loading state
        deluge.core.oldstateupgrader.OldStateUpgrader()

        # Try to load the state from file
        self.load_state()

        # Save the state every 5 minutes
        self.save_state_timer = LoopingCall(self.save_state)
        self.save_state_timer.start(200, False)
        self.save_resume_data_timer = LoopingCall(self.save_resume_data)
        self.save_resume_data_timer.start(190)

    def stop(self):
        # Stop timers
        if self.save_state_timer.running:
            self.save_state_timer.stop()

        if self.save_resume_data_timer.running:
            self.save_resume_data_timer.stop()

        # Save state on shutdown
        self.save_state()

        # Make another list just to make sure all paused torrents will be
        # passed to self.save_resume_data(). With
        # self.shutdown_torrent_pause_list it is possible to have a case when
        # torrent_id is removed from it in self.on_alert_torrent_paused()
        # before we call self.save_resume_data() here.
        save_resume_data_list = []
        for key in self.torrents:
            # Stop the status cleanup LoopingCall here
            self.torrents[key].prev_status_cleanup_loop.stop()
            if not self.torrents[key].handle.is_paused():
                # We set auto_managed false to prevent lt from resuming the torrent
                self.torrents[key].handle.auto_managed(False)
                self.torrents[key].handle.pause()
                self.shutdown_torrent_pause_list.append(key)
                save_resume_data_list.append(key)

        self.save_resume_data(save_resume_data_list)

        # We have to wait for all torrents to pause and write their resume data
        wait = True
        while wait:
            if self.shutdown_torrent_pause_list:
                wait = True
            else:
                wait = False
                for torrent in self.torrents.values():
                    if torrent.waiting_on_resume_data:
                        wait = True
                        break

            time.sleep(0.01)
            # Wait for all alerts
            self.alerts.handle_alerts(True)

    def update(self):
        for torrent_id, torrent in self.torrents.items():
            if torrent.options["stop_at_ratio"] and torrent.state not in ("Checking", "Allocating", "Paused", "Queued"):
                # If the global setting is set, but the per-torrent isn't.. Just skip to the next torrent
                # This is so that a user can turn-off the stop at ratio option on a per-torrent basis
                if not torrent.options["stop_at_ratio"]:
                    continue
                if torrent.get_ratio() >= torrent.options["stop_ratio"] and torrent.is_finished:
                    if torrent.options["remove_at_ratio"]:
                        self.remove(torrent_id)
                        break
                    if not torrent.handle.is_paused():
                        torrent.pause()

    def __getitem__(self, torrent_id):
        """Return the Torrent with torrent_id"""
        return self.torrents[torrent_id]

    def get_torrent_list(self):
        """Returns a list of torrent_ids"""
        return self.torrents.keys()

    def get_torrent_info_from_file(self, filepath):
        """Returns a torrent_info for the file specified or None"""
        torrent_info = None
        # Get the torrent data from the torrent file
        try:
            log.debug("Attempting to create torrent_info from %s", filepath)
            _file = open(filepath, "rb")
            torrent_info = lt.torrent_info(lt.bdecode(_file.read()))
            _file.close()
        except (IOError, RuntimeError), e:
            log.warning("Unable to open %s: %s", filepath, e)

        return torrent_info
Ejemplo n.º 56
0
class Core(CorePluginBase):
    def enable(self):
        self.config = ConfigManager('execute.conf', DEFAULT_CONFIG)
        event_manager = component.get('EventManager')
        self.registered_events = {}
        self.preremoved_cache = {}

        # Go through the commands list and register event handlers
        for command in self.config['commands']:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id, *arg):
                    self.execute_commands(torrent_id, event, *arg)
                return event_handler
            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event], event_handler)
            if event == 'removed':
                event_manager.register_event_handler('PreTorrentRemovedEvent', self.on_preremoved)
            self.registered_events[event] = event_handler

        log.debug('Execute core plugin enabled!')

    def on_preremoved(self, torrent_id):
        # Get and store the torrent info before it is removed
        torrent = component.get('TorrentManager').torrents[torrent_id]
        info = torrent.get_status(['name', 'download_location'])
        self.preremoved_cache[torrent_id] = [torrent_id, info['name'], info['download_location']]

    def execute_commands(self, torrent_id, event, *arg):
        if event == 'added' and arg[0]:
            # No futher action as from_state (arg[0]) is True
            return
        elif event == 'removed':
            torrent_id, torrent_name, download_location = self.preremoved_cache.pop(torrent_id)
        else:
            torrent = component.get('TorrentManager').torrents[torrent_id]
            info = torrent.get_status(['name', 'download_location'])
            # Grab the torrent name and download location
            # getProcessOutputAndValue requires args to be str
            torrent_name = info['name']
            download_location = info['download_location']

        log.debug('Running commands for %s', event)

        def log_error(result, command):
            (stdout, stderr, exit_code) = result
            if exit_code:
                log.warn('Command "%s" failed with exit code %d', command, exit_code)
                if stdout:
                    log.warn('stdout: %s', stdout)
                if stderr:
                    log.warn('stderr: %s', stderr)

        # Go through and execute all the commands
        for command in self.config['commands']:
            if command[EXECUTE_EVENT] == event:
                command = os.path.expandvars(command[EXECUTE_COMMAND])
                command = os.path.expanduser(command)

                cmd_args = [torrent_id.encode('utf8'), torrent_name.encode('utf8'),
                            download_location.encode('utf8')]
                if windows_check():
                    # Escape ampersand on windows (see #2784)
                    cmd_args = [cmd_arg.replace('&', '^^^&') for cmd_arg in cmd_args]

                if os.path.isfile(command) and os.access(command, os.X_OK):
                    log.debug('Running %s with args: %s', command, cmd_args)
                    d = getProcessOutputAndValue(command, cmd_args, env=os.environ)
                    d.addCallback(log_error, command)
                else:
                    log.error('Execute script not found or not executable')

    def disable(self):
        self.config.save()
        event_manager = component.get('EventManager')
        for event, handler in self.registered_events.items():
            event_manager.deregister_event_handler(event, handler)
        log.debug('Execute core plugin disabled!')

    # Exported RPC methods #
    @export
    def add_command(self, event, command):
        command_id = hashlib.sha1(str(time.time())).hexdigest()
        self.config['commands'].append((command_id, event, command))
        self.config.save()
        component.get('EventManager').emit(ExecuteCommandAddedEvent(command_id, event, command))

    @export
    def get_commands(self):
        return self.config['commands']

    @export
    def remove_command(self, command_id):
        for command in self.config['commands']:
            if command[EXECUTE_ID] == command_id:
                self.config['commands'].remove(command)
                component.get('EventManager').emit(ExecuteCommandRemovedEvent(command_id))
                break
        self.config.save()

    @export
    def save_command(self, command_id, event, cmd):
        for i, command in enumerate(self.config['commands']):
            if command[EXECUTE_ID] == command_id:
                self.config['commands'][i] = (command_id, event, cmd)
                break
        self.config.save()
Ejemplo n.º 57
0
class SystemTray(component.Component):
    def __init__(self):
        component.Component.__init__(self, "SystemTray", interval=4)
        self.window = component.get("MainWindow")
        self.config = ConfigManager("gtkui.conf")
        # List of widgets that need to be hidden when not connected to a host
        self.hide_widget_list = [
            "menuitem_add_torrent",
            "menuitem_pause_all",
            "menuitem_resume_all",
            "menuitem_download_limit",
            "menuitem_upload_limit",
            "menuitem_quitdaemon",
            "separatormenuitem1",
            "separatormenuitem2",
            "separatormenuitem3",
            "separatormenuitem4"
        ]
        self.config.register_set_function("enable_system_tray", self.on_enable_system_tray_set)
        # bit of a hack to prevent function from doing something on startup
        self.__enabled_set_once = False
        self.config.register_set_function("enable_appindicator", self.on_enable_appindicator_set)

        self.max_download_speed = -1.0
        self.download_rate = 0.0
        self.max_upload_speed = -1.0
        self.upload_rate = 0.0

        self.config_value_changed_dict = {
            "max_download_speed": self._on_max_download_speed,
            "max_upload_speed": self._on_max_upload_speed
        }

    def enable(self):
        """Enables the system tray icon."""
        self.builder = gtk.Builder()
        self.builder.add_from_file(deluge.common.resource_filename(
            "deluge.ui.gtkui", os.path.join("glade", "tray_menu.ui"))
        )

        self.builder.connect_signals({
            "on_menuitem_show_deluge_activate": self.on_menuitem_show_deluge_activate,
            "on_menuitem_add_torrent_activate": self.on_menuitem_add_torrent_activate,
            "on_menuitem_pause_all_activate": self.on_menuitem_pause_all_activate,
            "on_menuitem_resume_all_activate": self.on_menuitem_resume_all_activate,
            "on_menuitem_quit_activate": self.on_menuitem_quit_activate,
            "on_menuitem_quitdaemon_activate": self.on_menuitem_quitdaemon_activate
        })

        self.tray_menu = self.builder.get_object("tray_menu")

        if appindicator and self.config["enable_appindicator"]:
            log.debug("Enabling the Application Indicator..")
            self.indicator = appindicator.Indicator (
                "deluge", "deluge", appindicator.CATEGORY_APPLICATION_STATUS)
            # Pass the menu to the Application Indicator
            self.indicator.set_menu(self.tray_menu)

            # Make sure the status of the Show Window MenuItem is correct
            self._sig_win_hide = self.window.window.connect("hide", self._on_window_hide)
            self._sig_win_show = self.window.window.connect("show", self._on_window_show)
            if self.window.visible():
                self.builder.get_object("menuitem_show_deluge").set_active(True)
            else:
                self.builder.get_object("menuitem_show_deluge").set_active(False)

            # Show the Application Indicator
            self.indicator.set_status(appindicator.STATUS_ACTIVE)

        else:
            log.debug("Enabling the system tray icon..")
            if deluge.common.windows_check() or deluge.common.osx_check():
                self.tray = gtk.status_icon_new_from_pixbuf(common.get_logo(32))
            else:
                try:
                    self.tray = gtk.status_icon_new_from_icon_name("deluge")
                except:
                    log.warning("Update PyGTK to 2.10 or greater for SystemTray..")
                    return

            self.tray.connect("activate", self.on_tray_clicked)
            self.tray.connect("popup-menu", self.on_tray_popup)

            # For some reason these icons do not display in appindicator
            self.builder.get_object("download-limit-image").set_from_file(
                deluge.common.get_pixmap("downloading16.png"))
            self.builder.get_object("upload-limit-image").set_from_file(
                deluge.common.get_pixmap("seeding16.png"))

        client.register_event_handler("ConfigValueChangedEvent", self.config_value_changed)
        if client.connected():
            # We're connected so we need to get some values from the core
            self.__start()
        else:
            # Hide menu widgets because we're not connected to a host.
            for widget in self.hide_widget_list:
                self.builder.get_object(widget).hide()

    def __start(self):
        if self.config["enable_system_tray"]:

            if self.config["classic_mode"]:
                self.hide_widget_list.remove("menuitem_quitdaemon")
                self.hide_widget_list.remove("separatormenuitem4")
                self.builder.get_object("menuitem_quitdaemon").hide()
                self.builder.get_object("separatormenuitem4").hide()

            # These do not work with appindicator currently and can crash Deluge.
            # Related to Launchpad bug #608219
            if appindicator and self.config["enable_appindicator"]:
                self.hide_widget_list.remove("menuitem_download_limit")
                self.hide_widget_list.remove("menuitem_upload_limit")
                self.hide_widget_list.remove("separatormenuitem3")
                self.builder.get_object("menuitem_download_limit").hide()
                self.builder.get_object("menuitem_upload_limit").hide()
                self.builder.get_object("separatormenuitem3").hide()

            # Show widgets in the hide list because we've connected to a host
            for widget in self.hide_widget_list:
                self.builder.get_object(widget).show()

            # Build the bandwidth speed limit menus
            self.build_tray_bwsetsubmenu()

            # Get some config values
            client.core.get_config_value(
                "max_download_speed").addCallback(self._on_max_download_speed)
            client.core.get_config_value(
                "max_upload_speed").addCallback(self._on_max_upload_speed)
            self.send_status_request()

    def start(self):
        self.__start()

    def stop(self):
        if self.config["enable_system_tray"] and not self.config["enable_appindicator"]:
            try:
                # Hide widgets in hide list because we're not connected to a host
                for widget in self.hide_widget_list:
                    self.builder.get_object(widget).hide()
            except Exception, e:
                log.debug("Unable to hide system tray menu widgets: %s", e)

            self.tray.set_tooltip(_("Deluge") + "\n" + _("Not Connected..."))
Ejemplo n.º 58
0
class Core(CorePluginBase):
    def enable(self):
        self.config = ConfigManager("execute.conf", DEFAULT_CONFIG)
        event_manager = component.get("EventManager")
        self.registered_events = {}

        # Go through the commands list and register event handlers
        for command in self.config["commands"]:
            event = command[EXECUTE_EVENT]
            if event in self.registered_events:
                continue

            def create_event_handler(event):
                def event_handler(torrent_id, *arg):
                    self.execute_commands(torrent_id, event, *arg)

                return event_handler

            event_handler = create_event_handler(event)
            event_manager.register_event_handler(EVENT_MAP[event], event_handler)
            self.registered_events[event] = event_handler

        log.debug("Execute core plugin enabled!")

    def execute_commands(self, torrent_id, event, *arg):
        torrent = component.get("TorrentManager").torrents[torrent_id]
        info = torrent.get_status(["name", "save_path", "move_on_completed", "move_on_completed_path"])

        # Grab the torrent name and save path
        torrent_name = info["name"]
        if event == "complete":
            save_path = info["move_on_completed_path"] if info["move_on_completed"] else info["save_path"]
        elif event == "added" and arg[0]:
            # No futher action as from_state (arg[0]) is True
            return
        else:
            save_path = info["save_path"]

        log.debug("[execute] Running commands for %s", event)

        def log_error(result, command):
            (stdout, stderr, exit_code) = result
            if exit_code:
                log.warn("[execute] command '%s' failed with exit code %d", command, exit_code)
                if stdout:
                    log.warn("[execute] stdout: %s", stdout)
                if stderr:
                    log.warn("[execute] stderr: %s", stderr)

        # Go through and execute all the commands
        for command in self.config["commands"]:
            if command[EXECUTE_EVENT] == event:
                command = os.path.expandvars(command[EXECUTE_COMMAND])
                command = os.path.expanduser(command)
                log.debug("[execute] running %s", command)
                d = getProcessOutputAndValue(command, (torrent_id, torrent_name, save_path), env=os.environ)
                d.addCallback(log_error, command)

    def disable(self):
        self.config.save()
        event_manager = component.get("EventManager")
        for event, handler in self.registered_events.iteritems():
            event_manager.deregister_event_handler(event, handler)
        log.debug("Execute core plugin disabled!")

    ### Exported RPC methods ###
    @export
    def add_command(self, event, command):
        command_id = hashlib.sha1(str(time.time())).hexdigest()
        self.config["commands"].append((command_id, event, command))
        self.config.save()
        component.get("EventManager").emit(ExecuteCommandAddedEvent(command_id, event, command))

    @export
    def get_commands(self):
        return self.config["commands"]

    @export
    def remove_command(self, command_id):
        for command in self.config["commands"]:
            if command[EXECUTE_ID] == command_id:
                self.config["commands"].remove(command)
                component.get("EventManager").emit(ExecuteCommandRemovedEvent(command_id))
                break
        self.config.save()

    @export
    def save_command(self, command_id, event, cmd):
        for i, command in enumerate(self.config["commands"]):
            if command[EXECUTE_ID] == command_id:
                self.config["commands"][i] = (command_id, event, cmd)
                break
        self.config.save()